ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.38
Committed: Mon Feb 9 07:11:49 2004 UTC (20 years, 3 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.37: +249 -256 lines
Log Message:
*** empty log message ***

File Contents

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