*** empty log message ***
[dana/urxvt.git] / src / command.C
1 /*--------------------------------*-C-*---------------------------------*
2  * File:        command.c
3  *----------------------------------------------------------------------*
4  * $Id: command.C,v 1.13 2003-12-05 04:27:20 pcg Exp $
5  *
6  * All portions of code are copyright by their respective author/s.
7  * Copyright (c) 1992      John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
8  *                              - original version
9  * Copyright (c) 1994      Robert Nation <nation@rocket.sanders.lockheed.com>
10  *                              - extensive modifications
11  * Copyright (c) 1995      Garrett D'Amore <garrett@netcom.com>
12  *                              - vt100 printing
13  * Copyright (c) 1995      Steven Hirsch <hirsch@emba.uvm.edu>
14  *                              - X11 mouse report mode and support for
15  *                                DEC "private mode" save/restore functions.
16  * Copyright (c) 1995      Jakub Jelinek <jj@gnu.ai.mit.edu>
17  *                              - key-related changes to handle Shift+function
18  *                                keys properly.
19  * Copyright (c) 1997      MJ Olesen <olesen@me.queensu.ca>
20  *                              - extensive modifications
21  * Copyright (c) 1997      Raul Garcia Garcia <rgg@tid.es>
22  *                              - modification and cleanups for Solaris 2.x
23  *                                and Linux 1.2.x
24  * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
25  * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
26  *                              - extensive modifications
27  * Copyright (c) 1998      Alfredo K. Kojima <kojima@windowmaker.org>
28  * Copyright (c) 2001      Marius Gedminas
29  *                              - Ctrl/Mod4+Tab works like Meta+Tab (options)
30  * Copyright (c) 2003      Rob McMullen <robm@flipturn.org>
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 /*----------------------------------------------------------------------*/
54
55 /*{{{ Convert the keypress event into a string */
56 /* INTPROTO */
57 void
58 rxvt_lookup_key(pR_ XKeyEvent *ev)
59 {
60     int             ctrl, meta, shft, len;
61     unsigned int    newlen;
62     KeySym          keysym;
63 #ifdef DEBUG_CMD
64     static int      debug_key = 1;      /* accessible by a debugger only */
65 #endif
66 #ifdef USE_XIM
67     int             valid_keysym;
68 #endif
69     unsigned char  *kbuf = R->kbuf;
70
71 /*
72  * use Num_Lock to toggle Keypad on/off.  If Num_Lock is off, allow an
73  * escape sequence to toggle the Keypad.
74  *
75  * Always permit `shift' to override the current setting
76  */
77     shft = (ev->state & ShiftMask);
78     ctrl = (ev->state & ControlMask);
79     meta = (ev->state & R->ModMetaMask);
80     if (R->numlock_state || (ev->state & R->ModNumLockMask)) {
81         R->numlock_state = (ev->state & R->ModNumLockMask);
82         PrivMode((!R->numlock_state), PrivMode_aplKP);
83     }
84 #ifdef USE_XIM
85     if (R->Input_Context != NULL) {
86         Status          status_return;
87
88         kbuf[0] = '\0';
89 #ifdef X_HAVE_UTF8_STRING
90         len = Xutf8LookupString(R->Input_Context, ev, (char *)kbuf,
91                               KBUFSZ, &keysym, &status_return);
92 #else
93         len = XmbLookupString(R->Input_Context, ev, (char *)kbuf,
94                               KBUFSZ, &keysym, &status_return);
95 #endif
96         valid_keysym = ((status_return == XLookupKeySym)
97                         || (status_return == XLookupBoth));
98     } else {
99         len = XLookupString(ev, (char *)kbuf, KBUFSZ, &keysym,
100                             &R->compose);
101         valid_keysym = 1;
102     }
103 #else                           /* USE_XIM */
104     len = XLookupString(ev, (char *)kbuf, KBUFSZ, &keysym,
105                         &R->compose);
106 /*
107  * map unmapped Latin[2-4]/Katakana/Arabic/Cyrillic/Greek entries -> Latin1
108  * good for installations with correct fonts, but without XLOCALE
109  */
110     if (!len) {
111         if ((keysym >= 0x0100) && (keysym < 0x0800)) {
112             kbuf[0] = (keysym & 0xFF);
113             kbuf[1] = '\0';
114             len = 1;
115         } else
116             kbuf[0] = '\0';
117     }
118 #endif                          /* USE_XIM */
119
120 #ifdef USE_XIM
121     if (valid_keysym)
122 #endif
123     {
124 /* for some backwards compatibility */
125 #if defined(HOTKEY_CTRL) || defined(HOTKEY_META)
126 # ifdef HOTKEY_CTRL
127         if (ctrl) {
128 # else
129         if (meta) {
130 # endif
131             if (keysym == R->ks_bigfont) {
132                 rxvt_change_font(aR_ 0, FONT_UP);
133                 return;
134             } else if (keysym == R->ks_smallfont) {
135                 rxvt_change_font(aR_ 0, FONT_DN);
136                 return;
137             }
138         }
139 #endif
140
141         if (R->TermWin.saveLines) {
142 #ifdef UNSHIFTED_SCROLLKEYS
143             if (!ctrl && !meta) {
144 #else
145             if (IS_SCROLL_MOD) {
146 #endif
147                 int             lnsppg;
148
149 #ifdef PAGING_CONTEXT_LINES
150                 lnsppg = R->TermWin.nrow - PAGING_CONTEXT_LINES;
151 #else
152                 lnsppg = R->TermWin.nrow * 4 / 5;
153 #endif
154                 if (keysym == XK_Prior) {
155                     rxvt_scr_page(aR_ UP, lnsppg);
156                     return;
157                 } else if (keysym == XK_Next) {
158                     rxvt_scr_page(aR_ DN, lnsppg);
159                     return;
160                 }
161             }
162 #ifdef SCROLL_ON_UPDOWN_KEYS
163             if (IS_SCROLL_MOD) {
164                 if (keysym == XK_Up) {
165                     rxvt_scr_page(aR_ UP, 1);
166                     return;
167                 } else if (keysym == XK_Down) {
168                     rxvt_scr_page(aR_ DN, 1);
169                     return;
170                 }
171             }
172 #endif
173 #ifdef SCROLL_ON_HOMEEND_KEYS
174             if (IS_SCROLL_MOD) {
175                 if (keysym == XK_Home) {
176                     rxvt_scr_move_to(aR_ 0, 1);
177                     return;
178                 } else if (keysym == XK_End) {
179                     rxvt_scr_move_to(aR_ 1, 0);
180                     return;
181                 }
182             }
183 #endif
184         }
185
186         if (shft) {
187         /* Shift + F1 - F10 generates F11 - F20 */
188             if (keysym >= XK_F1 && keysym <= XK_F10) {
189                 keysym += (XK_F11 - XK_F1);
190                 shft = 0;       /* turn off Shift */
191             } else if (!ctrl && !meta && (R->PrivateModes & PrivMode_ShiftKeys)) {
192                 switch (keysym) {
193                 /* normal XTerm key bindings */
194                 case XK_Insert: /* Shift+Insert = paste mouse selection */
195                     rxvt_selection_request(aR_ ev->time, 0, 0);
196                     return;
197                 /* rxvt extras */
198                 case XK_KP_Add: /* Shift+KP_Add = bigger font */
199                     rxvt_change_font(aR_ 0, FONT_UP);
200                     return;
201                 case XK_KP_Subtract:    /* Shift+KP_Subtract = smaller font */
202                     rxvt_change_font(aR_ 0, FONT_DN);
203                     return;
204                 }
205             }
206         }
207 #ifdef PRINTPIPE
208         if (keysym == XK_Print) {
209             rxvt_scr_printscreen(aR_ ctrl | shft);
210             return;
211         }
212 #endif
213 #ifdef GREEK_SUPPORT
214         if (keysym == R->ks_greekmodeswith) {
215             R->greek_mode = !R->greek_mode;
216             if (R->greek_mode) {
217                 rxvt_xterm_seq(aR_ XTerm_title,
218                                (greek_getmode() == GREEK_ELOT928
219                                 ? "[Greek: iso]" : "[Greek: ibm]"), CHAR_ST);
220                 greek_reset();
221             } else
222                 rxvt_xterm_seq(aR_ XTerm_title, APL_NAME "-" VERSION, CHAR_ST);
223             return;
224         }
225 #endif
226
227         if (keysym >= 0xFF00 && keysym <= 0xFFFF) {
228 #ifdef KEYSYM_RESOURCE
229             if (!(shft | ctrl) && R->Keysym_map[keysym & 0xFF] != NULL) {
230                 unsigned int    l;
231                 const unsigned char *kbuf0;
232                 const unsigned char ch = C0_ESC;
233
234                 kbuf0 = (R->Keysym_map[keysym & 0xFF]);
235                 l = (unsigned int)*kbuf0++;
236
237             /* escape prefix */
238                 if (meta)
239 # ifdef META8_OPTION
240                     if (R->meta_char == C0_ESC)
241 # endif
242                         R->tt_write(&ch, 1);
243                 R->tt_write(kbuf0, l);
244                 return;
245             } else
246 #endif
247             {
248                 newlen = 1;
249                 switch (keysym) {
250 #ifndef NO_BACKSPACE_KEY
251                 case XK_BackSpace:
252                     if (R->PrivateModes & PrivMode_HaveBackSpace) {
253                         kbuf[0] = (!!(R->PrivateModes & PrivMode_BackSpace)
254                                    ^ !!ctrl) ? '\b' : '\177';
255                         kbuf[1] = '\0';
256                     } else
257                         STRCPY(kbuf, R->key_backspace);
258 # ifdef MULTICHAR_SET
259                     if ((R->Options & Opt_mc_hack) && R->screen.cur.col > 0) {
260                         int             col, row;
261
262                         newlen = STRLEN(kbuf);
263                         col = R->screen.cur.col - 1;
264                         row = R->screen.cur.row + R->TermWin.saveLines;
265                         if (IS_MULTI2(R->screen.rend[row][col]))
266                             MEMMOVE(kbuf + newlen, kbuf, newlen + 1);
267                     }
268 # endif
269                     break;
270 #endif
271 #ifndef NO_DELETE_KEY
272                 case XK_Delete:
273                     STRCPY(kbuf, R->key_delete);
274 # ifdef MULTICHAR_SET
275                     if (R->Options & Opt_mc_hack) {
276                         int             col, row;
277  
278                         newlen = STRLEN(kbuf);
279                         col = R->screen.cur.col;
280                         row = R->screen.cur.row + R->TermWin.saveLines;
281                         if (IS_MULTI1(R->screen.rend[row][col]))
282                             MEMMOVE(kbuf + newlen, kbuf, newlen + 1);
283                     }
284 # endif
285                     break;
286 #endif
287                 case XK_Tab:
288                     if (shft)
289                         STRCPY(kbuf, "\033[Z");
290                     else {
291 #ifdef CTRL_TAB_MAKES_META
292                         if (ctrl)
293                             meta = 1;
294 #endif
295 #ifdef MOD4_TAB_MAKES_META
296                         if (ev->state & Mod4Mask)
297                             meta = 1;
298 #endif
299                         newlen = 0;
300                     }
301                     break;
302
303
304 #ifdef XK_KP_Left
305                 case XK_KP_Up:          /* \033Ox or standard */
306                 case XK_KP_Down:        /* \033Or or standard */
307                 case XK_KP_Right:       /* \033Ov or standard */
308                 case XK_KP_Left:        /* \033Ot or standard */
309                     if ((R->PrivateModes & PrivMode_aplKP) ? !shft : shft) {
310                         STRCPY(kbuf, "\033OZ");
311                         kbuf[2] = ("txvr"[keysym - XK_KP_Left]);
312                         break;
313                     } else
314                     /* translate to std. cursor key */
315                         keysym = XK_Left + (keysym - XK_KP_Left);
316                 /* FALLTHROUGH */
317 #endif
318                 case XK_Up:     /* "\033[A" */
319                 case XK_Down:   /* "\033[B" */
320                 case XK_Right:  /* "\033[C" */
321                 case XK_Left:   /* "\033[D" */
322                     STRCPY(kbuf, "\033[Z");
323                     kbuf[2] = ("DACB"[keysym - XK_Left]);
324                 /* do Shift first */
325                     if (shft)
326                         kbuf[2] = ("dacb"[keysym - XK_Left]);
327                     else if (ctrl) {
328                         kbuf[1] = 'O';
329                         kbuf[2] = ("dacb"[keysym - XK_Left]);
330                     } else if (R->PrivateModes & PrivMode_aplCUR)
331                         kbuf[1] = 'O';
332 #ifdef MULTICHAR_SET
333                     //TODO: ??
334                     if (R->Options & Opt_mc_hack) {
335                         int             col, row, m;
336
337                         col = R->screen.cur.col;
338                         row = R->screen.cur.row + R->TermWin.saveLines;
339                         m = 0;
340                         if (keysym == XK_Right
341                             && IS_MULTI1(R->screen.rend[row][col]))
342                             m = 1;
343                         else if (keysym == XK_Left) {
344                             if (col > 0) {
345                                 if (IS_MULTI2(R->screen.rend[row][col - 1]))
346                                     m = 1;
347                             } else if (R->screen.cur.row > 0) {
348                                 col = R->screen.tlen[--row];
349                                 if (col == -1)
350                                     col = R->TermWin.ncol - 1;
351                                 else
352                                     col--;
353                                 if (col > 0
354                                     && IS_MULTI2(R->screen.rend[row][col]))
355                                     m = 1;
356                             }
357                         }
358                         if (m)
359                             MEMMOVE(kbuf + 3, kbuf, 3 + 1);
360                     }
361 #endif
362                     break;
363
364 #ifndef UNSHIFTED_SCROLLKEYS
365 # ifdef XK_KP_Prior
366                 case XK_KP_Prior:
367                 /* allow shift to override */
368                     if ((R->PrivateModes & PrivMode_aplKP) ? !shft : shft) {
369                         STRCPY(kbuf, "\033Oy");
370                         break;
371                     }
372                 /* FALLTHROUGH */
373 # endif
374                 case XK_Prior:
375                     STRCPY(kbuf, "\033[5~");
376                     break;
377 # ifdef XK_KP_Next
378                 case XK_KP_Next:
379                 /* allow shift to override */
380                     if ((R->PrivateModes & PrivMode_aplKP) ? !shft : shft) {
381                         STRCPY(kbuf, "\033Os");
382                         break;
383                     }
384                 /* FALLTHROUGH */
385 # endif
386                 case XK_Next:
387                     STRCPY(kbuf, "\033[6~");
388                     break;
389 #endif
390                 case XK_KP_Enter:
391                 /* allow shift to override */
392                     if ((R->PrivateModes & PrivMode_aplKP) ? !shft : shft) {
393                         STRCPY(kbuf, "\033OM");
394                     } else {
395                         kbuf[0] = '\r';
396                         kbuf[1] = '\0';
397                     }
398                     break;
399
400 #ifdef XK_KP_Begin
401                 case XK_KP_Begin:
402                     STRCPY(kbuf, "\033Ou");
403                     break;
404
405                 case XK_KP_Insert:
406                     STRCPY(kbuf, "\033Op");
407                     break;
408
409                 case XK_KP_Delete:
410                     STRCPY(kbuf, "\033On");
411                     break;
412 #endif
413                 case XK_KP_F1:  /* "\033OP" */
414                 case XK_KP_F2:  /* "\033OQ" */
415                 case XK_KP_F3:  /* "\033OR" */
416                 case XK_KP_F4:  /* "\033OS" */
417                     STRCPY(kbuf, "\033OP");
418                     kbuf[2] += (keysym - XK_KP_F1);
419                     break;
420
421                 case XK_KP_Multiply:    /* "\033Oj" : "*" */
422                 case XK_KP_Add:         /* "\033Ok" : "+" */
423                 case XK_KP_Separator:   /* "\033Ol" : "," */
424                 case XK_KP_Subtract:    /* "\033Om" : "-" */
425                 case XK_KP_Decimal:     /* "\033On" : "." */
426                 case XK_KP_Divide:      /* "\033Oo" : "/" */
427                 case XK_KP_0:           /* "\033Op" : "0" */
428                 case XK_KP_1:           /* "\033Oq" : "1" */
429                 case XK_KP_2:           /* "\033Or" : "2" */
430                 case XK_KP_3:           /* "\033Os" : "3" */
431                 case XK_KP_4:           /* "\033Ot" : "4" */
432                 case XK_KP_5:           /* "\033Ou" : "5" */
433                 case XK_KP_6:           /* "\033Ov" : "6" */
434                 case XK_KP_7:           /* "\033Ow" : "7" */
435                 case XK_KP_8:           /* "\033Ox" : "8" */
436                 case XK_KP_9:           /* "\033Oy" : "9" */
437                 /* allow shift to override */
438                     if ((R->PrivateModes & PrivMode_aplKP) ? !shft : shft) {
439                         STRCPY(kbuf, "\033Oj");
440                         kbuf[2] += (keysym - XK_KP_Multiply);
441                     } else {
442                         kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
443                         kbuf[1] = '\0';
444                     }
445                     break;
446
447                 case XK_Find:
448                     STRCPY(kbuf, "\033[1~");
449                     break;
450                 case XK_Insert:
451                     STRCPY(kbuf, "\033[2~");
452                     break;
453 #ifdef DXK_Remove               /* support for DEC remove like key */
454                 case DXK_Remove:
455                 /* FALLTHROUGH */
456 #endif
457                 case XK_Execute:
458                     STRCPY(kbuf, "\033[3~");
459                     break;
460                 case XK_Select:
461                     STRCPY(kbuf, "\033[4~");
462                     break;
463 #ifdef XK_KP_End
464                 case XK_KP_End:
465                 /* allow shift to override */
466                     if ((R->PrivateModes & PrivMode_aplKP) ? !shft : shft) {
467                         STRCPY(kbuf, "\033Oq");
468                         break;
469                     }
470                 /* FALLTHROUGH */
471 #endif
472                 case XK_End:
473                     STRCPY(kbuf, KS_END);
474                     break;
475 #ifdef XK_KP_Home
476                 case XK_KP_Home:
477                 /* allow shift to override */
478                     if ((R->PrivateModes & PrivMode_aplKP) ? !shft : shft) {
479                         STRCPY(kbuf, "\033Ow");
480                         break;
481                     }
482                 /* FALLTHROUGH */
483 #endif
484                 case XK_Home:
485                     STRCPY(kbuf, KS_HOME);
486                     break;
487
488 #define FKEY(n, fkey)                                                   \
489     sprintf((char *)kbuf,"\033[%2d~", (int)((n) + (keysym - fkey)))
490
491                 case XK_F1:     /* "\033[11~" */
492                 case XK_F2:     /* "\033[12~" */
493                 case XK_F3:     /* "\033[13~" */
494                 case XK_F4:     /* "\033[14~" */
495                 case XK_F5:     /* "\033[15~" */
496                     FKEY(11, XK_F1);
497                     break;
498                 case XK_F6:     /* "\033[17~" */
499                 case XK_F7:     /* "\033[18~" */
500                 case XK_F8:     /* "\033[19~" */
501                 case XK_F9:     /* "\033[20~" */
502                 case XK_F10:    /* "\033[21~" */
503                     FKEY(17, XK_F6);
504                     break;
505                 case XK_F11:    /* "\033[23~" */
506                 case XK_F12:    /* "\033[24~" */
507                 case XK_F13:    /* "\033[25~" */
508                 case XK_F14:    /* "\033[26~" */
509                     FKEY(23, XK_F11);
510                     break;
511                 case XK_F15:    /* "\033[28~" */
512                 case XK_F16:    /* "\033[29~" */
513                     FKEY(28, XK_F15);
514                     break;
515                 case XK_Help:   /* "\033[28~" */
516                     FKEY(28, XK_Help);
517                     break;
518                 case XK_Menu:   /* "\033[29~" */
519                     FKEY(29, XK_Menu);
520                     break;
521                 case XK_F17:    /* "\033[31~" */
522                 case XK_F18:    /* "\033[32~" */
523                 case XK_F19:    /* "\033[33~" */
524                 case XK_F20:    /* "\033[34~" */
525                 case XK_F21:    /* "\033[35~" */
526                 case XK_F22:    /* "\033[36~" */
527                 case XK_F23:    /* "\033[37~" */
528                 case XK_F24:    /* "\033[38~" */
529                 case XK_F25:    /* "\033[39~" */
530                 case XK_F26:    /* "\033[40~" */
531                 case XK_F27:    /* "\033[41~" */
532                 case XK_F28:    /* "\033[42~" */
533                 case XK_F29:    /* "\033[43~" */
534                 case XK_F30:    /* "\033[44~" */
535                 case XK_F31:    /* "\033[45~" */
536                 case XK_F32:    /* "\033[46~" */
537                 case XK_F33:    /* "\033[47~" */
538                 case XK_F34:    /* "\033[48~" */
539                 case XK_F35:    /* "\033[49~" */
540                     FKEY(31, XK_F17);
541                     break;
542 #undef FKEY
543                 default:
544                     newlen = 0;
545                     break;
546                 }
547                 if (newlen)
548                     len = STRLEN(kbuf);
549             }
550         /*
551          * Pass meta for all function keys, if 'meta' option set
552          */
553 #ifdef META8_OPTION
554             if (meta && (R->meta_char == 0x80) && len > 0)
555                 kbuf[len - 1] |= 0x80;
556 #endif
557         } else if (ctrl && keysym == XK_minus) {
558             len = 1;
559             kbuf[0] = '\037';   /* Ctrl-Minus generates ^_ (31) */
560         } else {
561 #ifdef META8_OPTION
562         /* set 8-bit on */
563             if (meta && (R->meta_char == 0x80)) {
564                 unsigned char  *ch;
565
566                 for (ch = kbuf; ch < kbuf + len; ch++)
567                     *ch |= 0x80;
568                 meta = 0;
569             }
570 #endif
571 #ifdef GREEK_SUPPORT
572             if (R->greek_mode)
573                 len = greek_xlat(kbuf, len);
574 #endif
575         /* nil */ ;
576         }
577     }
578
579     if (len <= 0)
580         return;                 /* not mapped */
581
582     if (R->Options & Opt_scrollTtyKeypress)
583         if (R->TermWin.view_start) {
584             R->TermWin.view_start = 0;
585             R->want_refresh = 1;
586         }
587
588 /*
589  * these modifications only affect the static keybuffer
590  * pass Shift/Control indicators for function keys ending with `~'
591  *
592  * eg,
593  *   Prior = "ESC[5~"
594  *   Shift+Prior = "ESC[5$"
595  *   Ctrl+Prior = "ESC[5^"
596  *   Ctrl+Shift+Prior = "ESC[5@"
597  * Meta adds an Escape prefix (with META8_OPTION, if meta == <escape>).
598  */
599     if (kbuf[0] == C0_ESC && kbuf[1] == '[' && kbuf[len - 1] == '~')
600         kbuf[len - 1] = (shft ? (ctrl ? '@' : '$') : (ctrl ? '^' : '~'));
601
602 /* escape prefix */
603     if (meta
604 #ifdef META8_OPTION
605         && (R->meta_char == C0_ESC)
606 #endif
607         ) {
608         const unsigned char ch = C0_ESC;
609
610         R->tt_write(&ch, 1);
611     }
612 #ifdef DEBUG_CMD
613     if (debug_key) {            /* Display keyboard buffer contents */
614         char           *p;
615         int             i;
616
617         fprintf(stderr, "key 0x%04X [%d]: `", (unsigned int)keysym, len);
618         for (i = 0, p = kbuf; i < len; i++, p++)
619             fprintf(stderr, (*p >= ' ' && *p < '\177' ? "%c" : "\\%03o"), *p);
620         fprintf(stderr, "'\n");
621     }
622 #endif                          /* DEBUG_CMD */
623     R->tt_write(kbuf, (unsigned int)len);
624 }
625 /*}}} */
626
627 #if (MENUBAR_MAX)
628 /*{{{ rxvt_cmd_write(), rxvt_cmd_getc() */
629 /* attempt to `write' count to the input buffer */
630 /* EXTPROTO */
631 unsigned int
632 rxvt_cmd_write(pR_ const unsigned char *str, unsigned int count)
633 {
634     unsigned int    n, s;
635     unsigned char  *cmdbuf_base = R->cmdbuf_base,
636                    *cmdbuf_endp = R->cmdbuf_endp,
637                    *cmdbuf_ptr  = R->cmdbuf_ptr;
638
639     n = cmdbuf_ptr - cmdbuf_base;
640     s = cmdbuf_base + BUFSIZ - 1 - cmdbuf_endp;
641     if (n > 0 && s < count) {
642         MEMMOVE(cmdbuf_base, cmdbuf_ptr,
643                 (unsigned int)(cmdbuf_endp - cmdbuf_ptr));
644         cmdbuf_ptr = cmdbuf_base;
645         cmdbuf_endp -= n;
646         s += n;
647     }
648     if (count > s) {
649         rxvt_print_error("data loss: cmd_write too large");
650         count = s;
651     }
652     for (; count--;)
653         *cmdbuf_endp++ = *str++;
654     R->cmdbuf_ptr = cmdbuf_ptr;
655     R->cmdbuf_endp = cmdbuf_endp;
656     return 0;
657 }
658 #endif                          /* MENUBAR_MAX */
659
660 void
661 rxvt_term::flush ()
662 {
663 #ifdef TRANSPARENT
664   if (want_full_refresh)
665     {
666       want_full_refresh = 0;
667       rxvt_scr_clear (this);
668       rxvt_scr_touch (this, False);
669       want_refresh = 1;
670     }
671 #endif
672
673   if (want_refresh)
674     {
675       rxvt_scr_refresh (this, refresh_type);
676       rxvt_scrollbar_show (this, 1);
677 #ifdef USE_XIM
678       rxvt_IMSendSpot (this);
679 #endif
680     }
681
682   XFlush (Xdisplay);
683 #if 0
684   if (XPending (Xdisplay)) process_x_events ();
685   if (XPending (Xdisplay)) process_x_events ();
686 #endif
687 }
688
689 void
690 rxvt_term::check_cb (check_watcher &w)
691 {
692   SET_R (this);
693
694   flush ();
695 }
696
697 void
698 rxvt_term::process_x_events ()
699 {
700   do
701     {
702       XEvent          xev;
703
704       XNextEvent (Xdisplay, &xev);
705
706 #if defined(CURSOR_BLINK)
707       if ((Options & Opt_cursorBlink)
708           && xev.type == KeyPress)
709         {
710           if (hidden_cursor)
711             {
712               hidden_cursor = 0;
713               want_refresh = 1;
714             }
715
716           blink_ev.start (NOW + BLINK_INTERVAL);
717         }
718 #endif
719
720 #if defined(POINTER_BLANK)
721       if ((Options & Opt_pointerBlank)
722           && (pointerBlankDelay > 0))
723         {
724           if (xev.type == MotionNotify
725               || xev.type == ButtonPress
726               || xev.type == ButtonRelease)
727             if (hidden_pointer)
728               pointer_unblank ();
729
730           if (xev.type == KeyPress && hidden_pointer == 0)
731             pointer_blank ();
732         }
733 #endif
734
735 #ifdef USE_XIM
736       if (!XFilterEvent (&xev, xev.xany.window))
737 #endif
738         rxvt_process_x_event (this, &xev);
739     }
740   while (XPending (Xdisplay));
741 }
742
743 void
744 rxvt_term::blink_cb (time_watcher &w)
745 {
746   SET_R (this);
747
748   w.at += BLINK_INTERVAL;
749   hidden_cursor = !hidden_cursor;
750   want_refresh = 1;
751 }
752
753 void
754 rxvt_term::x_cb (io_watcher &w, short revents)
755 {
756   SET_R (this);
757
758   process_x_events ();
759 }
760
761 bool
762 rxvt_term::pty_fill ()
763 {
764   ssize_t n = cmdbuf_endp - cmdbuf_ptr;
765
766   memmove (cmdbuf_base, cmdbuf_ptr, n);
767   cmdbuf_ptr = cmdbuf_base;
768   cmdbuf_endp = cmdbuf_ptr + n;
769  
770   n = read (cmd_fd, cmdbuf_endp, BUFSIZ - n);
771
772   if (n > 0)
773     {
774       cmdbuf_endp += n;
775       return true;
776     }
777   else if (n < 0 && errno != EAGAIN)
778     destroy ();
779
780   return false;
781 }
782
783 void
784 rxvt_term::pty_cb (io_watcher &w, short revents)
785 {
786   SET_R (this);
787
788   if (revents & EVENT_WRITE)
789     tt_write (0, 0);
790   else if (revents & EVENT_READ)
791     {
792       bool flag = true;
793
794       // loop, but don't allow a single term to monopolize us
795       // the number of loops is fully arbitrary, and thus wrong
796       while (flag && pty_fill ())
797         {
798           if (!seen_input)
799             {
800               seen_input = 1;
801               /* once we know the shell is running, send the screen size.  Again! */
802               tt_winch ();
803             }
804
805           uint32_t ch = NOCHAR;
806
807           for (;;)
808             {
809               if (ch == NOCHAR)
810                 ch = next_char ();
811
812               if (ch == NOCHAR) // TODO: improve
813                 break;
814
815               if (ch >= ' ' || ch == '\t' || ch == '\n' || ch == '\r')
816                 {
817                   /* Read a text string from the input buffer */
818                   uint32_t buf[BUFSIZ];
819                   bool refreshnow = false;
820                   int nlines = 0;
821                   uint32_t *str = buf;
822
823                   *str++ = ch;
824
825                   for (;;)
826                     {
827                       ch = next_char ();
828
829                       if (ch == NOCHAR || (ch < ' ' && ch != '\t' && ch != '\n' && ch != '\r'))
830                         break;
831                       else
832                         {
833                           *str++ = ch;
834
835                           if (ch == '\n')
836                             {
837                               nlines++;
838                               refresh_count++;
839
840                               if (!(Options & Opt_jumpScroll)
841                                   || (refresh_count >= (refresh_limit * (TermWin.nrow - 1))))
842                                 {
843                                   refreshnow = true;
844                                   flag = false;
845                                   ch = NOCHAR;
846                                   break;
847                                 }
848                             }
849
850                           if (str >= buf + BUFSIZ)
851                             {
852                               ch = NOCHAR;
853                               break;
854                             }
855                         }
856                     }
857
858                   rxvt_scr_add_lines (this, buf, nlines, str - buf);
859
860                   /*
861                    * If there have been a lot of new lines, then update the screen
862                    * What the heck I'll cheat and only refresh less than every page-full.
863                    * the number of pages between refreshes is refresh_limit, which
864                    * is incremented here because we must be doing flat-out scrolling.
865                    *
866                    * refreshing should be correct for small scrolls, because of the
867                    * time-out
868                    */
869                   if (refreshnow)
870                     {
871                       if ((Options & Opt_jumpScroll) && refresh_limit < REFRESH_PERIOD)
872                         refresh_limit++;
873
874                       rxvt_scr_refresh (this, refresh_type);
875                     }
876
877                 }
878               else
879                 {
880                   switch (ch)
881                     {
882                       default:
883                         rxvt_process_nonprinting (this, ch);
884                         break;
885                       case C0_ESC:      /* escape char */
886                         rxvt_process_escape_seq (this);
887                         break;
888                       /*case 0x9b: */   /* CSI */
889                       /*  rxvt_process_csi_seq (this); */
890                     }
891
892                   ch = NOCHAR;
893                 }
894             }
895         }
896     }
897 }
898
899 // read the next character, currently handles UTF-8
900 // will probably handle all sorts of other stuff in the future
901 uint32_t
902 rxvt_term::next_char ()
903 {
904   struct mbstate &s = mbstate;
905
906   while (cmdbuf_ptr < cmdbuf_endp)
907     {
908       uint8_t ch = *cmdbuf_ptr;
909
910       if (s.cnt)
911         {
912           if ((ch & 0xc0) == 0x80)
913             {
914               cmdbuf_ptr++;
915
916               /* continuation */
917               s.reg = (s.reg << 6) | (ch & 0x7f);
918
919               if (--s.cnt == 0 && s.reg >= 128) /* if !inrange then corruption or Racking */
920                 return s.reg;
921
922               continue;
923             }
924           else
925             {
926               s.cnt = 0;
927               return s.orig; /* the _occasional_ non-utf-8 character may slip through... */
928             }
929         }
930       
931       if ((ch & 0xc0) == 0xc0)
932         {
933           cmdbuf_ptr++;
934
935           /* first byte */
936           s.orig = ch; /* for broken encodings */
937           s.reg = ch;
938           if ((ch & 0xe0) == 0xc0) { s.reg &= 0x1f; s.cnt = 1; }
939           if ((ch & 0xf0) == 0xe0) { s.reg &= 0x0f; s.cnt = 2; }
940           if ((ch & 0xf8) == 0xf0) { s.reg &= 0x07; s.cnt = 3; }
941           if ((ch & 0xfc) == 0xf8) { s.reg &= 0x03; s.cnt = 4; }
942           if ((ch & 0xfe) == 0xfc) { s.reg &= 0x01; s.cnt = 5; }
943         }
944       else
945         {
946           cmdbuf_ptr++; /* _occasional_ non-utf8 may slip through... */
947           return ch;
948         }
949     }
950
951   return NOCHAR;
952 }
953
954 /* rxvt_cmd_getc() - Return next input character */
955 /*
956  * Return the next input character after first passing any keyboard input
957  * to the command.
958  */
959 /* INTPROTO */
960 uint32_t
961 rxvt_cmd_getc(pR)
962 {
963   for (;;)
964     {
965       uint32_t c = R->next_char ();
966       if (c != NOCHAR)
967         return c;
968
969       // incomplete sequences should occur rarely, still, a better solution
970       // would be preferred. either setjmp/longjmp or better design.
971       fcntl (R->cmd_fd, F_SETFL, 0);
972       R->pty_fill ();
973       fcntl (R->cmd_fd, F_SETFL, O_NONBLOCK);
974     }
975
976 #if 0
977 #define TIMEOUT_USEC    5000
978     fd_set          readfds;
979     int             quick_timeout, select_res;
980     int             want_motion_time, want_keypress_time;
981     struct timeval  value;
982 #if defined(POINTER_BLANK) || defined(CURSOR_BLINK)
983     struct timeval  tp;
984 #endif
985
986     for (;;) {
987     /* loop until we can return something */
988
989         if (R->v_bufstr < R->v_bufptr)  /* output any pending chars */
990             R->tt_write(NULL, 0);
991
992 #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
993         if (R->mouse_slip_wheel_speed) {
994             quick_timeout = 1;
995             if (!R->mouse_slip_wheel_delay--
996                 && rxvt_scr_page(aR_ R->mouse_slip_wheel_speed > 0 ? UP : DN,
997                                  abs(R->mouse_slip_wheel_speed))) {
998                 R->mouse_slip_wheel_delay = SCROLLBAR_CONTINUOUS_DELAY;
999                 R->refresh_type |= SMOOTH_REFRESH;
1000                 R->want_refresh = 1;
1001             }
1002         }
1003 #endif /* MOUSE_WHEEL && MOUSE_SLIP_WHEELING */
1004 #ifdef SELECTION_SCROLLING
1005         if (R->pending_scroll_selection) {
1006             quick_timeout = 1;
1007             if (!R->scroll_selection_delay--
1008                 && rxvt_scr_page(aR_ R->scroll_selection_dir,
1009                     R->scroll_selection_lines)) {
1010                 rxvt_selection_extend(aR_ R->selection_save_x,
1011                     R->selection_save_y, R->selection_save_state);
1012                 R->scroll_selection_delay = SCROLLBAR_CONTINUOUS_DELAY;
1013                 R->refresh_type |= SMOOTH_REFRESH;
1014                 R->want_refresh = 1;
1015             }
1016         }
1017 #endif
1018 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1019         if (scrollbar_isUp() || scrollbar_isDn()) {
1020             quick_timeout = 1;
1021             if (!R->scroll_arrow_delay--
1022                 && rxvt_scr_page(aR_ scrollbar_isUp() ? UP : DN, 1)) {
1023                 R->scroll_arrow_delay = SCROLLBAR_CONTINUOUS_DELAY;
1024                 R->refresh_type |= SMOOTH_REFRESH;
1025                 R->want_refresh = 1;
1026             }
1027         }
1028 #endif                          /* NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING */
1029
1030 #ifdef TRANSPARENT
1031             quick_timeout |= R->want_full_refresh;
1032 #endif
1033 #endif
1034 }
1035
1036 void
1037 rxvt_term::pointer_unblank ()
1038 {
1039   XDefineCursor (Xdisplay, TermWin.vt, TermWin_cursor);
1040   rxvt_recolour_cursor (this);
1041
1042 #ifdef POINTER_BLANK
1043   hidden_pointer = 0;
1044
1045   if (Options & Opt_pointerBlank)
1046     pointer_ev.start (NOW + pointerBlankDelay);
1047 #endif
1048 }
1049
1050 #ifdef POINTER_BLANK
1051 void
1052 rxvt_term::pointer_blank ()
1053 {
1054   pointer_ev.stop ();
1055
1056   if (!(Options & Opt_pointerBlank))
1057     return;
1058
1059   XDefineCursor (Xdisplay, TermWin.vt, blank_cursor);
1060   XFlush (Xdisplay);
1061
1062   hidden_pointer = 1;
1063 }
1064
1065 void
1066 rxvt_term::pointer_cb (time_watcher &w)
1067 {
1068   SET_R (this);
1069
1070   pointer_blank ();
1071 }
1072 #endif
1073
1074 /* INTPROTO */
1075 void
1076 rxvt_mouse_report(pR_ const XButtonEvent *ev)
1077 {
1078     int             button_number, key_state = 0;
1079     int             x, y;
1080
1081     x = ev->x;
1082     y = ev->y;
1083     rxvt_pixel_position(aR_ &x, &y);
1084
1085     if (R->MEvent.button == AnyButton) {
1086         button_number = 3;
1087     } else {
1088         button_number = R->MEvent.button - Button1;
1089         /* add 0x3D for wheel events, like xterm does */
1090         if (button_number >= 3)
1091             button_number += (64 - 3);
1092     }
1093
1094     if (R->PrivateModes & PrivMode_MouseX10) {
1095     /*
1096      * do not report ButtonRelease
1097      * no state info allowed
1098      */
1099         key_state = 0;
1100         if (button_number == 3)
1101             return;
1102     } else {
1103     /* XTerm mouse reporting needs these values:
1104      *   4 = Shift
1105      *   8 = Meta
1106      *  16 = Control
1107      * plus will add in our own Double-Click reporting
1108      *  32 = Double Click
1109      */
1110         key_state = ((R->MEvent.state & ShiftMask) ? 4 : 0)
1111                      + ((R->MEvent.state & R->ModMetaMask) ? 8 : 0)
1112                      + ((R->MEvent.state & ControlMask) ? 16 : 0);
1113 #ifdef MOUSE_REPORT_DOUBLECLICK
1114         key_state += ((R->MEvent.clicks > 1) ? 32 : 0);
1115 #endif
1116     }
1117
1118 #ifdef DEBUG_MOUSEREPORT
1119     fprintf(stderr, "Mouse [");
1120     if (key_state & 16)
1121         fputc('C', stderr);
1122     if (key_state & 4)
1123         fputc('S', stderr);
1124     if (key_state & 8)
1125         fputc('A', stderr);
1126     if (key_state & 32)
1127         fputc('2', stderr);
1128     fprintf(stderr, "]: <%d>, %d/%d\n",
1129             button_number,
1130             x + 1,
1131             y + 1);
1132 #else
1133     R->tt_printf("\033[M%c%c%c",
1134               (32 + button_number + key_state),
1135               (32 + x + 1),
1136               (32 + y + 1));
1137 #endif
1138 }
1139
1140 #ifdef USING_W11LIB
1141 /* EXTPROTO */
1142 void
1143 rxvt_W11_process_x_event(XEvent *ev)
1144 {
1145     rxvt_t         *r = rxvt_get_r();
1146
1147     rxvt_process_x_event(aR_ ev);
1148 }
1149 #endif
1150
1151 /*{{{ process an X event */
1152 /* INTPROTO */
1153 void
1154 rxvt_process_x_event(pR_ XEvent *ev)
1155 {
1156     int             i, want_timeout;
1157     Window          unused_root, unused_child;
1158     int             unused_root_x, unused_root_y;
1159     unsigned int    unused_mask;
1160     struct timeval  tp;
1161
1162 #ifdef DEBUG_X
1163     const char *const eventnames[] =
1164     {                           /* mason - this matches my system */
1165         "",
1166         "",
1167         "KeyPress",
1168         "KeyRelease",
1169         "ButtonPress",
1170         "ButtonRelease",
1171         "MotionNotify",
1172         "EnterNotify",
1173         "LeaveNotify",
1174         "FocusIn",
1175         "FocusOut",
1176         "KeymapNotify",
1177         "Expose",
1178         "GraphicsExpose",
1179         "NoExpose",
1180         "VisibilityNotify",
1181         "CreateNotify",
1182         "DestroyNotify",
1183         "UnmapNotify",
1184         "MapNotify",
1185         "MapRequest",
1186         "ReparentNotify",
1187         "ConfigureNotify",
1188         "ConfigureRequest",
1189         "GravityNotify",
1190         "ResizeRequest",
1191         "CirculateNotify",
1192         "CirculateRequest",
1193         "PropertyNotify",
1194         "SelectionClear",
1195         "SelectionRequest",
1196         "SelectionNotify",
1197         "ColormapNotify",
1198         "ClientMessage",
1199         "MappingNotify"
1200     };
1201     struct tm      *ltt;
1202 #endif
1203
1204     /*
1205      * check if we need to get the time for any timeouts
1206      */
1207
1208     for (i = NUM_TIMEOUTS; i--; )
1209         if (R->timeout[i].tv_sec) {
1210             want_timeout = 1;
1211             break;
1212         }
1213
1214 #ifndef DEBUG_X
1215     if (want_timeout)
1216 #endif
1217         (void)gettimeofday(&tp, NULL);
1218
1219 #ifdef DEBUG_X
1220     ltt = localtime(&(tp.tv_sec));
1221     D_X((stderr, "Event: %-16s %-7s %08lx (%4d-%02d-%02d %02d:%02d:%02d.%.6ld) %s %lu", eventnames[ev->type], (ev->xany.window == R->TermWin.parent[0] ? "parent" : (ev->xany.window == R->TermWin.vt ? "vt" : (ev->xany.window == R->scrollBar.win ? "scroll" : (ev->xany.window == R->menuBar.win ? "menubar" : "UNKNOWN")))), (ev->xany.window == R->TermWin.parent[0] ? R->TermWin.parent[0] : (ev->xany.window == R->TermWin.vt ? R->TermWin.vt : (ev->xany.window == R->scrollBar.win ? R->scrollBar.win : (ev->xany.window == R->menuBar.win ? R->menuBar.win : 0)))), ltt->tm_year + 1900, ltt->tm_mon + 1, ltt->tm_mday, ltt->tm_hour, ltt->tm_min, ltt->tm_sec, tp.tv_usec, ev->xany.send_event ? "S" : " ", ev->xany.serial));
1222 #endif
1223
1224     /* X event timeouts */
1225     if (want_timeout)
1226         for (i = NUM_TIMEOUTS; i--; ) {
1227             if (R->timeout[i].tv_sec == 0)
1228                 continue;
1229             if ((tp.tv_sec < R->timeout[i].tv_sec)
1230                 || (tp.tv_sec == R->timeout[i].tv_sec
1231                     && tp.tv_usec < R->timeout[i].tv_usec))
1232                 continue;
1233             R->timeout[i].tv_sec = 0;
1234             switch(i) {
1235             case TIMEOUT_INCR:
1236                 rxvt_print_error("data loss: timeout on INCR selection paste");
1237                 R->selection_wait = Sel_none;
1238                 break;
1239             default:
1240                 break;
1241             }
1242         }
1243
1244     switch (ev->type) {
1245     case KeyPress:
1246         rxvt_lookup_key(aR_ (XKeyEvent *)ev);
1247         break;
1248
1249 #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
1250     case KeyRelease:
1251         {
1252             if (!(ev->xkey.state & ControlMask))
1253                 R->mouse_slip_wheel_speed = 0;
1254             else {
1255                 KeySym          ks;
1256                 
1257                 ks = XKeycodeToKeysym(R->Xdisplay, ev->xkey.keycode, 0);
1258                 if (ks == XK_Control_L || ks == XK_Control_R)
1259                     R->mouse_slip_wheel_speed = 0;
1260             }
1261             break;
1262         }
1263 #endif
1264
1265     case ButtonPress:
1266         rxvt_button_press(aR_ (XButtonEvent *)ev);
1267         break;
1268
1269     case ButtonRelease:
1270         rxvt_button_release(aR_ (XButtonEvent *)ev);
1271         break;
1272
1273     case ClientMessage:
1274         if (ev->xclient.format == 32
1275             && (Atom)ev->xclient.data.l[0] == R->xa[XA_WMDELETEWINDOW])
1276           R->destroy ();
1277 #ifdef OFFIX_DND
1278     /* OffiX Dnd (drag 'n' drop) protocol */
1279         else if (ev->xclient.message_type == R->xa[XA_DNDPROTOCOL]
1280             && (ev->xclient.data.l[0] == DndFile
1281                 || ev->xclient.data.l[0] == DndDir
1282                 || ev->xclient.data.l[0] == DndLink)) {
1283         /* Get Dnd data */
1284             Atom            ActualType;
1285             int             ActualFormat;
1286             unsigned char  *data;
1287             unsigned long   Size, RemainingBytes;
1288
1289             XGetWindowProperty(R->Xdisplay, Xroot,
1290                                R->xa[XA_DNDSELECTION],
1291                                0L, 1000000L,
1292                                False, AnyPropertyType,
1293                                &ActualType, &ActualFormat,
1294                                &Size, &RemainingBytes,
1295                                &data);
1296             XChangeProperty(R->Xdisplay, Xroot,
1297                             XA_CUT_BUFFER0, XA_STRING,
1298                             8, PropModeReplace,
1299                             data, STRLEN(data));
1300             rxvt_selection_paste(aR_ Xroot, XA_CUT_BUFFER0, True);
1301             XSetInputFocus(R->Xdisplay, Xroot, RevertToNone, CurrentTime);
1302         }
1303 #endif                          /* OFFIX_DND */
1304         break;
1305
1306     case MappingNotify:
1307         XRefreshKeyboardMapping(&(ev->xmapping));
1308         break;
1309
1310     /*
1311      * XXX: this is not the _current_ arrangement
1312      * Here's my conclusion:
1313      * If the window is completely unobscured, use bitblt's
1314      * to scroll. Even then, they're only used when doing partial
1315      * screen scrolling. When partially obscured, we have to fill
1316      * in the GraphicsExpose parts, which means that after each refresh,
1317      * we need to wait for the graphics expose or Noexpose events,
1318      * which ought to make things real slow!
1319      */
1320     case VisibilityNotify:
1321         switch (ev->xvisibility.state)
1322           {
1323             case VisibilityUnobscured:
1324               R->refresh_type = FAST_REFRESH;
1325               break;
1326             case VisibilityPartiallyObscured:
1327               R->refresh_type = SLOW_REFRESH;
1328               break;
1329             default:
1330               R->refresh_type = NO_REFRESH;
1331               break;
1332           }
1333         break;
1334
1335     case FocusIn:
1336         if (!R->TermWin.focus) {
1337             R->TermWin.focus = 1;
1338             R->want_refresh = 1;
1339 #ifdef USE_XIM
1340             if (R->Input_Context != NULL)
1341                 XSetICFocus(R->Input_Context);
1342 #endif
1343 #ifdef CURSOR_BLINK
1344             if (R->Options & Opt_cursorBlink)
1345               R->blink_ev.start (NOW + BLINK_INTERVAL);
1346 #endif
1347         }
1348         break;
1349
1350     case FocusOut:
1351         if (R->TermWin.focus) {
1352             R->TermWin.focus = 0;
1353             R->want_refresh = 1;
1354 #ifdef USE_XIM
1355             if (R->Input_Context != NULL)
1356                 XUnsetICFocus(R->Input_Context);
1357 #endif
1358 #ifdef CURSOR_BLINK
1359             if (R->Options & Opt_cursorBlink)
1360               R->blink_ev.stop ();
1361             R->hidden_cursor = 0;
1362 #endif
1363         }
1364         break;
1365
1366     case ConfigureNotify:
1367         if (ev->xconfigure.window == R->TermWin.parent[0]) {
1368             int             height, width;
1369
1370             do {        /* Wrap lots of configures into one */
1371                 width = ev->xconfigure.width;
1372                 height = ev->xconfigure.height;
1373                 D_SIZE((stderr, "Size: ConfigureNotify: %4d x %4d", width, height));
1374             } while (XCheckTypedWindowEvent(R->Xdisplay, ev->xconfigure.window,
1375                                             ConfigureNotify, ev));
1376             if (R->szHint.width != width || R->szHint.height != height) {
1377                 D_SIZE((stderr, "Size: Resizing from: %4d x %4d", R->szHint.width, R->szHint.height));
1378                 rxvt_resize_all_windows(aR_ (unsigned int)width,
1379                                         (unsigned int)height, 1);
1380             }
1381 #ifdef DEBUG_SIZE
1382             else {
1383                 D_SIZE((stderr, "Size: Not resizing"));
1384             }
1385 #endif
1386 #ifdef TRANSPARENT              /* XXX: maybe not needed - leave in for now */
1387             if (R->Options & Opt_transparent) {
1388                 rxvt_check_our_parents(aR);
1389                 if (R->am_transparent)
1390                     R->want_full_refresh = 1;
1391             }
1392 #endif
1393         }
1394         break;
1395
1396     case SelectionClear:
1397         rxvt_selection_clear(aR);
1398         break;
1399
1400     case SelectionNotify:
1401         if (R->selection_wait == Sel_normal)
1402             rxvt_selection_paste(aR_ ev->xselection.requestor,
1403                                  ev->xselection.property, True);
1404         break;
1405
1406     case SelectionRequest:
1407         rxvt_selection_send(aR_ &(ev->xselectionrequest));
1408         break;
1409
1410     case UnmapNotify:
1411         R->TermWin.mapped = 0;
1412         break;
1413
1414     case MapNotify:
1415         R->TermWin.mapped = 1;
1416         break;
1417
1418     case PropertyNotify:
1419         if (ev->xproperty.atom == R->xa[XA_VT_SELECTION]) {
1420             if (ev->xproperty.state == PropertyNewValue)
1421                 rxvt_selection_property(aR_ ev->xproperty.window,
1422                                         ev->xproperty.atom);
1423             break;
1424         }
1425 #ifdef TRANSPARENT
1426     /*
1427      * if user used some Esetroot compatible prog to set the root bg,
1428      * use the property to determine the pixmap.  We use it later on.
1429      */
1430         if (R->xa[XA_XROOTPMAPID] == 0)
1431             R->xa[XA_XROOTPMAPID] = XInternAtom(R->Xdisplay,
1432                                                "_XROOTPMAP_ID", False);
1433         if (ev->xproperty.atom != R->xa[XA_XROOTPMAPID])
1434             break;
1435     /* FALLTHROUGH */
1436     case ReparentNotify:
1437         if ((R->Options & Opt_transparent) && rxvt_check_our_parents(aR)) {
1438             if (R->am_transparent)
1439                 R->want_full_refresh = 1;
1440         }
1441 #endif                          /* TRANSPARENT */
1442         break;
1443
1444     case GraphicsExpose:
1445     case Expose:
1446         if (ev->xany.window == R->TermWin.vt) {
1447 #ifdef NO_SLOW_LINK_SUPPORT
1448             rxvt_scr_expose(aR_ ev->xexpose.x, ev->xexpose.y,
1449                             ev->xexpose.width, ev->xexpose.height, False);
1450 #else
1451             // don't understand this, so commented it out
1452             rxvt_scr_expose(aR_ ev->xexpose.x, ev->xexpose.y,
1453                             ev->xexpose.width, ev->xexpose.height, False);
1454             //rxvt_scr_expose(aR_ ev->xexpose.x, 0,
1455             //              ev->xexpose.width, R->TermWin.height, False);
1456 #endif
1457             R->want_refresh = 1;
1458         } else {
1459             XEvent          unused_xevent;
1460
1461             while (XCheckTypedWindowEvent(R->Xdisplay, ev->xany.window,
1462                                           Expose,
1463                                           &unused_xevent)) ;
1464             while (XCheckTypedWindowEvent(R->Xdisplay, ev->xany.window,
1465                                           GraphicsExpose,
1466                                           &unused_xevent)) ;
1467             if (isScrollbarWindow(ev->xany.window)) {
1468                 scrollbar_setIdle();
1469                 rxvt_scrollbar_show(aR_ 0);
1470             }
1471 #ifdef MENUBAR
1472             if (menubar_visible(aR) && isMenuBarWindow(ev->xany.window))
1473                 rxvt_menubar_expose(aR);
1474 #endif
1475 #ifdef RXVT_GRAPHICS
1476             rxvt_Gr_expose(aR_ ev->xany.window);
1477 #endif
1478         }
1479         break;
1480
1481     case MotionNotify:
1482 #ifdef POINTER_BLANK
1483         if (R->hidden_pointer)
1484             R->pointer_unblank ();
1485 #endif
1486 #if MENUBAR
1487         if (isMenuBarWindow(ev->xany.window)) {
1488             rxvt_menubar_control(aR_ &(ev->xbutton));
1489             break;
1490         }
1491 #endif
1492         if ((R->PrivateModes & PrivMode_mouse_report) && !(R->bypass_keystate))
1493             break;
1494
1495         if (ev->xany.window == R->TermWin.vt) {
1496             if ((ev->xbutton.state & (Button1Mask | Button3Mask))) {
1497                 while (XCheckTypedWindowEvent(R->Xdisplay, R->TermWin.vt,
1498                                               MotionNotify, ev)) ;
1499                 XQueryPointer(R->Xdisplay, R->TermWin.vt,
1500                               &unused_root, &unused_child,
1501                               &unused_root_x, &unused_root_y,
1502                               &(ev->xbutton.x), &(ev->xbutton.y),
1503                               &unused_mask);
1504 #ifdef MOUSE_THRESHOLD
1505             /* deal with a `jumpy' mouse */
1506                 if ((ev->xmotion.time - R->MEvent.time) > MOUSE_THRESHOLD) {
1507 #endif
1508                     rxvt_selection_extend(aR_ (ev->xbutton.x), (ev->xbutton.y),
1509                                   (ev->xbutton.state & Button3Mask) ? 2 : 0);
1510 #ifdef SELECTION_SCROLLING
1511                     if (ev->xbutton.y<R->TermWin.int_bwidth ||
1512                         Pixel2Row(ev->xbutton.y)>(R->TermWin.nrow-1)) {
1513                         int dist;
1514                         
1515                         R->pending_scroll_selection=1;
1516                         
1517                           /* don't clobber the current delay if we are
1518                            * already in the middle of scrolling.
1519                            */
1520                         if (R->scroll_selection_delay<=0)
1521                             R->scroll_selection_delay=SCROLLBAR_CONTINUOUS_DELAY;
1522
1523                           /* save the event params so we can highlight
1524                            * the selection in the pending-scroll loop
1525                            */
1526                         R->selection_save_x=ev->xbutton.x;
1527                         R->selection_save_y=ev->xbutton.y;
1528                         R->selection_save_state=
1529                             (ev->xbutton.state & Button3Mask) ? 2 : 0;
1530
1531                           /* calc number of lines to scroll */
1532                         if (ev->xbutton.y<R->TermWin.int_bwidth) {
1533                             R->scroll_selection_dir = UP;
1534                             dist = R->TermWin.int_bwidth - ev->xbutton.y;
1535                         }
1536                         else {
1537                             R->scroll_selection_dir = DN;
1538                             dist = ev->xbutton.y -
1539                                 (R->TermWin.int_bwidth + R->TermWin.height);
1540                         }
1541                         R->scroll_selection_lines=(Pixel2Height(dist)/
1542                             SELECTION_SCROLL_LINE_SPEEDUP)+1;
1543                         MIN_IT(R->scroll_selection_lines,
1544                             SELECTION_SCROLL_MAX_LINES);
1545                     }
1546                     else {
1547                           /* we are within the text window, so we
1548                            * shouldn't be scrolling
1549                            */
1550                         R->pending_scroll_selection = 0;
1551                     }
1552 #endif
1553 #ifdef MOUSE_THRESHOLD
1554                 }
1555 #endif
1556             }
1557         } else if (isScrollbarWindow(ev->xany.window) && scrollbar_isMotion()) {
1558             while (XCheckTypedWindowEvent(R->Xdisplay, R->scrollBar.win,
1559                                           MotionNotify, ev)) ;
1560             XQueryPointer(R->Xdisplay, R->scrollBar.win,
1561                           &unused_root, &unused_child,
1562                           &unused_root_x, &unused_root_y,
1563                           &(ev->xbutton.x), &(ev->xbutton.y),
1564                           &unused_mask);
1565             rxvt_scr_move_to(aR_ scrollbar_position(ev->xbutton.y) - R->csrO,
1566                              scrollbar_size());
1567             rxvt_scr_refresh(aR_ R->refresh_type);
1568             R->refresh_limit = 0;
1569             rxvt_scrollbar_show(aR_ 1);
1570         }
1571         break;
1572     }
1573 }
1574
1575 /* INTPROTO */
1576 void
1577 rxvt_button_press(pR_ XButtonEvent *ev)
1578 {
1579     int             reportmode = 0, clickintime;
1580
1581     R->bypass_keystate = ev->state & (R->ModMetaMask | ShiftMask);
1582     if (!R->bypass_keystate)
1583         reportmode = !!(R->PrivateModes & PrivMode_mouse_report);
1584 /*
1585  * VT window processing of button press
1586  */
1587     if (ev->window == R->TermWin.vt)
1588       {
1589 #if RXVT_GRAPHICS
1590         if (ev->subwindow != None)
1591           rxvt_Gr_ButtonPress(ev->x, ev->y);
1592         else
1593 #endif
1594           {
1595             clickintime = ev->time - R->MEvent.time < MULTICLICK_TIME;
1596             if (reportmode)
1597               {
1598                 /* mouse report from vt window */
1599                 /* save the xbutton state (for ButtonRelease) */
1600                 R->MEvent.state = ev->state;
1601 #ifdef MOUSE_REPORT_DOUBLECLICK
1602                 if (ev->button == R->MEvent.button && clickintime)
1603                   {
1604                     /* same button, within alloted time */
1605                     R->MEvent.clicks++;
1606                     if (R->MEvent.clicks > 1)
1607                       {
1608                         /* only report double clicks */
1609                         R->MEvent.clicks = 2;
1610                         rxvt_mouse_report(aR_ ev);
1611
1612                         /* don't report the release */
1613                         R->MEvent.clicks = 0;
1614                         R->MEvent.button = AnyButton;
1615                       }
1616                   }
1617                 else
1618                   {
1619                     /* different button, or time expired */
1620                     R->MEvent.clicks = 1;
1621                     R->MEvent.button = ev->button;
1622                     rxvt_mouse_report(aR_ ev);
1623                   }
1624 #else
1625                 R->MEvent.button = ev->button;
1626                 rxvt_mouse_report(aR_ ev);
1627 #endif                          /* MOUSE_REPORT_DOUBLECLICK */
1628               }
1629             else
1630               {
1631                 if (ev->button != R->MEvent.button)
1632                     R->MEvent.clicks = 0;
1633                 switch (ev->button)
1634                   {
1635                     case Button1:
1636                         if (R->MEvent.button == Button1 && clickintime)
1637                           R->MEvent.clicks++;
1638                         else
1639                           R->MEvent.clicks = 1;
1640                         rxvt_selection_click(aR_ R->MEvent.clicks, ev->x, ev->y);
1641                         R->MEvent.button = Button1;
1642                         break;
1643
1644                     case Button3:
1645                         if (R->MEvent.button == Button3 && clickintime)
1646                           rxvt_selection_rotate(aR_ ev->x, ev->y);
1647                         else
1648                           rxvt_selection_extend(aR_ ev->x, ev->y, 1);
1649                         R->MEvent.button = Button3;
1650                         break;
1651                   }
1652               }
1653             R->MEvent.time = ev->time;
1654             return;
1655           }
1656       }
1657
1658 /*
1659  * Scrollbar window processing of button press
1660  */
1661     if (isScrollbarWindow(ev->window))
1662       {
1663         scrollbar_setIdle();
1664         /*
1665          * Rxvt-style scrollbar:
1666          * move up if mouse is above slider
1667          * move dn if mouse is below slider
1668          *
1669          * XTerm-style scrollbar:
1670          * Move display proportional to pointer location
1671          * pointer near top -> scroll one line
1672          * pointer near bot -> scroll full page
1673          */
1674 #ifndef NO_SCROLLBAR_REPORT
1675         if (reportmode) {
1676             /*
1677              * Mouse report disabled scrollbar:
1678              * arrow buttons - send up/down
1679              * click on scrollbar - send pageup/down
1680              */
1681             if ((R->scrollBar.style == R_SB_NEXT
1682                  && scrollbarnext_upButton(ev->y))
1683                 || (R->scrollBar.style == R_SB_RXVT
1684                     && scrollbarrxvt_upButton(ev->y)))
1685                 R->tt_printf("\033[A");
1686             else if ((R->scrollBar.style == R_SB_NEXT
1687                       && scrollbarnext_dnButton(ev->y))
1688                      || (R->scrollBar.style == R_SB_RXVT
1689                          && scrollbarrxvt_dnButton(ev->y)))
1690                 R->tt_printf("\033[B");
1691             else
1692                 switch (ev->button) {
1693                 case Button2:
1694                     R->tt_printf("\014");
1695                     break;
1696                 case Button1:
1697                     R->tt_printf("\033[6~");
1698                     break;
1699                 case Button3:
1700                     R->tt_printf("\033[5~");
1701                     break;
1702                 }
1703           }
1704         else
1705 #endif                          /* NO_SCROLLBAR_REPORT */
1706           {
1707             char            upordown = 0;
1708
1709             if (R->scrollBar.style == R_SB_NEXT) {
1710                 if (scrollbarnext_upButton(ev->y))
1711                     upordown = -1;      /* up */
1712                 else if (scrollbarnext_dnButton(ev->y))
1713                     upordown = 1;       /* down */
1714             } else if (R->scrollBar.style == R_SB_RXVT) {
1715                 if (scrollbarrxvt_upButton(ev->y))
1716                     upordown = -1;      /* up */
1717                 else if (scrollbarrxvt_dnButton(ev->y))
1718                     upordown = 1;       /* down */
1719             }
1720             if (upordown) { 
1721 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1722                 R->scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
1723 #endif
1724                 if (rxvt_scr_page(aR_ upordown < 0 ? UP : DN, 1)) {
1725                     if (upordown < 0)
1726                         scrollbar_setUp();
1727                     else
1728                         scrollbar_setDn();
1729                 }
1730             } else
1731                 switch (ev->button) {
1732                 case Button2:
1733                     switch (R->scrollbar_align) {
1734                     case R_SB_ALIGN_TOP:
1735                         R->csrO = 0;
1736                         break;
1737                     case R_SB_ALIGN_CENTRE:
1738                         R->csrO = (R->scrollBar.bot - R->scrollBar.top) / 2;
1739                         break;
1740                     case R_SB_ALIGN_BOTTOM:
1741                         R->csrO = R->scrollBar.bot - R->scrollBar.top;
1742                         break;
1743                     }
1744                     if (R->scrollBar.style == R_SB_XTERM
1745                         || scrollbar_above_slider(ev->y)
1746                         || scrollbar_below_slider(ev->y))
1747                         rxvt_scr_move_to(aR_
1748                                          scrollbar_position(ev->y) - R->csrO,
1749                                          scrollbar_size());
1750                     scrollbar_setMotion();
1751                     break;
1752
1753                 case Button1:
1754                     if (R->scrollbar_align == R_SB_ALIGN_CENTRE)
1755                         R->csrO = ev->y - R->scrollBar.top;
1756                     /* FALLTHROUGH */
1757
1758                 case Button3:
1759                     if (R->scrollBar.style != R_SB_XTERM) {
1760                         if (scrollbar_above_slider(ev->y))
1761 # ifdef RXVT_SCROLL_FULL
1762                             rxvt_scr_page(aR_ UP, R->TermWin.nrow - 1);
1763 # else
1764                             rxvt_scr_page(aR_ UP, R->TermWin.nrow / 4);
1765 # endif
1766                         else if (scrollbar_below_slider(ev->y))
1767 # ifdef RXVT_SCROLL_FULL
1768                             rxvt_scr_page(aR_ DN, R->TermWin.nrow - 1);
1769 # else
1770                             rxvt_scr_page(aR_ DN, R->TermWin.nrow / 4);
1771 # endif
1772                         else
1773                             scrollbar_setMotion();
1774                     } else {
1775                         rxvt_scr_page(aR_ (ev->button == Button1 ? DN : UP),
1776                                       (R->TermWin.nrow
1777                                        * scrollbar_position(ev->y)
1778                                        / scrollbar_size()));
1779                     }
1780                     break;
1781                 }
1782           }
1783         return;
1784     }
1785 #if MENUBAR
1786     /*
1787      * Menubar window processing of button press
1788      */
1789     if (isMenuBarWindow(ev->window))
1790         rxvt_menubar_control(aR_ ev);
1791 #endif
1792 }
1793
1794 /* INTPROTO */
1795 void
1796 rxvt_button_release(pR_ XButtonEvent *ev)
1797 {
1798     int             reportmode = 0;
1799
1800     R->csrO = 0;                /* reset csr Offset */
1801     if (!R->bypass_keystate)
1802         reportmode = !!(R->PrivateModes & PrivMode_mouse_report);
1803
1804     if (scrollbar_isUpDn()) {
1805         scrollbar_setIdle();
1806         rxvt_scrollbar_show(aR_ 0);
1807 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1808         R->refresh_type &= ~SMOOTH_REFRESH;
1809 #endif
1810     }
1811 #ifdef SELECTION_SCROLLING
1812     R->pending_scroll_selection=0;
1813 #endif
1814     if (ev->window == R->TermWin.vt) 
1815       {
1816 #ifdef RXVT_GRAPHICS
1817         if (ev->subwindow != None)
1818           rxvt_Gr_ButtonRelease(ev->x, ev->y);
1819         else 
1820 #endif
1821           {
1822             if (reportmode) 
1823               {
1824                 /* mouse report from vt window */
1825                 /* don't report release of wheel "buttons" */
1826                 if (ev->button >= 4)
1827                     return;
1828 #ifdef MOUSE_REPORT_DOUBLECLICK
1829                 /* only report the release of 'slow' single clicks */
1830                 if (R->MEvent.button != AnyButton
1831                     && (ev->button != R->MEvent.button
1832                         || (ev->time - R->MEvent.time
1833                             > MULTICLICK_TIME / 2))) 
1834                   {
1835                     R->MEvent.clicks = 0;
1836                     R->MEvent.button = AnyButton;
1837                     rxvt_mouse_report(aR_ ev);
1838                   }
1839 #else                           /* MOUSE_REPORT_DOUBLECLICK */
1840                 R->MEvent.button = AnyButton;
1841                 rxvt_mouse_report(aR_ ev);
1842 #endif                          /* MOUSE_REPORT_DOUBLECLICK */
1843                 return;
1844             }
1845             /*
1846              * dumb hack to compensate for the failure of click-and-drag
1847              * when overriding mouse reporting
1848              */
1849             if (R->PrivateModes & PrivMode_mouse_report
1850                 && R->bypass_keystate
1851                 && ev->button == Button1 && R->MEvent.clicks <= 1)
1852                 rxvt_selection_extend(aR_ ev->x, ev->y, 0);
1853
1854             switch (ev->button) {
1855             case Button1:
1856             case Button3:
1857                 rxvt_selection_make(aR_ ev->time);
1858                 break;
1859             case Button2:
1860                 rxvt_selection_request(aR_ ev->time, ev->x, ev->y);
1861                 break;
1862 #ifdef MOUSE_WHEEL
1863             case Button4:
1864             case Button5:
1865                   {
1866                     int             i, v;
1867
1868                     v = (ev->button == Button4) ? UP : DN;
1869                     if (ev->state & ShiftMask)
1870                         i = 1;
1871                     else if ((R->Options & Opt_mouseWheelScrollPage))
1872                         i = R->TermWin.nrow - 1;
1873                     else
1874                         i = 5;
1875 # ifdef MOUSE_SLIP_WHEELING
1876                     if (ev->state & ControlMask) 
1877                       {
1878                         R->mouse_slip_wheel_speed += (v ? -1 : 1);
1879                         R->mouse_slip_wheel_delay = SCROLLBAR_CONTINUOUS_DELAY;
1880                       }
1881 # endif
1882 # ifdef JUMP_MOUSE_WHEEL
1883                     rxvt_scr_page(aR_ v, i);
1884                     rxvt_scr_refresh(aR_ SMOOTH_REFRESH);
1885                     rxvt_scrollbar_show(aR_ 1);
1886 # else
1887                     for (; i--;)
1888                       {
1889                         rxvt_scr_page(aR_ v, 1);
1890                         rxvt_scr_refresh(aR_ SMOOTH_REFRESH);
1891                         rxvt_scrollbar_show(aR_ 1);
1892                       }
1893 # endif
1894                   }
1895                 break;
1896 #endif
1897               }
1898           }
1899       }
1900 #ifdef MENUBAR
1901     else if (isMenuBarWindow(ev->window))
1902         rxvt_menubar_control(aR_ ev);
1903 #endif
1904 }
1905
1906
1907 #ifdef TRANSPARENT
1908 /*
1909  * Check our parents are still who we think they are.
1910  * Do transparency updates if required
1911  */
1912 /* EXTPROTO */
1913 int
1914 rxvt_check_our_parents(pR)
1915 {
1916     int             i, pchanged, aformat, have_pixmap, rootdepth;
1917     unsigned long   nitems, bytes_after;
1918     Atom            atype;
1919     unsigned char   *prop = NULL;
1920     Window          root, oldp, *list;
1921     Pixmap          rootpixmap = None;
1922     XWindowAttributes wattr, wrootattr;
1923
1924     pchanged = 0;
1925
1926     if (!(R->Options & Opt_transparent))
1927         return pchanged;        /* Don't try any more */
1928
1929     XGetWindowAttributes(R->Xdisplay, Xroot, &wrootattr);
1930     rootdepth = wrootattr.depth;
1931
1932     XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[0], &wattr);
1933     if (rootdepth != wattr.depth) {
1934         if (R->am_transparent) {
1935             pchanged = 1;
1936             XSetWindowBackground(R->Xdisplay, R->TermWin.vt,
1937                                  R->PixColors[Color_bg]);
1938             R->am_transparent = R->am_pixmap_trans = 0;
1939         }
1940         return pchanged;        /* Don't try any more */
1941     }
1942
1943 /* Get all X ops out of the queue so that our information is up-to-date. */
1944     XSync(R->Xdisplay, False);
1945
1946 /*
1947  * Make the frame window set by the window manager have
1948  * the root background. Some window managers put multiple nested frame
1949  * windows for each client, so we have to take care about that.
1950  */
1951     i = (R->xa[XA_XROOTPMAPID] != 0
1952          && (XGetWindowProperty(R->Xdisplay, Xroot, R->xa[XA_XROOTPMAPID],
1953                                 0L, 1L, False, XA_PIXMAP, &atype, &aformat,
1954                                 &nitems, &bytes_after, &prop) == Success));
1955     if (!i || prop == NULL)
1956         have_pixmap = 0;
1957     else {
1958         have_pixmap = 1;
1959         rootpixmap = *((Pixmap *)prop);
1960         XFree(prop);
1961     }
1962     if (have_pixmap) {
1963 /*
1964  * Copy Xroot pixmap transparency
1965  */
1966         int             sx, sy, nx, ny;
1967         unsigned int    nw, nh;
1968         Window          cr;
1969         XImage         *image;
1970         GC              gc;
1971         XGCValues       gcvalue;
1972
1973         XTranslateCoordinates(R->Xdisplay, R->TermWin.parent[0], Xroot,
1974                               0, 0, &sx, &sy, &cr);
1975         nw = (unsigned int)R->szHint.width;
1976         nh = (unsigned int)R->szHint.height;
1977         nx = ny = 0;
1978         if (sx < 0) {
1979             nw += sx;
1980             nx = -sx;
1981             sx = 0;
1982         }
1983         if (sy < 0) {
1984             nh += sy;
1985             ny = -sy;
1986             sy = 0;
1987         }
1988         MIN_IT(nw, (unsigned int)(wrootattr.width - sx));
1989         MIN_IT(nh, (unsigned int)(wrootattr.height - sy));
1990         R->allowedxerror = -1;
1991         image = XGetImage(R->Xdisplay, rootpixmap, sx, sy, nw, nh, AllPlanes,
1992                           ZPixmap);
1993         /* XXX: handle BadMatch - usually because we're outside the pixmap */
1994         /* XXX: may need a delay here? */
1995         R->allowedxerror = 0;
1996         if (image == NULL) {
1997             if (R->am_transparent && R->am_pixmap_trans) {
1998                 pchanged = 1;
1999                 if (R->TermWin.pixmap != None) {
2000                     XFreePixmap(R->Xdisplay, R->TermWin.pixmap);
2001                     R->TermWin.pixmap = None;
2002                 }
2003             }
2004             R->am_pixmap_trans = 0;
2005         } else {
2006             if (R->TermWin.pixmap != None)
2007                 XFreePixmap(R->Xdisplay, R->TermWin.pixmap);
2008             R->TermWin.pixmap = XCreatePixmap(R->Xdisplay, R->TermWin.vt,
2009                                               (unsigned int)R->szHint.width,
2010                                               (unsigned int)R->szHint.height,
2011                                               (unsigned int)image->depth);
2012             gc = XCreateGC(R->Xdisplay, R->TermWin.vt, 0UL, &gcvalue);
2013             XPutImage(R->Xdisplay, R->TermWin.pixmap, gc, image, 0, 0,
2014                       nx, ny, (unsigned int)image->width,
2015                       (unsigned int)image->height);
2016             XFreeGC(R->Xdisplay, gc);
2017             XDestroyImage(image);
2018             XSetWindowBackgroundPixmap(R->Xdisplay, R->TermWin.vt,
2019                                        R->TermWin.pixmap);
2020             if (!R->am_transparent || !R->am_pixmap_trans)
2021                 pchanged = 1;
2022             R->am_transparent = R->am_pixmap_trans = 1;
2023         }
2024     }
2025     if (!R->am_pixmap_trans) {
2026         unsigned int    n;
2027 /*
2028  * InheritPixmap transparency
2029  */
2030         D_X((stderr, "InheritPixmap Seeking to  %08lx", Xroot));
2031         for (i = 1; i < (int)(sizeof(R->TermWin.parent) / sizeof(Window));
2032              i++) {
2033             oldp = R->TermWin.parent[i];
2034             XQueryTree(R->Xdisplay, R->TermWin.parent[i - 1], &root,
2035                        &R->TermWin.parent[i], &list, &n);
2036             XFree(list);
2037             D_X((stderr, "InheritPixmap Parent[%d] = %08lx", i, R->TermWin.parent[i]));
2038             if (R->TermWin.parent[i] == Xroot) {
2039                 if (oldp != None)
2040                     pchanged = 1;
2041                 break;
2042             }
2043             if (oldp != R->TermWin.parent[i])
2044                 pchanged = 1;
2045         }
2046         n = 0;
2047         if (pchanged) {
2048             for (; n < (unsigned int)i; n++) {
2049                 XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[n], &wattr);
2050                 D_X((stderr, "InheritPixmap Checking Parent[%d]: %s", n, (wattr.depth == rootdepth && wattr.class != InputOnly) ? "OK" : "FAIL"));
2051                 if (wattr.depth != rootdepth || wattr.class == InputOnly) {
2052                     n = (int)(sizeof(R->TermWin.parent) / sizeof(Window)) + 1;
2053                     break;
2054                 }
2055             }
2056         }
2057         if (n > (int)(sizeof(R->TermWin.parent)
2058                       / sizeof(R->TermWin.parent[0]))) {
2059             D_X((stderr, "InheritPixmap Turning off"));
2060             XSetWindowBackground(R->Xdisplay, R->TermWin.parent[0],
2061                                  R->PixColors[Color_fg]);
2062             XSetWindowBackground(R->Xdisplay, R->TermWin.vt,
2063                                  R->PixColors[Color_bg]);
2064             R->am_transparent = 0;
2065             /* XXX: also turn off Opt_transparent? */
2066         } else {
2067             /* wait (an arbitrary period) for the WM to do its thing
2068              * needed for fvwm2.2.2 (and before?) */
2069 # ifdef HAVE_NANOSLEEP
2070             struct timespec rqt;
2071
2072             rqt.tv_sec = 1;
2073             rqt.tv_nsec = 0;
2074             nanosleep(&rqt, NULL);
2075 # else
2076             sleep(1);   
2077 # endif
2078             D_X((stderr, "InheritPixmap Turning on (%d parents)", i - 1));
2079             for (n = 0; n < (unsigned int)i; n++)
2080                 XSetWindowBackgroundPixmap(R->Xdisplay, R->TermWin.parent[n],
2081                                            ParentRelative);
2082             XSetWindowBackgroundPixmap(R->Xdisplay, R->TermWin.vt,
2083                                        ParentRelative);
2084             R->am_transparent = 1;
2085         }
2086         for (; i < (int)(sizeof(R->TermWin.parent) / sizeof(Window)); i++)
2087             R->TermWin.parent[i] = None;
2088     }
2089     return pchanged;
2090 }
2091 #endif
2092
2093 /*}}} */
2094
2095 /*{{{ print pipe */
2096 /*----------------------------------------------------------------------*/
2097 #ifdef PRINTPIPE
2098 /* EXTPROTO */
2099 FILE           *
2100 rxvt_popen_printer(pR)
2101 {
2102     FILE           *stream = popen(R->rs[Rs_print_pipe], "w");
2103
2104     if (stream == NULL)
2105         rxvt_print_error("can't open printer pipe");
2106     return stream;
2107 }
2108
2109 /* EXTPROTO */
2110 int
2111 rxvt_pclose_printer (FILE *stream)
2112 {
2113   fflush (stream);
2114 /* pclose() reported not to work on SunOS 4.1.3 */
2115 # if defined (__sun__)          /* TODO: RESOLVE THIS */
2116 /* pclose works provided SIGCHLD handler uses waitpid */
2117   return pclose (stream);       /* return fclose (stream); */
2118 # else
2119   return pclose (stream);
2120 # endif
2121 }
2122
2123 /*
2124  * simulate attached vt100 printer
2125  */
2126 /* INTPROTO */
2127 void
2128 rxvt_process_print_pipe(pR)
2129 {
2130     int             done;
2131     FILE           *fd;
2132
2133     if ((fd = rxvt_popen_printer(aR)) == NULL)
2134         return;
2135
2136 /*
2137  * Send all input to the printer until either ESC[4i or ESC[?4i
2138  * is received.
2139  */
2140     for (done = 0; !done;) {
2141         unsigned char   buf[8];
2142         unsigned char   ch;
2143         unsigned int    i, len;
2144
2145         if ((ch = rxvt_cmd_getc(aR)) != C0_ESC) {
2146             if (putc(ch, fd) == EOF)
2147                 break;          /* done = 1 */
2148         } else {
2149             len = 0;
2150             buf[len++] = ch;
2151
2152             if ((buf[len++] = rxvt_cmd_getc(aR)) == '[') {
2153                 if ((ch = rxvt_cmd_getc(aR)) == '?') {
2154                     buf[len++] = '?';
2155                     ch = rxvt_cmd_getc(aR);
2156                 }
2157                 if ((buf[len++] = ch) == '4') {
2158                     if ((buf[len++] = rxvt_cmd_getc(aR)) == 'i')
2159                         break;  /* done = 1 */
2160                 }
2161             }
2162             for (i = 0; i < len; i++)
2163                 if (putc(buf[i], fd) == EOF) {
2164                     done = 1;
2165                     break;
2166                 }
2167         }
2168     }
2169     rxvt_pclose_printer(fd);
2170 }
2171 #endif                          /* PRINTPIPE */
2172 /*}}} */
2173
2174 /* *INDENT-OFF* */
2175 enum {
2176     C1_40 = 0x40,
2177             C1_41 , C1_BPH, C1_NBH, C1_44 , C1_NEL, C1_SSA, C1_ESA,
2178     C1_HTS, C1_HTJ, C1_VTS, C1_PLD, C1_PLU, C1_RI , C1_SS2, C1_SS3,
2179     C1_DCS, C1_PU1, C1_PU2, C1_STS, C1_CCH, C1_MW , C1_SPA, C1_EPA,
2180     C1_SOS, C1_59 , C1_SCI, C1_CSI, CS_ST , C1_OSC, C1_PM , C1_APC
2181 };
2182 /* *INDENT-ON* */
2183
2184 /*{{{ process non-printing single characters */
2185 /* INTPROTO */
2186 void
2187 rxvt_process_nonprinting(pR_ unsigned char ch)
2188 {
2189     switch (ch) {
2190     case C0_ENQ:        /* terminal Status */
2191         if (R->rs[Rs_answerbackstring])
2192             R->tt_write(
2193                 (const unsigned char *)R->rs[Rs_answerbackstring],
2194                 (unsigned int)STRLEN(R->rs[Rs_answerbackstring]));
2195         else
2196             R->tt_write((unsigned char *)VT100_ANS,
2197                           (unsigned int)STRLEN(VT100_ANS));
2198         break;
2199     case C0_BEL:        /* bell */
2200         rxvt_scr_bell(aR);
2201         break;
2202     case C0_BS:         /* backspace */
2203         rxvt_scr_backspace(aR);
2204         break;
2205     case C0_HT:         /* tab */
2206         rxvt_scr_tab(aR_ 1);
2207         break;
2208     case C0_CR:         /* carriage return */
2209         rxvt_scr_gotorc(aR_ 0, 0, R_RELATIVE);
2210         break;
2211     case C0_VT:         /* vertical tab, form feed */
2212     case C0_FF:
2213     case C0_LF:         /* line feed */
2214         rxvt_scr_index(aR_ UP);
2215         break;
2216     case C0_SO:         /* shift out - acs */
2217         rxvt_scr_charset_choose(aR_ 1);
2218         break;
2219     case C0_SI:         /* shift in - acs */
2220         rxvt_scr_charset_choose(aR_ 0);
2221         break;
2222     }
2223 }
2224 /*}}} */
2225
2226
2227 /*{{{ process VT52 escape sequences */
2228 /* INTPROTO */
2229 void
2230 rxvt_process_escape_vt52(pR_ unsigned char ch)
2231 {
2232     int row, col;
2233     
2234     switch (ch) {
2235     case 'A':           /* cursor up */
2236         rxvt_scr_gotorc(aR_ -1, 0, R_RELATIVE | C_RELATIVE);    
2237         break;
2238     case 'B':           /* cursor down */
2239         rxvt_scr_gotorc(aR_ 1, 0, R_RELATIVE | C_RELATIVE);     
2240         break;
2241     case 'C':           /* cursor right */
2242         rxvt_scr_gotorc(aR_ 0, 1, R_RELATIVE | C_RELATIVE);     
2243         break;
2244     case 'D':           /* cursor left */
2245         rxvt_scr_gotorc(aR_ 0, -1, R_RELATIVE | C_RELATIVE);    
2246         break;
2247     case 'H':           /* cursor home */
2248         rxvt_scr_gotorc(aR_ 0, 0, 0);   
2249         break;
2250     case 'I':           /* cursor up and scroll down if needed */
2251         rxvt_scr_index(aR_ DN);
2252         break;
2253     case 'J':           /* erase to end of screen */
2254         rxvt_scr_erase_screen(aR_ 0);
2255         break;
2256     case 'K':           /* erase to end of line */
2257         rxvt_scr_erase_line(aR_ 0);
2258         break;
2259     case 'Y':           /* move to specified row and col */
2260           /* full command is 'ESC Y row col' where row and col
2261            * are encoded by adding 32 and sending the ascii
2262            * character.  eg. SPACE = 0, '+' = 13, '0' = 18,
2263            * etc. */
2264         row = rxvt_cmd_getc(aR) - ' ';
2265         col = rxvt_cmd_getc(aR) - ' ';
2266         rxvt_scr_gotorc(aR_ row, col, 0);
2267         break;
2268     case 'Z':           /* identify the terminal type */
2269         R->tt_printf("\033/Z"); /* I am a VT100 emulating a VT52 */
2270         break;
2271     case '<':           /* turn off VT52 mode */
2272         PrivMode(0, PrivMode_vt52);
2273         break;
2274     case 'F':           /* use special graphics character set */
2275     case 'G':           /* use regular character set */
2276           /* unimplemented */
2277         break;
2278     case '=':           /* use alternate keypad mode */
2279     case '>':           /* use regular keypad mode */
2280           /* unimplemented */
2281         break;
2282     }
2283 }
2284 /*}}} */
2285
2286
2287 /*{{{ process escape sequences */
2288 /* INTPROTO */
2289 void
2290 rxvt_process_escape_seq(pR)
2291 {
2292     unsigned char   ch = rxvt_cmd_getc(aR);
2293
2294     if (R->PrivateModes & PrivMode_vt52) {
2295         rxvt_process_escape_vt52(aR_ ch);
2296         return;
2297     }
2298     
2299     switch (ch) {
2300     /* case 1:        do_tek_mode (); break; */
2301     case '#':
2302         if (rxvt_cmd_getc(aR) == '8')
2303             rxvt_scr_E(aR);
2304         break;
2305     case '(':
2306         rxvt_scr_charset_set(aR_ 0, (unsigned int)rxvt_cmd_getc(aR));
2307         break;
2308     case ')':
2309         rxvt_scr_charset_set(aR_ 1, (unsigned int)rxvt_cmd_getc(aR));
2310         break;
2311     case '*':
2312         rxvt_scr_charset_set(aR_ 2, (unsigned int)rxvt_cmd_getc(aR));
2313         break;
2314     case '+':
2315         rxvt_scr_charset_set(aR_ 3, (unsigned int)rxvt_cmd_getc(aR));
2316         break;
2317 #ifdef MULTICHAR_SET
2318     case '$':
2319         rxvt_scr_charset_set(aR_ -2, (unsigned int)rxvt_cmd_getc(aR));
2320         break;
2321 #endif
2322 #ifndef NO_FRILLS
2323     case '6':
2324         rxvt_scr_backindex(aR);
2325         break;
2326 #endif
2327     case '7':
2328         rxvt_scr_cursor(aR_ SAVE);
2329         break;
2330     case '8':
2331         rxvt_scr_cursor(aR_ RESTORE);
2332         break;
2333 #ifndef NO_FRILLS
2334     case '9':
2335         rxvt_scr_forwardindex(aR);
2336         break;
2337 #endif
2338     case '=':
2339     case '>':
2340         PrivMode((ch == '='), PrivMode_aplKP);
2341         break;
2342
2343     case C1_40:
2344         rxvt_cmd_getc(aR);
2345         break;
2346     case C1_44:
2347         rxvt_scr_index(aR_ UP);
2348         break;
2349
2350     /* 8.3.87: NEXT LINE */
2351     case C1_NEL:                /* ESC E */
2352         {
2353           uint32_t nlcr[] = { '\n', '\r' };
2354           rxvt_scr_add_lines(aR_ nlcr, 1, 2);
2355         }
2356         break;
2357
2358     /* kidnapped escape sequence: Should be 8.3.48 */
2359     case C1_ESA:                /* ESC G */
2360         rxvt_process_graphics(aR);
2361         break;
2362
2363     /* 8.3.63: CHARACTER TABULATION SET */
2364     case C1_HTS:                /* ESC H */
2365         rxvt_scr_set_tab(aR_ 1);
2366         break;
2367
2368     /* 8.3.105: REVERSE LINE FEED */
2369     case C1_RI:                 /* ESC M */
2370         rxvt_scr_index(aR_ DN);
2371         break;
2372
2373     /* 8.3.142: SINGLE-SHIFT TWO */
2374     /*case C1_SS2: scr_single_shift (2);   break; */
2375
2376     /* 8.3.143: SINGLE-SHIFT THREE */
2377     /*case C1_SS3: scr_single_shift (3);   break; */
2378
2379     /* 8.3.27: DEVICE CONTROL STRING */
2380     case C1_DCS:                /* ESC P */
2381         rxvt_process_dcs_seq(aR);
2382         break;
2383
2384     /* 8.3.110: SINGLE CHARACTER INTRODUCER */
2385     case C1_SCI:                /* ESC Z */
2386         R->tt_write((const unsigned char *)ESCZ_ANSWER,
2387                       (unsigned int)(sizeof(ESCZ_ANSWER) - 1));
2388         break;                  /* steal obsolete ESC [ c */
2389
2390     /* 8.3.16: CONTROL SEQUENCE INTRODUCER */
2391     case C1_CSI:                /* ESC [ */
2392         rxvt_process_csi_seq(aR);
2393         break;
2394
2395     /* 8.3.90: OPERATING SYSTEM COMMAND */
2396     case C1_OSC:                /* ESC ] */
2397         rxvt_process_osc_seq(aR);
2398         break;
2399
2400     /* 8.3.106: RESET TO INITIAL STATE */
2401     case 'c':
2402         rxvt_scr_poweron(aR);
2403         rxvt_scrollbar_show(aR_ 1);
2404         break;
2405
2406     /* 8.3.79: LOCKING-SHIFT TWO (see ISO2022) */
2407     case 'n':
2408         rxvt_scr_charset_choose(aR_ 2);
2409         break;
2410
2411     /* 8.3.81: LOCKING-SHIFT THREE (see ISO2022) */
2412     case 'o':
2413         rxvt_scr_charset_choose(aR_ 3);
2414         break;
2415     }
2416 }
2417 /*}}} */
2418
2419 /*{{{ process CONTROL SEQUENCE INTRODUCER (CSI) sequences `ESC[' */
2420 /* *INDENT-OFF* */
2421 enum {
2422     CSI_ICH = 0x40,
2423              CSI_CUU, CSI_CUD, CSI_CUF, CSI_CUB, CSI_CNL, CSI_CPL, CSI_CHA,
2424     CSI_CUP, CSI_CHT, CSI_ED , CSI_EL , CSI_IL , CSI_DL , CSI_EF , CSI_EA ,
2425     CSI_DCH, CSI_SEE, CSI_CPR, CSI_SU , CSI_SD , CSI_NP , CSI_PP , CSI_CTC,
2426     CSI_ECH, CSI_CVT, CSI_CBT, CSI_SRS, CSI_PTX, CSI_SDS, CSI_SIMD, CSI_5F,
2427     CSI_HPA, CSI_HPR, CSI_REP, CSI_DA , CSI_VPA, CSI_VPR, CSI_HVP, CSI_TBC,
2428     CSI_SM , CSI_MC , CSI_HPB, CSI_VPB, CSI_RM , CSI_SGR, CSI_DSR, CSI_DAQ,
2429     CSI_70 , CSI_71 , CSI_72 , CSI_73 , CSI_74 , CSI_75 , CSI_76 , CSI_77 ,
2430     CSI_78 , CSI_79 , CSI_7A , CSI_7B , CSI_7C , CSI_7D , CSI_7E , CSI_7F 
2431 };
2432
2433 #define make_byte(b7,b6,b5,b4,b3,b2,b1,b0)                      \
2434     (((b7) << 7) | ((b6) << 6) | ((b5) << 5) | ((b4) << 4)      \
2435      | ((b3) << 3) | ((b2) << 2) | ((b1) << 1) | (b0))
2436 #define get_byte_array_bit(array, bit)                          \
2437     (!!((array)[(bit) / 8] & (128 >> ((bit) & 7))))
2438
2439 const unsigned char csi_defaults[] = {
2440     make_byte(1,1,1,1,1,1,1,1), /* @, A, B, C, D, E, F, G, */
2441     make_byte(1,1,0,0,1,1,0,0), /* H, I, J, K, L, M, N, O, */
2442     make_byte(1,0,1,1,1,1,1,0), /* P, Q, R, S, T, U, V, W, */
2443     make_byte(1,1,1,0,0,0,1,0), /* X, Y, Z, [, \, ], ^, _, */
2444     make_byte(1,1,1,0,1,1,1,0), /* `, a, b, c, d, e, f, g, */
2445     make_byte(0,0,1,1,0,0,0,0), /* h, i, j, k, l, m, n, o, */
2446     make_byte(0,0,0,0,0,0,0,0), /* p, q, r, s, t, u, v, w, */
2447     make_byte(0,0,0,0,0,0,0,0)  /* x, y, z, {, |, }, ~,    */
2448 };
2449 /* *INDENT-ON* */
2450
2451 /* INTPROTO */
2452 void
2453 rxvt_process_csi_seq(pR)
2454 {
2455     unsigned char   ch, priv, i;
2456     unsigned int    nargs, p;
2457     int             n, ndef;
2458     int             arg[ESC_ARGS];
2459
2460     for (nargs = ESC_ARGS; nargs > 0;)
2461         arg[--nargs] = 0;
2462
2463     priv = 0;
2464     ch = rxvt_cmd_getc(aR);
2465     if (ch >= '<' && ch <= '?') {       /* '<' '=' '>' '?' */
2466         priv = ch;
2467         ch = rxvt_cmd_getc(aR);
2468     }
2469 /* read any numerical arguments */
2470     for (n = -1; ch < CSI_ICH; ) {
2471         if (isdigit(ch)) {
2472             if (n < 0)
2473                 n = ch - '0';
2474             else
2475                 n = n * 10 + ch - '0';
2476         } else if (ch == ';') {
2477             if (nargs < ESC_ARGS)
2478                 arg[nargs++] = n;
2479             n = -1;
2480         } else if (ch == '\b') {
2481             rxvt_scr_backspace(aR);
2482         } else if (ch == C0_ESC) {
2483             rxvt_process_escape_seq(aR);
2484             return;
2485         } else if (ch < ' ') {
2486             rxvt_process_nonprinting(aR_ ch);
2487         }
2488         ch = rxvt_cmd_getc(aR);
2489     }
2490
2491     if (ch > CSI_7F)
2492         return;
2493
2494     if (nargs < ESC_ARGS)
2495         arg[nargs++] = n;
2496
2497     i = ch - CSI_ICH;
2498     ndef = get_byte_array_bit(csi_defaults, i);
2499     for (p = 0; p < nargs; p++)
2500         if (arg[p] == -1)
2501             arg[p] = ndef;
2502
2503 #ifdef DEBUG_CMD
2504     fprintf(stderr, "CSI ");
2505     for (p = 0; p < nargs; p++)
2506         fprintf(stderr, "%d%s", arg[p], p < nargs - 1 ? ";" : "");
2507     fprintf(stderr, "%c\n", ch);
2508 #endif
2509
2510 /*
2511  * private mode handling
2512  */
2513     if (priv) {
2514         switch (priv) {
2515         case '>':
2516             if (ch == CSI_DA)   /* secondary device attributes */
2517                 R->tt_printf("\033[>%d;%-.8s;0c", 'R', VSTRING);
2518             break;
2519         case '?':
2520             if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
2521                 rxvt_process_terminal_mode(aR_ ch, priv, nargs, arg);
2522             break;
2523         }
2524         return;
2525     }
2526
2527     switch (ch) {
2528 /*
2529  * ISO/IEC 6429:1992(E) CSI sequences (defaults in parentheses)
2530  */
2531 #ifdef PRINTPIPE
2532     case CSI_MC:                /* 8.3.83: (0) MEDIA COPY */
2533         switch (arg[0]) {
2534         case 0:                 /* initiate transfer to primary aux device */
2535             rxvt_scr_printscreen(aR_ 0);
2536             break;
2537         case 5:                 /* start relay to primary aux device */
2538             rxvt_process_print_pipe(aR);
2539             break;
2540         }
2541         break;
2542 #endif
2543
2544     case CSI_CUU:               /* 8.3.22: (1) CURSOR UP */
2545     case CSI_VPR:               /* 8.3.161: (1) LINE POSITION FORWARD */
2546         arg[0] = -arg[0];
2547     /* FALLTHROUGH */
2548     case CSI_CUD:               /* 8.3.19: (1) CURSOR DOWN */
2549     case CSI_VPB:               /* 8.3.160: (1) LINE POSITION BACKWARD */
2550         rxvt_scr_gotorc(aR_ arg[0], 0, RELATIVE);
2551         break;
2552
2553     case CSI_CUB:               /* 8.3.18: (1) CURSOR LEFT */
2554     case CSI_HPB:               /* 8.3.59: (1) CHARACTER POSITION BACKWARD */
2555 #ifdef ISO6429
2556         arg[0] = -arg[0];
2557 #else                           /* emulate common DEC VTs */
2558         arg[0] = arg[0] ? -arg[0] : -1;
2559 #endif
2560     /* FALLTHROUGH */
2561     case CSI_CUF:               /* 8.3.20: (1) CURSOR RIGHT */
2562     case CSI_HPR:               /* 8.3.60: (1) CHARACTER POSITION FORWARD */
2563 #ifdef ISO6429
2564         rxvt_scr_gotorc(aR_ 0, arg[0], RELATIVE);
2565 #else                           /* emulate common DEC VTs */
2566         rxvt_scr_gotorc(aR_ 0, arg[0] ? arg[0] : 1, RELATIVE);
2567 #endif
2568         break;
2569
2570     case CSI_CPL:               /* 8.3.13: (1) CURSOR PRECEDING LINE */
2571         arg[0] = -arg[0];
2572     /* FALLTHROUGH */
2573     case CSI_CNL:               /* 8.3.12: (1) CURSOR NEXT LINE */
2574         rxvt_scr_gotorc(aR_ arg[0], 0, R_RELATIVE);
2575         break;
2576
2577     case CSI_CHA:               /* 8.3.9: (1) CURSOR CHARACTER ABSOLUTE */
2578     case CSI_HPA:               /* 8.3.58: (1) CURSOR POSITION ABSOLUTE */
2579         rxvt_scr_gotorc(aR_ 0, arg[0] - 1, R_RELATIVE);
2580         break;
2581
2582     case CSI_VPA:               /* 8.3.159: (1) LINE POSITION ABSOLUTE */
2583         rxvt_scr_gotorc(aR_ arg[0] - 1, 0, C_RELATIVE);
2584         break;
2585
2586     case CSI_CUP:               /* 8.3.21: (1,1) CURSOR POSITION */
2587     case CSI_HVP:               /* 8.3.64: (1,1) CHARACTER AND LINE POSITION */
2588         rxvt_scr_gotorc(aR_ arg[0] - 1, nargs < 2 ? 0 : (arg[1] - 1), 0);
2589         break;
2590
2591     case CSI_CBT:               /* 8.3.7: (1) CURSOR BACKWARD TABULATION */
2592         arg[0] = -arg[0];
2593     /* FALLTHROUGH */
2594     case CSI_CHT:               /* 8.3.10: (1) CURSOR FORWARD TABULATION */
2595         rxvt_scr_tab(aR_ arg[0]);
2596         break;
2597
2598     case CSI_ED:                /* 8.3.40: (0) ERASE IN PAGE */
2599         rxvt_scr_erase_screen(aR_ arg[0]);
2600         break;
2601
2602     case CSI_EL:                /* 8.3.42: (0) ERASE IN LINE */
2603         rxvt_scr_erase_line(aR_ arg[0]);
2604         break;
2605
2606     case CSI_ICH:               /* 8.3.65: (1) INSERT CHARACTER */
2607         rxvt_scr_insdel_chars(aR_ arg[0], INSERT);
2608         break;
2609
2610     case CSI_IL:                /* 8.3.68: (1) INSERT LINE */
2611         rxvt_scr_insdel_lines(aR_ arg[0], INSERT);
2612         break;
2613
2614     case CSI_DL:                /* 8.3.33: (1) DELETE LINE */
2615         rxvt_scr_insdel_lines(aR_ arg[0], DELETE);
2616         break;
2617
2618     case CSI_ECH:               /* 8.3.39: (1) ERASE CHARACTER */
2619         rxvt_scr_insdel_chars(aR_ arg[0], ERASE);
2620         break;
2621
2622     case CSI_DCH:               /* 8.3.26: (1) DELETE CHARACTER */
2623         rxvt_scr_insdel_chars(aR_ arg[0], DELETE);
2624         break;
2625
2626     case CSI_SD:                /* 8.3.114: (1) SCROLL DOWN */
2627         arg[0] = -arg[0];
2628     /* FALLTHROUGH */
2629     case CSI_SU:                /* 8.3.148: (1) SCROLL UP */
2630         rxvt_scroll_text(aR_ R->screen.tscroll, R->screen.bscroll, arg[0], 0);
2631         break;
2632
2633     case CSI_DA:                /* 8.3.24: (0) DEVICE ATTRIBUTES */
2634         R->tt_write((const unsigned char *)VT100_ANS,
2635                       (unsigned int)(sizeof(VT100_ANS) - 1));
2636         break;
2637
2638     case CSI_SGR:               /* 8.3.118: (0) SELECT GRAPHIC RENDITION */
2639         rxvt_process_sgr_mode(aR_ nargs, arg);
2640         break;
2641
2642     case CSI_DSR:               /* 8.3.36: (0) DEVICE STATUS REPORT */
2643         switch (arg[0]) {
2644         case 5:                 /* DSR requested */
2645             R->tt_printf("\033[0n");
2646             break;
2647         case 6:                 /* CPR requested */
2648             rxvt_scr_report_position(aR);
2649             break;
2650 #if defined (ENABLE_DISPLAY_ANSWER)
2651         case 7:                 /* unofficial extension */
2652             R->tt_printf("%-.250s\n", R->rs[Rs_display_name]);
2653             break;
2654 #endif
2655         case 8:                 /* unofficial extension */
2656             rxvt_xterm_seq(aR_ XTerm_title, APL_NAME "-" VERSION, CHAR_ST);
2657             break;
2658         }
2659         break;
2660
2661     case CSI_TBC:               /* 8.3.155: (0) TABULATION CLEAR */
2662         switch (arg[0]) {
2663         case 0:                 /* char tab stop cleared at active position */
2664             rxvt_scr_set_tab(aR_ 0);
2665             break;
2666         /* case 1: */           /* line tab stop cleared in active line */
2667         /* case 2: */           /* char tab stops cleared in active line */
2668         case 3:                 /* all char tab stops are cleared */
2669         /* case 4: */           /* all line tab stops are cleared */
2670         case 5:                 /* all tab stops are cleared */
2671             rxvt_scr_set_tab(aR_ -1);
2672             break;
2673         }
2674         break;
2675
2676     case CSI_CTC:               /* 8.3.17: (0) CURSOR TABULATION CONTROL */
2677         switch (arg[0]) {
2678         case 0:                 /* char tab stop set at active position */
2679             rxvt_scr_set_tab(aR_ 1);
2680             break;              /* = ESC H */
2681         /* case 1: */           /* line tab stop set at active line */
2682         case 2:                 /* char tab stop cleared at active position */
2683             rxvt_scr_set_tab(aR_ 0);
2684             break;              /* = ESC [ 0 g */
2685         /* case 3: */           /* line tab stop cleared at active line */
2686         /* case 4: */           /* char tab stops cleared at active line */
2687         case 5:                 /* all char tab stops are cleared */
2688             rxvt_scr_set_tab(aR_ -1);
2689             break;              /* = ESC [ 3 g */
2690         /* case 6: */           /* all line tab stops are cleared */
2691         }
2692         break;
2693
2694     case CSI_RM:                /* 8.3.107: RESET MODE */
2695         if (arg[0] == 4)
2696             rxvt_scr_insert_mode(aR_ 0);
2697         break;
2698
2699     case CSI_SM:                /* 8.3.126: SET MODE */
2700         if (arg[0] == 4)
2701             rxvt_scr_insert_mode(aR_ 1);
2702         break;
2703
2704 /*
2705  * PRIVATE USE beyond this point.  All CSI_7? sequences here
2706  */ 
2707     case CSI_72:                /* DECSTBM: set top and bottom margins */
2708         if (nargs == 1)
2709             rxvt_scr_scroll_region(aR_ arg[0] - 1, MAX_ROWS - 1);
2710         else if (nargs == 0 || arg[0] >= arg[1])
2711             rxvt_scr_scroll_region(aR_ 0, MAX_ROWS - 1);
2712         else 
2713             rxvt_scr_scroll_region(aR_ arg[0] - 1, arg[1] - 1);
2714         break;
2715
2716     case CSI_73:
2717         rxvt_scr_cursor(aR_ SAVE);
2718         break;
2719     case CSI_75:
2720         rxvt_scr_cursor(aR_ RESTORE);
2721         break;
2722
2723 #ifndef NO_FRILLS
2724     case CSI_74:
2725         rxvt_process_window_ops(aR_ arg, nargs);
2726         break;
2727 #endif
2728
2729     case CSI_78:                /* DECREQTPARM */
2730         if (arg[0] == 0 || arg[0] == 1)
2731             R->tt_printf("\033[%d;1;1;112;112;1;0x", arg[0] + 2);
2732     /* FALLTHROUGH */
2733
2734     default:
2735         break;
2736     }
2737 }
2738 /*}}} */
2739
2740 #ifndef NO_FRILLS
2741 /* ARGSUSED */
2742 /* INTPROTO */
2743 void
2744 rxvt_process_window_ops(pR_ const int *args, unsigned int nargs)
2745 {
2746     int             x, y;
2747 #if 0
2748     char           *s;
2749 #endif
2750     XWindowAttributes wattr;
2751     Window          wdummy;
2752
2753     if (nargs == 0)
2754         return;
2755     switch (args[0]) {
2756     /*
2757      * commands
2758      */
2759     case 1:                     /* deiconify window */
2760         XMapWindow(R->Xdisplay, R->TermWin.parent[0]);
2761         break;
2762     case 2:                     /* iconify window */
2763         XIconifyWindow(R->Xdisplay, R->TermWin.parent[0],
2764                        DefaultScreen(R->Xdisplay));
2765         break;
2766     case 3:                     /* set position (pixels) */
2767         XMoveWindow(R->Xdisplay, R->TermWin.parent[0], args[1], args[2]);
2768         break;
2769     case 4:                     /* set size (pixels) */
2770         rxvt_set_widthheight(aR_ (unsigned int)args[2], (unsigned int)args[1]);
2771         break;
2772     case 5:                     /* raise window */
2773         XRaiseWindow(R->Xdisplay, R->TermWin.parent[0]);
2774         break;
2775     case 6:                     /* lower window */
2776         XLowerWindow(R->Xdisplay, R->TermWin.parent[0]);
2777         break;
2778     case 7:                     /* refresh window */
2779         rxvt_scr_touch(aR_ True);
2780         break;
2781     case 8:                     /* set size (chars) */
2782         rxvt_set_widthheight(aR_ (unsigned int)(args[2] * R->TermWin.fwidth),
2783                              (unsigned int)(args[1] * R->TermWin.fheight));
2784         break;
2785     default:
2786         if (args[0] >= 24)      /* set height (chars) */
2787             rxvt_set_widthheight(aR_ (unsigned int)R->TermWin.width,
2788                                  (unsigned int)(args[1] * R->TermWin.fheight));
2789         break;
2790     /*
2791      * reports - some output format copied from XTerm
2792      */
2793     case 11:                    /* report window state */
2794         XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[0], &wattr);
2795         R->tt_printf("\033[%dt", wattr.map_state == IsViewable ? 1 : 2);
2796         break;
2797     case 13:                    /* report window position */
2798         XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[0], &wattr);
2799         XTranslateCoordinates(R->Xdisplay, R->TermWin.parent[0], wattr.root,
2800                               -wattr.border_width, -wattr.border_width,
2801                               &x, &y, &wdummy);
2802         R->tt_printf("\033[3;%d;%dt", x, y);
2803         break;
2804     case 14:                    /* report window size (pixels) */
2805         XGetWindowAttributes(R->Xdisplay, R->TermWin.parent[0], &wattr);
2806         R->tt_printf("\033[4;%d;%dt", wattr.height, wattr.width);
2807         break;
2808     case 18:                    /* report window size (chars) */
2809         R->tt_printf("\033[8;%d;%dt", R->TermWin.nrow, R->TermWin.ncol);
2810         break;
2811 #if 0 /* XXX: currently disabled due to security concerns */
2812     case 20:                    /* report icon label */
2813         XGetIconName(R->Xdisplay, R->TermWin.parent[0], &s);
2814         R->tt_printf("\033]L%-.200s\234", s ? s : "");  /* 8bit ST */
2815         break;
2816     case 21:                    /* report window title */
2817         XFetchName(R->Xdisplay, R->TermWin.parent[0], &s);
2818         R->tt_printf("\033]l%-.200s\234", s ? s : "");  /* 8bit ST */
2819         break;
2820 #endif
2821     }
2822 }
2823 #endif
2824
2825 /*----------------------------------------------------------------------*/
2826 /*
2827  * get input up until STRING TERMINATOR (or BEL)
2828  * ends_how is terminator used.  returned input must be free()d
2829  */
2830 /* INTPROTO */
2831 unsigned char  *
2832 rxvt_get_to_st(pR_ unsigned char *ends_how)
2833 {
2834     int             seen_esc = 0;       /* seen escape? */
2835     unsigned int    n = 0;
2836     unsigned char  *s;
2837     unsigned char   ch, string[STRING_MAX];
2838
2839     for (; (ch = rxvt_cmd_getc(aR));) {
2840         if (ch == C0_BEL
2841             || ch == CHAR_ST
2842             || (ch == 0x5c && seen_esc))        /* 7bit ST */
2843             break;
2844         if (ch == C0_ESC) {
2845             seen_esc = 1;
2846             continue;
2847         } else if (ch == '\t')
2848             ch = ' ';   /* translate '\t' to space */
2849         else if (ch < 0x08 || (ch > 0x0d && ch < 0x20))
2850             return NULL;        /* other control character - exit */
2851         if (n < sizeof(string) - 1)
2852             string[n++] = ch;
2853         seen_esc = 0;
2854     }
2855     string[n++] = '\0';
2856     if ((s = (unsigned char *)rxvt_malloc(n)) == NULL)
2857         return NULL;
2858     *ends_how = (ch == 0x5c ? C0_ESC : ch);
2859     STRNCPY(s, string, n);
2860     return s;
2861 }
2862
2863 /*----------------------------------------------------------------------*/
2864 /*
2865  * process DEVICE CONTROL STRING `ESC P ... (ST|BEL)' or `0x90 ... (ST|BEL)'
2866  */
2867 /* INTPROTO */
2868 void
2869 rxvt_process_dcs_seq(pR)
2870 {
2871     unsigned char    eh, *s;
2872 /*
2873  * Not handled yet
2874  */
2875     s = rxvt_get_to_st(aR_ &eh);
2876     if (s)
2877         free(s);
2878     return;
2879 }
2880
2881 /*----------------------------------------------------------------------*/
2882 /*
2883  * process OPERATING SYSTEM COMMAND sequence `ESC ] Ps ; Pt (ST|BEL)'
2884  */
2885 /* INTPROTO */
2886 void
2887 rxvt_process_osc_seq(pR)
2888 {
2889     unsigned char   ch, eh, *s;
2890     int             arg;
2891
2892     ch = rxvt_cmd_getc(aR);
2893     for (arg = 0; isdigit(ch); ch = rxvt_cmd_getc(aR))
2894         arg = arg * 10 + (ch - '0');
2895
2896     if (ch == ';') {
2897         s = rxvt_get_to_st(aR_ &eh);
2898         if (s) {
2899     /*
2900      * rxvt_menubar_dispatch() violates the constness of the string,
2901      * so do it here
2902      */
2903             if (arg == XTerm_Menu)
2904 #if 0 /* XXX: currently disabled due to security concerns */
2905                 rxvt_menubar_dispatch(aR_ (char *)s);
2906 #else
2907                 0;
2908 #endif
2909             else
2910                 rxvt_xterm_seq(aR_ arg, (char *)s, eh);
2911             free(s);
2912         }
2913     }
2914 }
2915 /*
2916  * XTerm escape sequences: ESC ] Ps;Pt (ST|BEL)
2917  *       0 = change iconName/title
2918  *       1 = change iconName
2919  *       2 = change title
2920  *       4 = change color
2921  *      12 = change text color
2922  *      13 = change mouse foreground color 
2923  *      17 = change highlight character colour
2924  *      18 = change bold character color
2925  *      19 = change underlined character color 
2926  *      46 = change logfile (not implemented)
2927  *      50 = change font
2928  *
2929  * rxvt extensions:
2930  *      10 = menu (may change in future)
2931  *      20 = bg pixmap
2932  *      39 = change default fg color
2933  *      49 = change default bg color
2934  *      55 = dump scrollback buffer and all of screen
2935  */
2936 /* EXTPROTO */
2937 void
2938 rxvt_xterm_seq(pR_ int op, const char *str, unsigned char resp __attribute__((unused)))
2939 {
2940     int             changed = 0;
2941     int             color;
2942     char           *buf, *name;
2943
2944     assert(str != NULL);
2945     switch (op) {
2946     case XTerm_name:
2947         rxvt_set_title(aR_ str);
2948     /* FALLTHROUGH */
2949     case XTerm_iconName:
2950         rxvt_set_iconName(aR_ str);
2951         break;
2952     case XTerm_title:
2953         rxvt_set_title(aR_ str);
2954         break;
2955     case XTerm_Color:
2956         for (buf = (char *)str; buf && *buf;) {
2957             if ((name = STRCHR(buf, ';')) == NULL)
2958                 break;
2959             *name++ = '\0';
2960             color = atoi(buf);
2961             if (color < 0 || color >= TOTAL_COLORS)
2962                 break;
2963             if ((buf = STRCHR(name, ';')) != NULL)
2964                 *buf++ = '\0';
2965             rxvt_set_window_color(aR_ color + minCOLOR, name);
2966         }
2967         break;
2968 #ifndef NO_CURSORCOLOR
2969     case XTerm_Color_cursor:
2970         rxvt_set_window_color(aR_ Color_cursor, str);
2971         break;
2972 #endif
2973     case XTerm_Color_pointer:
2974         rxvt_set_window_color(aR_ Color_pointer, str);
2975         break;
2976 #ifndef NO_BOLD_UNDERLINE_REVERSE
2977     case XTerm_Color_BD:
2978         rxvt_set_window_color(aR_ Color_BD, str);
2979         break;
2980     case XTerm_Color_UL:
2981         rxvt_set_window_color(aR_ Color_UL, str);
2982         break;
2983     case XTerm_Color_RV:
2984         rxvt_set_window_color(aR_ Color_RV, str);
2985         break;
2986 #endif
2987
2988     case XTerm_Menu:
2989         /*
2990          * rxvt_menubar_dispatch() violates the constness of the string,
2991          * so DON'T do it here
2992          */
2993         break;
2994     case XTerm_Pixmap:
2995         if (*str != ';') {
2996 #if XPM_BACKGROUND
2997             rxvt_scale_pixmap(aR_ "");  /* reset to default scaling */
2998             rxvt_set_bgPixmap(aR_ str); /* change pixmap */
2999 #endif
3000             rxvt_scr_touch(aR_ True);
3001         }
3002         while ((str = STRCHR(str, ';')) != NULL) {
3003             str++;
3004 #if XPM_BACKGROUND
3005             changed += rxvt_scale_pixmap(aR_ str);
3006 #endif
3007         }
3008         if (changed) {
3009 #ifdef XPM_BACKGROUND
3010             rxvt_resize_pixmap(aR);
3011 #endif
3012             rxvt_scr_touch(aR_ True);
3013         }
3014         break;
3015
3016     case XTerm_restoreFG:
3017         rxvt_set_window_color(aR_ Color_fg, str);
3018         break;
3019     case XTerm_restoreBG:
3020         rxvt_set_window_color(aR_ Color_bg, str);
3021         break;
3022     case XTerm_logfile:
3023         break;
3024     case XTerm_font:
3025         rxvt_change_font(aR_ 0, str);
3026         break;
3027 #if 0
3028     case XTerm_dumpscreen:      /* no error notices */
3029         {
3030             int             fd;
3031             if ((fd = open(str, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0) {
3032                 rxvt_scr_dump(aR_ fd);
3033                 close(fd);
3034             }
3035         }
3036         break;
3037 #endif
3038     }
3039 }
3040 /*----------------------------------------------------------------------*/
3041
3042 /*{{{ process DEC private mode sequences `ESC [ ? Ps mode' */
3043 /*
3044  * mode can only have the following values:
3045  *      'l' = low
3046  *      'h' = high
3047  *      's' = save
3048  *      'r' = restore
3049  *      't' = toggle
3050  * so no need for fancy checking
3051  */
3052 /* INTPROTO */
3053 int
3054 rxvt_privcases(pR_ int mode, unsigned long bit)
3055 {
3056     int             state;
3057
3058     if (mode == 's') {
3059         R->SavedModes |= (R->PrivateModes & bit);
3060         return -1;
3061     } else {
3062         if (mode == 'r')
3063             state = (R->SavedModes & bit) ? 1 : 0;      /* no overlapping */
3064         else
3065             state = (mode == 't') ? !(R->PrivateModes & bit) : mode;
3066         PrivMode(state, bit);
3067     }
3068     return state;
3069 }
3070
3071 /* we're not using priv _yet_ */
3072 /* INTPROTO */
3073 void
3074 rxvt_process_terminal_mode(pR_ int mode, int priv __attribute__((unused)), unsigned int nargs, const int *arg)
3075 {
3076     unsigned int    i, j;
3077     int             state;
3078     static const struct {
3079         const int       argval;
3080         const unsigned long bit;
3081     } argtopriv[] = {
3082         { 1, PrivMode_aplCUR },
3083         { 2, PrivMode_vt52 },
3084         { 3, PrivMode_132 },
3085         { 4, PrivMode_smoothScroll },
3086         { 5, PrivMode_rVideo },
3087         { 6, PrivMode_relOrigin },
3088         { 7, PrivMode_Autowrap },
3089         { 9, PrivMode_MouseX10 },
3090 #ifdef menuBar_esc
3091         { menuBar_esc, PrivMode_menuBar },
3092 #endif
3093 #ifdef scrollBar_esc
3094         { scrollBar_esc, PrivMode_scrollBar },
3095 #endif
3096         { 25, PrivMode_VisibleCursor },
3097         { 35, PrivMode_ShiftKeys },
3098         { 40, PrivMode_132OK },
3099         { 47, PrivMode_Screen },
3100         { 66, PrivMode_aplKP },
3101 #ifndef NO_BACKSPACE_KEY
3102         { 67, PrivMode_BackSpace },
3103 #endif
3104         { 1000, PrivMode_MouseX11 },
3105         { 1010, PrivMode_TtyOutputInh },
3106         { 1011, PrivMode_Keypress },
3107         { 1047, PrivMode_Screen },
3108     };
3109
3110     if (nargs == 0)
3111         return;
3112
3113 /* make lo/hi boolean */
3114     if (mode == 'l')
3115         mode = 0;               /* reset */
3116     else if (mode == 'h')
3117         mode = 1;               /* set */
3118
3119     for (i = 0; i < nargs; i++) {
3120         state = -1;
3121
3122         /* basic handling */
3123         for (j = 0; j < (sizeof(argtopriv)/sizeof(argtopriv[0])); j++)
3124             if (argtopriv[j].argval == arg[i]) {
3125                 state = rxvt_privcases(aR_ mode, argtopriv[j].bit);
3126                 break;
3127             }
3128         
3129         /* extra handling for values with state unkept  */
3130         if (state == -1)
3131             switch (arg[i]) {
3132             case 1048:          /* alternative cursor save */
3133                 if (mode == 0)
3134                     rxvt_scr_cursor(aR_ RESTORE);
3135                 else if (mode == 1)
3136                     rxvt_scr_cursor(aR_ SAVE);
3137             /* FALLTHROUGH */
3138             default:
3139                 continue;       /* for(;i;) */
3140             }
3141
3142         /* extra handling for values with valid 0 or 1 state */
3143         switch (arg[i]) {
3144         /* case 1:      - application cursor keys */
3145         case 2:                 /* VT52 mode */
3146               /* oddball mode.  should be set regardless of set/reset
3147                * parameter.  Return from VT52 mode with an ESC < from
3148                * within VT52 mode
3149                */
3150             PrivMode(1, PrivMode_vt52);
3151             break;
3152         case 3:                 /* 80/132 */
3153             if (R->PrivateModes & PrivMode_132OK)
3154                 rxvt_set_widthheight(aR_
3155                     (unsigned int)((state ? 132 : 80) * R->TermWin.fwidth),
3156                     (unsigned int)R->TermWin.height);
3157             break;
3158         case 4:                 /* smooth scrolling */
3159             if (state)
3160                 R->Options &= ~Opt_jumpScroll;
3161             else
3162                 R->Options |= Opt_jumpScroll;
3163             break;
3164         case 5:                 /* reverse video */
3165             rxvt_scr_rvideo_mode(aR_ state);
3166             break;
3167         case 6:                 /* relative/absolute origins  */
3168             rxvt_scr_relative_origin(aR_ state);
3169             break;
3170         case 7:                 /* autowrap */
3171             rxvt_scr_autowrap(aR_ state);
3172             break;
3173         /* case 8:      - auto repeat, can't do on a per window basis */
3174         case 9:                 /* X10 mouse reporting */
3175             if (state)          /* orthogonal */
3176                 R->PrivateModes &= ~(PrivMode_MouseX11);
3177             break;
3178 #ifdef menuBar_esc
3179         case menuBar_esc:
3180 #ifdef MENUBAR
3181             rxvt_map_menuBar(aR_ state);
3182 #endif
3183             break;
3184 #endif
3185 #ifdef scrollBar_esc
3186         case scrollBar_esc:
3187             if (rxvt_scrollbar_mapping(aR_ state)) {
3188                 rxvt_resize_all_windows(aR_ 0, 0, 0);
3189                 rxvt_scr_touch(aR_ True);
3190             }
3191             break;
3192 #endif
3193         case 25:                /* visible/invisible cursor */
3194             rxvt_scr_cursor_visible(aR_ state);
3195             break;
3196         /* case 35:     - shift keys */
3197         /* case 40:     - 80 <--> 132 mode */
3198         case 47:                /* secondary screen */
3199             rxvt_scr_change_screen(aR_ state);
3200             break;
3201         /* case 66:     - application key pad */
3202         /* case 67:     - backspace key */
3203         case 1000:              /* X11 mouse reporting */
3204             if (state)          /* orthogonal */
3205                 R->PrivateModes &= ~(PrivMode_MouseX10);
3206             break;
3207 #if 0
3208         case 1001:
3209             break;              /* X11 mouse highlighting */
3210 #endif
3211         case 1010:              /* scroll to bottom on TTY output inhibit */
3212             if (state)
3213                 R->Options &= ~Opt_scrollTtyOutput;
3214             else
3215                 R->Options |= Opt_scrollTtyOutput;
3216             break;
3217         case 1011:              /* scroll to bottom on key press */
3218             if (state)
3219                 R->Options |= Opt_scrollTtyKeypress;
3220             else
3221                 R->Options &= ~Opt_scrollTtyKeypress;
3222             break;
3223         case 1047:              /* secondary screen w/ clearing */
3224             if (R->current_screen != PRIMARY)
3225                 rxvt_scr_erase_screen(aR_ 2);
3226             rxvt_scr_change_screen(aR_ state);
3227         /* FALLTHROUGH */
3228         default:
3229             break;
3230         }
3231     }
3232 }
3233 /*}}} */
3234
3235 /*{{{ process sgr sequences */
3236 /* INTPROTO */
3237 void
3238 rxvt_process_sgr_mode(pR_ unsigned int nargs, const int *arg)
3239 {
3240     unsigned int    i;
3241     short           rendset;
3242     int             rendstyle;
3243
3244     if (nargs == 0) {
3245         rxvt_scr_rendition(aR_ 0, ~RS_None);
3246         return;
3247     }
3248     for (i = 0; i < nargs; i++) {
3249         rendset = -1;
3250         switch (arg[i]) {
3251         case 0:
3252             rendset = 0, rendstyle = ~RS_None;
3253             break;
3254         case 1:
3255             rendset = 1, rendstyle = RS_Bold;
3256             break;
3257         case 4:
3258             rendset = 1, rendstyle = RS_Uline;
3259             break;
3260         case 5:
3261             rendset = 1, rendstyle = RS_Blink;
3262             break;
3263         case 7:
3264             rendset = 1, rendstyle = RS_RVid;
3265             break;
3266         case 22:
3267             rendset = 0, rendstyle = RS_Bold;
3268             break;
3269         case 24:
3270             rendset = 0, rendstyle = RS_Uline;
3271             break;
3272         case 25:
3273             rendset = 0, rendstyle = RS_Blink;
3274             break;
3275         case 27:
3276             rendset = 0, rendstyle = RS_RVid;
3277             break;
3278         }
3279         if (rendset != -1) {
3280             rxvt_scr_rendition(aR_ rendset, rendstyle);
3281             continue;           /* for(;i;) */
3282         }
3283
3284         switch (arg[i]) {
3285         case 30:
3286         case 31:                /* set fg color */
3287         case 32:
3288         case 33:
3289         case 34:
3290         case 35:
3291         case 36:
3292         case 37:
3293             rxvt_scr_color(aR_ (unsigned int)(minCOLOR + (arg[i] - 30)),
3294                            Color_fg);
3295             break;
3296 #ifdef TTY_256COLOR
3297         case 38:
3298             if (nargs > i + 2 && arg[i + 1] == 5) {
3299                 rxvt_scr_color(aR_ (unsigned int)(minCOLOR + arg[i + 2]),
3300                                Color_fg);
3301                 i += 2;
3302             }
3303             break;
3304 #endif
3305         case 39:                /* default fg */
3306             rxvt_scr_color(aR_ Color_fg, Color_fg);
3307             break;
3308
3309         case 40:
3310         case 41:                /* set bg color */
3311         case 42:
3312         case 43:
3313         case 44:
3314         case 45:
3315         case 46:
3316         case 47:
3317             rxvt_scr_color(aR_ (unsigned int)(minCOLOR + (arg[i] - 40)),
3318                            Color_bg);
3319             break;
3320 #ifdef TTY_256COLOR
3321         case 48:
3322             if (nargs > i + 2 && arg[i + 1] == 5) {
3323                 rxvt_scr_color(aR_ (unsigned int)(minCOLOR + arg[i + 2]),
3324                                Color_bg);
3325                 i += 2;
3326             }
3327             break;
3328 #endif
3329         case 49:                /* default bg */
3330             rxvt_scr_color(aR_ Color_bg, Color_bg);
3331             break;
3332
3333 #ifndef NO_BRIGHTCOLOR
3334         case 90:
3335         case 91:                /* set bright fg color */
3336         case 92:
3337         case 93:
3338         case 94:
3339         case 95:
3340         case 96:
3341         case 97:
3342             rxvt_scr_color(aR_ (unsigned int)(minBrightCOLOR + (arg[i] - 90)),
3343                            Color_fg);
3344             break;
3345         case 100:
3346         case 101:               /* set bright bg color */
3347         case 102:
3348         case 103:
3349         case 104:
3350         case 105:
3351         case 106:
3352         case 107:
3353             rxvt_scr_color(aR_ (unsigned int)(minBrightCOLOR + (arg[i] - 100)),
3354                            Color_bg);
3355             break;
3356 #endif
3357         }
3358     }
3359 }
3360 /*}}} */
3361
3362 /*{{{ process Rob Nation's own graphics mode sequences */
3363 /* INTPROTO */
3364 void
3365 rxvt_process_graphics(pR)
3366 {
3367     unsigned char   ch, cmd = rxvt_cmd_getc(aR);
3368
3369 #ifndef RXVT_GRAPHICS
3370     if (cmd == 'Q') {           /* query graphics */
3371         R->tt_printf("\033G0\n");       /* no graphics */
3372         return;
3373     }
3374 /* swallow other graphics sequences until terminating ':' */
3375     do
3376         ch = rxvt_cmd_getc(aR);
3377     while (ch != ':');
3378 #else
3379     unsigned int    nargs;
3380     int             args[NGRX_PTS];
3381     unsigned char  *text = NULL;
3382
3383     if (cmd == 'Q') {           /* query graphics */
3384         R->tt_printf("\033G1\n");       /* yes, graphics (color) */
3385         return;
3386     }
3387     for (nargs = 0; nargs < (sizeof(args) / sizeof(args[0])) - 1;) {
3388         int             neg;
3389
3390         ch = rxvt_cmd_getc(aR);
3391         neg = (ch == '-');
3392         if (neg || ch == '+')
3393             ch = rxvt_cmd_getc(aR);
3394
3395         for (args[nargs] = 0; isdigit(ch); ch = rxvt_cmd_getc(aR))
3396             args[nargs] = args[nargs] * 10 + (ch - '0');
3397         if (neg)
3398             args[nargs] = -args[nargs];
3399
3400         nargs++;
3401         args[nargs] = 0;
3402         if (ch != ';')
3403             break;
3404     }
3405
3406     if ((cmd == 'T') && (nargs >= 5)) {
3407         int             i, len = args[4];
3408
3409         text = rxvt_malloc((len + 1) * sizeof(char));
3410
3411         if (text != NULL) {
3412             for (i = 0; i < len; i++)
3413                 text[i] = rxvt_cmd_getc(aR);
3414             text[len] = '\0';
3415         }
3416     }
3417     rxvt_Gr_do_graphics(aR_ cmd, nargs, args, text);
3418 #endif
3419 }
3420 /*}}} */
3421
3422 /* ------------------------------------------------------------------------- */
3423
3424 /*
3425  * Send printf() formatted output to the command.
3426  * Only use for small amounts of data.
3427  */
3428 void
3429 rxvt_term::tt_printf (const char *fmt,...)
3430 {
3431   va_list arg_ptr;
3432   unsigned char buf[256];
3433
3434   va_start (arg_ptr, fmt);
3435   vsnprintf ((char *)buf, 256, fmt, arg_ptr);
3436   va_end (arg_ptr);
3437   tt_write (buf, STRLEN (buf));
3438 }
3439
3440 /* ---------------------------------------------------------------------- */
3441 /* Write data to the pty as typed by the user, pasted with the mouse,
3442  * or generated by us in response to a query ESC sequence.
3443  */
3444 void
3445 rxvt_term::tt_write (const unsigned char *data, unsigned int len)
3446 {
3447   enum { MAX_PTY_WRITE = 255 }; // minimum MAX_INPUT
3448
3449   if (len)
3450     {
3451       if (v_buflen == 0)
3452         {
3453           int written = write (cmd_fd, data, min (MAX_PTY_WRITE, len));
3454           if (written == len)
3455             return;
3456
3457           data += written;
3458           len -= written;
3459         }
3460
3461
3462       v_buffer = (unsigned char *)realloc (v_buffer, v_buflen + len);
3463
3464       memcpy (v_buffer + v_buflen, data, len);
3465       v_buflen += len;
3466     }
3467
3468   for (;;)
3469     {
3470       int written = write (cmd_fd, v_buffer, min (MAX_PTY_WRITE, v_buflen));
3471
3472       if (written > 0)
3473         {
3474           v_buflen -= written;
3475
3476           if (v_buflen == 0)
3477             {
3478               free (v_buffer);
3479               v_buffer = 0;
3480               v_buflen = 0;
3481
3482               pty_ev.set (EVENT_READ);
3483               return;
3484             }
3485
3486           memmove (v_buffer, v_buffer + written, v_buflen);
3487         }
3488       else if (written != -1 || (errno != EAGAIN && errno != EINTR))
3489         // original code just ignores this...
3490         destroy ();
3491       else
3492         {
3493           pty_ev.set (EVENT_READ | EVENT_WRITE);
3494           return;
3495         }
3496     }
3497 }
3498
3499 /*----------------------- end-of-file (C source) -----------------------*/
3500