ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.27
Committed: Tue Dec 30 01:35:58 2003 UTC (20 years, 4 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.26: +3 -1 lines
Log Message:
*** empty log message ***

File Contents

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