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