ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.29
Committed: Mon Jan 19 17:26:43 2004 UTC (20 years, 3 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.28: +2 -4 lines
Log Message:
*** empty log message ***

File Contents

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