ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.26
Committed: Wed Dec 24 06:26:52 2003 UTC (20 years, 4 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1-3, rel-1-2
Changes since 1.25: +3 -3 lines
Log Message:
*** empty log message ***

File Contents

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