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