ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.39
Committed: Mon Feb 9 07:15:46 2004 UTC (20 years, 3 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.38: +2 -0 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 pcg 1.39 #ifdef TRANSPARENT
1554 pcg 1.1 void
1555 pcg 1.38 rxvt_term::rootwin_cb (XEvent &ev)
1556     {
1557     SET_R (this);
1558     SET_LOCALE (locale);
1559    
1560     if (ev.type == PropertyNotify)
1561     {
1562     /*
1563     * if user used some Esetroot compatible prog to set the root bg,
1564     * use the property to determine the pixmap. We use it later on.
1565     */
1566     if (xa[XA_XROOTPMAPID] == 0)
1567     xa[XA_XROOTPMAPID] = XInternAtom(display->display, "_XROOTPMAP_ID", False);
1568    
1569     if (ev.xproperty.atom != xa[XA_XROOTPMAPID])
1570     return;
1571     }
1572    
1573     if ((Options & Opt_transparent) && check_our_parents ())
1574     {
1575     if (am_transparent)
1576     want_full_refresh = 1;
1577     }
1578     }
1579 pcg 1.39 #endif
1580 pcg 1.38
1581     void
1582     rxvt_term::button_press (const XButtonEvent &ev)
1583 pcg 1.1 {
1584 pcg 1.36 int reportmode = 0, clickintime;
1585 pcg 1.1
1586 pcg 1.38 bypass_keystate = ev.state & (ModMetaMask | ShiftMask);
1587 pcg 1.36 if (!bypass_keystate)
1588     reportmode = !!(PrivateModes & PrivMode_mouse_report);
1589     /*
1590     * VT window processing of button press
1591     */
1592 pcg 1.38 if (ev.window == TermWin.vt)
1593 pcg 1.36 {
1594 pcg 1.1 #if RXVT_GRAPHICS
1595 pcg 1.38 if (ev.subwindow != None)
1596     rxvt_Gr_ButtonPress (ev.x, ev.y);
1597 pcg 1.36 else
1598 pcg 1.1 #endif
1599 pcg 1.36
1600     {
1601 pcg 1.38 clickintime = ev.time - MEvent.time < MULTICLICK_TIME;
1602 pcg 1.36 if (reportmode)
1603     {
1604     /* mouse report from vt window */
1605     /* save the xbutton state (for ButtonRelease) */
1606 pcg 1.38 MEvent.state = ev.state;
1607 pcg 1.1 #ifdef MOUSE_REPORT_DOUBLECLICK
1608 pcg 1.38 if (ev.button == MEvent.button && clickintime)
1609 pcg 1.36 {
1610     /* same button, within alloted time */
1611     MEvent.clicks++;
1612     if (MEvent.clicks > 1)
1613     {
1614     /* only report double clicks */
1615     MEvent.clicks = 2;
1616     mouse_report (ev);
1617    
1618     /* don't report the release */
1619     MEvent.clicks = 0;
1620     MEvent.button = AnyButton;
1621     }
1622     }
1623     else
1624     {
1625     /* different button, or time expired */
1626     MEvent.clicks = 1;
1627 pcg 1.38 MEvent.button = ev.button;
1628 pcg 1.36 mouse_report (ev);
1629     }
1630 pcg 1.1 #else
1631 pcg 1.38 MEvent.button = ev.button;
1632 pcg 1.36 mouse_report (ev);
1633 pcg 1.1 #endif /* MOUSE_REPORT_DOUBLECLICK */
1634 pcg 1.36
1635     }
1636     else
1637     {
1638 pcg 1.38 if (ev.button != MEvent.button)
1639 pcg 1.36 MEvent.clicks = 0;
1640 pcg 1.38 switch (ev.button)
1641 pcg 1.36 {
1642     case Button1:
1643     /* allow shift+left click to extend selection */
1644 pcg 1.38 if (ev.state & ShiftMask && !(PrivateModes & PrivMode_mouse_report))
1645 pcg 1.36 {
1646     if (MEvent.button == Button1 && clickintime)
1647 pcg 1.38 selection_rotate (ev.x, ev.y);
1648 pcg 1.36 else
1649 pcg 1.38 selection_extend (ev.x, ev.y, 1);
1650 pcg 1.36 }
1651     else
1652     {
1653     if (MEvent.button == Button1 && clickintime)
1654     MEvent.clicks++;
1655 pcg 1.1 else
1656 pcg 1.36 MEvent.clicks = 1;
1657 pcg 1.21
1658 pcg 1.38 selection_click (MEvent.clicks, ev.x, ev.y);
1659 pcg 1.36 }
1660 pcg 1.21
1661 pcg 1.36 MEvent.button = Button1;
1662     break;
1663 pcg 1.1
1664 pcg 1.36 case Button3:
1665     if (MEvent.button == Button3 && clickintime)
1666 pcg 1.38 selection_rotate (ev.x, ev.y);
1667 pcg 1.36 else
1668 pcg 1.38 selection_extend (ev.x, ev.y, 1);
1669 pcg 1.36 MEvent.button = Button3;
1670     break;
1671     }
1672     }
1673 pcg 1.38 MEvent.time = ev.time;
1674 pcg 1.36 return;
1675     }
1676     }
1677 pcg 1.1
1678 pcg 1.36 /*
1679     * Scrollbar window processing of button press
1680     */
1681 pcg 1.38 if (isScrollbarWindow(ev.window))
1682 pcg 1.36 {
1683     scrollBar.setIdle ();
1684     /*
1685     * Rxvt-style scrollbar:
1686     * move up if mouse is above slider
1687     * move dn if mouse is below slider
1688     *
1689     * XTerm-style scrollbar:
1690     * Move display proportional to pointer location
1691     * pointer near top -> scroll one line
1692     * pointer near bot -> scroll full page
1693     */
1694 pcg 1.1 #ifndef NO_SCROLLBAR_REPORT
1695 pcg 1.36 if (reportmode)
1696     {
1697     /*
1698     * Mouse report disabled scrollbar:
1699     * arrow buttons - send up/down
1700     * click on scrollbar - send pageup/down
1701     */
1702     if ((scrollBar.style == R_SB_NEXT
1703 pcg 1.38 && scrollbarnext_upButton(ev.y))
1704 pcg 1.36 || (scrollBar.style == R_SB_RXVT
1705 pcg 1.38 && scrollbarrxvt_upButton(ev.y)))
1706 pcg 1.36 tt_printf("\033[A");
1707     else if ((scrollBar.style == R_SB_NEXT
1708 pcg 1.38 && scrollbarnext_dnButton(ev.y))
1709 pcg 1.36 || (scrollBar.style == R_SB_RXVT
1710 pcg 1.38 && scrollbarrxvt_dnButton(ev.y)))
1711 pcg 1.36 tt_printf("\033[B");
1712     else
1713 pcg 1.38 switch (ev.button)
1714 pcg 1.36 {
1715     case Button2:
1716     tt_printf("\014");
1717     break;
1718     case Button1:
1719     tt_printf("\033[6~");
1720     break;
1721     case Button3:
1722     tt_printf("\033[5~");
1723     break;
1724     }
1725     }
1726     else
1727 pcg 1.1 #endif /* NO_SCROLLBAR_REPORT */
1728    
1729 pcg 1.36 {
1730     char upordown = 0;
1731    
1732     if (scrollBar.style == R_SB_NEXT)
1733     {
1734 pcg 1.38 if (scrollbarnext_upButton(ev.y))
1735 pcg 1.36 upordown = -1; /* up */
1736 pcg 1.38 else if (scrollbarnext_dnButton(ev.y))
1737 pcg 1.36 upordown = 1; /* down */
1738     }
1739     else if (scrollBar.style == R_SB_RXVT)
1740     {
1741 pcg 1.38 if (scrollbarrxvt_upButton(ev.y))
1742 pcg 1.36 upordown = -1; /* up */
1743 pcg 1.38 else if (scrollbarrxvt_dnButton(ev.y))
1744 pcg 1.36 upordown = 1; /* down */
1745     }
1746     if (upordown)
1747     {
1748 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1749 pcg 1.36 scroll_arrow_delay = SCROLLBAR_INITIAL_DELAY;
1750 pcg 1.1 #endif
1751 pcg 1.36 if (scr_page (upordown < 0 ? UP : DN, 1))
1752     {
1753     if (upordown < 0)
1754     scrollBar.setUp ();
1755     else
1756     scrollBar.setDn ();
1757     }
1758     }
1759     else
1760 pcg 1.38 switch (ev.button)
1761 pcg 1.36 {
1762     case Button2:
1763     switch (scrollbar_align)
1764     {
1765     case R_SB_ALIGN_TOP:
1766     csrO = 0;
1767     break;
1768     case R_SB_ALIGN_CENTRE:
1769     csrO = (scrollBar.bot - scrollBar.top) / 2;
1770     break;
1771     case R_SB_ALIGN_BOTTOM:
1772     csrO = scrollBar.bot - scrollBar.top;
1773     break;
1774     }
1775     if (scrollBar.style == R_SB_XTERM
1776 pcg 1.38 || scrollbar_above_slider(ev.y)
1777     || scrollbar_below_slider(ev.y))
1778     scr_move_to ( scrollbar_position(ev.y) - csrO,
1779 pcg 1.36 scrollbar_size());
1780     scrollBar.setMotion ();
1781     break;
1782    
1783     case Button1:
1784     if (scrollbar_align == R_SB_ALIGN_CENTRE)
1785 pcg 1.38 csrO = ev.y - scrollBar.top;
1786 pcg 1.36 /* FALLTHROUGH */
1787    
1788     case Button3:
1789     if (scrollBar.style != R_SB_XTERM)
1790     {
1791 pcg 1.38 if (scrollbar_above_slider(ev.y))
1792 pcg 1.1 # ifdef RXVT_SCROLL_FULL
1793 pcg 1.36 scr_page (UP, TermWin.nrow - 1);
1794 pcg 1.1 # else
1795 pcg 1.36 scr_page (UP, TermWin.nrow / 4);
1796 pcg 1.1 # endif
1797 pcg 1.38 else if (scrollbar_below_slider(ev.y))
1798 pcg 1.1 # ifdef RXVT_SCROLL_FULL
1799 pcg 1.36 scr_page (DN, TermWin.nrow - 1);
1800 pcg 1.1 # else
1801 pcg 1.36 scr_page (DN, TermWin.nrow / 4);
1802 pcg 1.1 # endif
1803 pcg 1.36 else
1804     scrollBar.setMotion ();
1805     }
1806     else
1807     {
1808 pcg 1.38 scr_page ((ev.button == Button1 ? DN : UP),
1809 pcg 1.36 (TermWin.nrow
1810 pcg 1.38 * scrollbar_position(ev.y)
1811 pcg 1.36 / scrollbar_size()));
1812     }
1813     break;
1814     }
1815     }
1816     return;
1817 pcg 1.1 }
1818     #if MENUBAR
1819 pcg 1.36 /*
1820     * Menubar window processing of button press
1821     */
1822 pcg 1.38 if (isMenuBarWindow(ev.window))
1823 pcg 1.36 menubar_control (ev);
1824 pcg 1.1 #endif
1825     }
1826    
1827     void
1828 pcg 1.38 rxvt_term::button_release (const XButtonEvent &ev)
1829 pcg 1.1 {
1830 pcg 1.38 int reportmode = 0;
1831 pcg 1.1
1832 pcg 1.36 csrO = 0; /* reset csr Offset */
1833     if (!bypass_keystate)
1834     reportmode = !!(PrivateModes & PrivMode_mouse_report);
1835    
1836     if (scrollbar_isUpDn())
1837     {
1838     scrollBar.setIdle ();
1839     scrollbar_show (0);
1840 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1841 pcg 1.36 refresh_type &= ~SMOOTH_REFRESH;
1842 pcg 1.1 #endif
1843 pcg 1.36
1844 pcg 1.1 }
1845     #ifdef SELECTION_SCROLLING
1846 pcg 1.36 pending_scroll_selection=0;
1847 pcg 1.1 #endif
1848 pcg 1.38 if (ev.window == TermWin.vt)
1849 pcg 1.36 {
1850 pcg 1.1 #ifdef RXVT_GRAPHICS
1851 pcg 1.38 if (ev.subwindow != None)
1852     rxvt_Gr_ButtonRelease(ev.x, ev.y);
1853 pcg 1.36 else
1854 pcg 1.1 #endif
1855 pcg 1.36
1856     {
1857     if (reportmode)
1858     {
1859     /* mouse report from vt window */
1860     /* don't report release of wheel "buttons" */
1861 pcg 1.38 if (ev.button >= 4)
1862 pcg 1.36 return;
1863 pcg 1.1 #ifdef MOUSE_REPORT_DOUBLECLICK
1864 pcg 1.36 /* only report the release of 'slow' single clicks */
1865     if (MEvent.button != AnyButton
1866 pcg 1.38 && (ev.button != MEvent.button
1867     || (ev.time - MEvent.time
1868 pcg 1.36 > MULTICLICK_TIME / 2)))
1869     {
1870     MEvent.clicks = 0;
1871     MEvent.button = AnyButton;
1872     mouse_report (ev);
1873     }
1874 pcg 1.1 #else /* MOUSE_REPORT_DOUBLECLICK */
1875 pcg 1.36 MEvent.button = AnyButton;
1876     mouse_report (ev);
1877 pcg 1.1 #endif /* MOUSE_REPORT_DOUBLECLICK */
1878 pcg 1.36 return;
1879     }
1880     /*
1881     * dumb hack to compensate for the failure of click-and-drag
1882     * when overriding mouse reporting
1883     */
1884     if (PrivateModes & PrivMode_mouse_report
1885     && bypass_keystate
1886 pcg 1.38 && ev.button == Button1 && MEvent.clicks <= 1)
1887     selection_extend (ev.x, ev.y, 0);
1888 pcg 1.36
1889 pcg 1.38 switch (ev.button)
1890 pcg 1.36 {
1891     case Button1:
1892     case Button3:
1893 pcg 1.38 selection_make (ev.time);
1894 pcg 1.36 break;
1895     case Button2:
1896 pcg 1.38 selection_request (ev.time, ev.x, ev.y);
1897 pcg 1.36 break;
1898 pcg 1.1 #ifdef MOUSE_WHEEL
1899 pcg 1.36 case Button4:
1900     case Button5:
1901     {
1902     int i;
1903     page_dirn v;
1904    
1905 pcg 1.38 v = (ev.button == Button4) ? UP : DN;
1906     if (ev.state & ShiftMask)
1907 pcg 1.36 i = 1;
1908     else if ((Options & Opt_mouseWheelScrollPage))
1909     i = TermWin.nrow - 1;
1910     else
1911     i = 5;
1912 pcg 1.1 # ifdef MOUSE_SLIP_WHEELING
1913 pcg 1.38 if (ev.state & ControlMask)
1914 pcg 1.36 {
1915     mouse_slip_wheel_speed += (v ? -1 : 1);
1916     mouse_slip_wheel_delay = SCROLLBAR_CONTINUOUS_DELAY;
1917     }
1918 pcg 1.1 # endif
1919     # ifdef JUMP_MOUSE_WHEEL
1920 pcg 1.36 scr_page (v, i);
1921     scr_refresh (SMOOTH_REFRESH);
1922     scrollbar_show (1);
1923 pcg 1.1 # else
1924 pcg 1.36 while (i--)
1925     {
1926     scr_page (v, 1);
1927     scr_refresh (SMOOTH_REFRESH);
1928     scrollbar_show (1);
1929     }
1930 pcg 1.1 # endif
1931 pcg 1.36
1932     }
1933     break;
1934 pcg 1.1 #endif
1935 pcg 1.36
1936     }
1937     }
1938     }
1939 pcg 1.1 #ifdef MENUBAR
1940 pcg 1.38 else if (isMenuBarWindow(ev.window))
1941 pcg 1.36 menubar_control (ev);
1942 pcg 1.1 #endif
1943     }
1944    
1945    
1946     #ifdef TRANSPARENT
1947     /*
1948     * Check our parents are still who we think they are.
1949     * Do transparency updates if required
1950     */
1951     int
1952 pcg 1.34 rxvt_term::check_our_parents ()
1953 pcg 1.1 {
1954 pcg 1.36 int i, pchanged, aformat, have_pixmap, rootdepth;
1955     unsigned long nitems, bytes_after;
1956     Atom atype;
1957     unsigned char *prop = NULL;
1958     Window root, oldp, *list;
1959     Pixmap rootpixmap = None;
1960     XWindowAttributes wattr, wrootattr;
1961    
1962     pchanged = 0;
1963    
1964     if (!(Options & Opt_transparent))
1965     return pchanged; /* Don't try any more */
1966    
1967 pcg 1.38 XGetWindowAttributes(display->display, display->root, &wrootattr);
1968 pcg 1.36 rootdepth = wrootattr.depth;
1969    
1970 pcg 1.38 XGetWindowAttributes(display->display, TermWin.parent[0], &wattr);
1971 pcg 1.36 if (rootdepth != wattr.depth)
1972     {
1973     if (am_transparent)
1974     {
1975     pchanged = 1;
1976 pcg 1.38 XSetWindowBackground(display->display, TermWin.vt,
1977 pcg 1.36 PixColors[Color_bg]);
1978     am_transparent = am_pixmap_trans = 0;
1979     }
1980     return pchanged; /* Don't try any more */
1981 pcg 1.1 }
1982    
1983 pcg 1.36 /* Get all X ops out of the queue so that our information is up-to-date. */
1984 pcg 1.38 XSync(display->display, False);
1985 pcg 1.1
1986 pcg 1.36 /*
1987     * Make the frame window set by the window manager have
1988     * the root background. Some window managers put multiple nested frame
1989     * windows for each client, so we have to take care about that.
1990     */
1991     i = (xa[XA_XROOTPMAPID] != 0
1992 pcg 1.38 && (XGetWindowProperty(display->display, display->root, xa[XA_XROOTPMAPID],
1993 pcg 1.36 0L, 1L, False, XA_PIXMAP, &atype, &aformat,
1994     &nitems, &bytes_after, &prop) == Success));
1995     if (!i || prop == NULL)
1996     have_pixmap = 0;
1997     else
1998     {
1999     have_pixmap = 1;
2000     rootpixmap = *((Pixmap *)prop);
2001     XFree(prop);
2002 pcg 1.1 }
2003 pcg 1.36 if (have_pixmap)
2004     {
2005     /*
2006 pcg 1.38 * Copy display->root pixmap transparency
2007 pcg 1.36 */
2008     int sx, sy, nx, ny;
2009     unsigned int nw, nh;
2010     Window cr;
2011     XImage *image;
2012     GC gc;
2013     XGCValues gcvalue;
2014    
2015 pcg 1.38 XTranslateCoordinates(display->display, TermWin.parent[0], display->root,
2016 pcg 1.36 0, 0, &sx, &sy, &cr);
2017     nw = (unsigned int)szHint.width;
2018     nh = (unsigned int)szHint.height;
2019     nx = ny = 0;
2020     if (sx < 0)
2021     {
2022     nw += sx;
2023     nx = -sx;
2024     sx = 0;
2025     }
2026     if (sy < 0)
2027     {
2028     nh += sy;
2029     ny = -sy;
2030     sy = 0;
2031     }
2032     MIN_IT(nw, (unsigned int)(wrootattr.width - sx));
2033     MIN_IT(nh, (unsigned int)(wrootattr.height - sy));
2034     allowedxerror = -1;
2035 pcg 1.38 image = XGetImage(display->display, rootpixmap, sx, sy, nw, nh, AllPlanes,
2036 pcg 1.36 ZPixmap);
2037     /* XXX: handle BadMatch - usually because we're outside the pixmap */
2038     /* XXX: may need a delay here? */
2039     allowedxerror = 0;
2040     if (image == NULL)
2041     {
2042     if (am_transparent && am_pixmap_trans)
2043     {
2044     pchanged = 1;
2045     if (TermWin.pixmap != None)
2046     {
2047 pcg 1.38 XFreePixmap(display->display, TermWin.pixmap);
2048 pcg 1.36 TermWin.pixmap = None;
2049     }
2050     }
2051     am_pixmap_trans = 0;
2052     }
2053     else
2054     {
2055     if (TermWin.pixmap != None)
2056 pcg 1.38 XFreePixmap(display->display, TermWin.pixmap);
2057     TermWin.pixmap = XCreatePixmap(display->display, TermWin.vt,
2058 pcg 1.36 (unsigned int)szHint.width,
2059     (unsigned int)szHint.height,
2060     (unsigned int)image->depth);
2061 pcg 1.38 gc = XCreateGC(display->display, TermWin.vt, 0UL, &gcvalue);
2062     XPutImage(display->display, TermWin.pixmap, gc, image, 0, 0,
2063 pcg 1.36 nx, ny, (unsigned int)image->width,
2064     (unsigned int)image->height);
2065 pcg 1.38 XFreeGC(display->display, gc);
2066 pcg 1.36 XDestroyImage(image);
2067 pcg 1.38 XSetWindowBackgroundPixmap(display->display, TermWin.vt,
2068 pcg 1.36 TermWin.pixmap);
2069     if (!am_transparent || !am_pixmap_trans)
2070     pchanged = 1;
2071     am_transparent = am_pixmap_trans = 1;
2072     }
2073 pcg 1.1 }
2074 pcg 1.36 if (!am_pixmap_trans)
2075     {
2076     unsigned int n;
2077     /*
2078     * InheritPixmap transparency
2079     */
2080 pcg 1.38 D_X((stderr, "InheritPixmap Seeking to %08lx", display->root));
2081 pcg 1.36 for (i = 1; i < (int)(sizeof(TermWin.parent) / sizeof(Window));
2082     i++)
2083     {
2084     oldp = TermWin.parent[i];
2085 pcg 1.38 XQueryTree(display->display, TermWin.parent[i - 1], &root,
2086 pcg 1.36 &TermWin.parent[i], &list, &n);
2087     XFree(list);
2088     D_X((stderr, "InheritPixmap Parent[%d] = %08lx", i, TermWin.parent[i]));
2089 pcg 1.38 if (TermWin.parent[i] == display->root)
2090 pcg 1.36 {
2091     if (oldp != None)
2092     pchanged = 1;
2093     break;
2094     }
2095     if (oldp != TermWin.parent[i])
2096     pchanged = 1;
2097     }
2098     n = 0;
2099     if (pchanged)
2100     {
2101     for (; n < (unsigned int)i; n++)
2102     {
2103 pcg 1.38 XGetWindowAttributes(display->display, TermWin.parent[n], &wattr);
2104 pcg 1.36 D_X((stderr, "InheritPixmap Checking Parent[%d]: %s", n, (wattr.depth == rootdepth && wattr.class != InputOnly) ? "OK" : "FAIL"));
2105     if (wattr.depth != rootdepth || wattr.c_class == InputOnly)
2106     {
2107     n = (int)(sizeof(TermWin.parent) / sizeof(Window)) + 1;
2108     break;
2109     }
2110     }
2111     }
2112     if (n > (int)(sizeof(TermWin.parent)
2113     / sizeof(TermWin.parent[0])))
2114     {
2115     D_X((stderr, "InheritPixmap Turning off"));
2116 pcg 1.38 XSetWindowBackground(display->display, TermWin.parent[0],
2117 pcg 1.36 PixColors[Color_fg]);
2118 pcg 1.38 XSetWindowBackground(display->display, TermWin.vt,
2119 pcg 1.36 PixColors[Color_bg]);
2120     am_transparent = 0;
2121     /* XXX: also turn off Opt_transparent? */
2122     }
2123     else
2124     {
2125     /* wait (an arbitrary period) for the WM to do its thing
2126     * needed for fvwm2.2.2 (and before?) */
2127 pcg 1.1 # ifdef HAVE_NANOSLEEP
2128 pcg 1.36 struct timespec rqt;
2129 pcg 1.1
2130 pcg 1.36 rqt.tv_sec = 1;
2131     rqt.tv_nsec = 0;
2132     nanosleep(&rqt, NULL);
2133 pcg 1.1 # else
2134 pcg 1.36 sleep(1);
2135 pcg 1.1 # endif
2136 pcg 1.36 D_X((stderr, "InheritPixmap Turning on (%d parents)", i - 1));
2137     for (n = 0; n < (unsigned int)i; n++)
2138 pcg 1.38 XSetWindowBackgroundPixmap(display->display, TermWin.parent[n],
2139 pcg 1.36 ParentRelative);
2140 pcg 1.38 XSetWindowBackgroundPixmap(display->display, TermWin.vt,
2141 pcg 1.36 ParentRelative);
2142     am_transparent = 1;
2143     }
2144     for (; i < (int)(sizeof(TermWin.parent) / sizeof(Window)); i++)
2145     TermWin.parent[i] = None;
2146 pcg 1.1 }
2147 pcg 1.36 return pchanged;
2148 pcg 1.1 }
2149     #endif
2150    
2151     /*}}} */
2152    
2153     /*{{{ print pipe */
2154     /*----------------------------------------------------------------------*/
2155     #ifdef PRINTPIPE
2156 pcg 1.34 FILE *
2157     rxvt_term::popen_printer ()
2158 pcg 1.1 {
2159 pcg 1.36 FILE *stream = popen(rs[Rs_print_pipe], "w");
2160 pcg 1.1
2161 pcg 1.36 if (stream == NULL)
2162     rxvt_print_error("can't open printer pipe");
2163     return stream;
2164 pcg 1.1 }
2165    
2166     int
2167 pcg 1.34 rxvt_term::pclose_printer (FILE *stream)
2168 pcg 1.1 {
2169 pcg 1.11 fflush (stream);
2170 pcg 1.36 /* pclose() reported not to work on SunOS 4.1.3 */
2171 pcg 1.1 # if defined (__sun__) /* TODO: RESOLVE THIS */
2172 pcg 1.36 /* pclose works provided SIGCHLD handler uses waitpid */
2173 pcg 1.11 return pclose (stream); /* return fclose (stream); */
2174 pcg 1.1 # else
2175 pcg 1.11 return pclose (stream);
2176 pcg 1.1 # endif
2177     }
2178    
2179     /*
2180     * simulate attached vt100 printer
2181     */
2182     void
2183 pcg 1.34 rxvt_term::process_print_pipe ()
2184 pcg 1.1 {
2185 pcg 1.36 int done;
2186     FILE *fd;
2187    
2188     if ((fd = popen_printer ()) == NULL)
2189     return;
2190    
2191     /*
2192     * Send all input to the printer until either ESC[4i or ESC[?4i
2193     * is received.
2194     */
2195     for (done = 0; !done;)
2196     {
2197     unsigned char buf[8];
2198     unsigned char ch;
2199     unsigned int i, len;
2200 pcg 1.1
2201 pcg 1.36 if ((ch = cmd_getc ()) != C0_ESC)
2202     {
2203     if (putc(ch, fd) == EOF)
2204     break; /* done = 1 */
2205     }
2206     else
2207     {
2208     len = 0;
2209     buf[len++] = ch;
2210 pcg 1.1
2211 pcg 1.36 if ((buf[len++] = cmd_getc ()) == '[')
2212     {
2213     if ((ch = cmd_getc ()) == '?')
2214     {
2215     buf[len++] = '?';
2216     ch = cmd_getc ();
2217     }
2218     if ((buf[len++] = ch) == '4')
2219     {
2220     if ((buf[len++] = cmd_getc ()) == 'i')
2221     break; /* done = 1 */
2222     }
2223     }
2224     for (i = 0; i < len; i++)
2225     if (putc(buf[i], fd) == EOF)
2226     {
2227     done = 1;
2228     break;
2229     }
2230     }
2231 pcg 1.1 }
2232 pcg 1.36 pclose_printer (fd);
2233 pcg 1.1 }
2234     #endif /* PRINTPIPE */
2235     /*}}} */
2236    
2237     /* *INDENT-OFF* */
2238     enum {
2239 pcg 1.36 C1_40 = 0x40,
2240     C1_41 , C1_BPH, C1_NBH, C1_44 , C1_NEL, C1_SSA, C1_ESA,
2241     C1_HTS, C1_HTJ, C1_VTS, C1_PLD, C1_PLU, C1_RI , C1_SS2, C1_SS3,
2242     C1_DCS, C1_PU1, C1_PU2, C1_STS, C1_CCH, C1_MW , C1_SPA, C1_EPA,
2243     C1_SOS, C1_59 , C1_SCI, C1_CSI, CS_ST , C1_OSC, C1_PM , C1_APC
2244 pcg 1.1 };
2245     /* *INDENT-ON* */
2246    
2247     /*{{{ process non-printing single characters */
2248     void
2249 pcg 1.34 rxvt_term::process_nonprinting (unsigned char ch)
2250 pcg 1.1 {
2251 pcg 1.36 switch (ch)
2252     {
2253     case C0_ENQ: /* terminal Status */
2254     if (rs[Rs_answerbackstring])
2255     tt_write(
2256     (const unsigned char *)rs[Rs_answerbackstring],
2257     (unsigned int)STRLEN(rs[Rs_answerbackstring]));
2258     else
2259     tt_write((unsigned char *)VT100_ANS,
2260     (unsigned int)STRLEN(VT100_ANS));
2261     break;
2262     case C0_BEL: /* bell */
2263     scr_bell ();
2264     break;
2265     case C0_BS: /* backspace */
2266     scr_backspace ();
2267     break;
2268     case C0_HT: /* tab */
2269     scr_tab (1);
2270     break;
2271     case C0_CR: /* carriage return */
2272     scr_gotorc (0, 0, R_RELATIVE);
2273     break;
2274     case C0_VT: /* vertical tab, form feed */
2275     case C0_FF:
2276     case C0_LF: /* line feed */
2277     scr_index (UP);
2278     break;
2279     case C0_SO: /* shift out - acs */
2280     scr_charset_choose (1);
2281     break;
2282     case C0_SI: /* shift in - acs */
2283     scr_charset_choose (0);
2284     break;
2285 pcg 1.1 }
2286     }
2287     /*}}} */
2288    
2289    
2290     /*{{{ process VT52 escape sequences */
2291     void
2292 pcg 1.34 rxvt_term::process_escape_vt52 (unsigned char ch)
2293 pcg 1.1 {
2294 pcg 1.36 int row, col;
2295    
2296     switch (ch)
2297     {
2298     case 'A': /* cursor up */
2299     scr_gotorc (-1, 0, R_RELATIVE | C_RELATIVE);
2300     break;
2301     case 'B': /* cursor down */
2302     scr_gotorc (1, 0, R_RELATIVE | C_RELATIVE);
2303     break;
2304     case 'C': /* cursor right */
2305     scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
2306     break;
2307     case 'D': /* cursor left */
2308     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
2309     break;
2310     case 'H': /* cursor home */
2311     scr_gotorc (0, 0, 0);
2312     break;
2313     case 'I': /* cursor up and scroll down if needed */
2314     scr_index (DN);
2315     break;
2316     case 'J': /* erase to end of screen */
2317     scr_erase_screen (0);
2318     break;
2319     case 'K': /* erase to end of line */
2320     scr_erase_line (0);
2321     break;
2322     case 'Y': /* move to specified row and col */
2323     /* full command is 'ESC Y row col' where row and col
2324     * are encoded by adding 32 and sending the ascii
2325     * character. eg. SPACE = 0, '+' = 13, '0' = 18,
2326     * etc. */
2327     row = cmd_getc () - ' ';
2328     col = cmd_getc () - ' ';
2329     scr_gotorc (row, col, 0);
2330     break;
2331     case 'Z': /* identify the terminal type */
2332     tt_printf("\033/Z"); /* I am a VT100 emulating a VT52 */
2333 pcg 1.1 break;
2334 pcg 1.36 case '<': /* turn off VT52 mode */
2335 pcg 1.1 PrivMode(0, PrivMode_vt52);
2336 pcg 1.36 break;
2337     case 'F': /* use special graphics character set */
2338     case 'G': /* use regular character set */
2339     /* unimplemented */
2340     break;
2341     case '=': /* use alternate keypad mode */
2342     case '>': /* use regular keypad mode */
2343     /* unimplemented */
2344     break;
2345 pcg 1.1 }
2346     }
2347     /*}}} */
2348    
2349    
2350     /*{{{ process escape sequences */
2351     void
2352 pcg 1.34 rxvt_term::process_escape_seq ()
2353 pcg 1.1 {
2354 pcg 1.36 unsigned char ch = cmd_getc ();
2355    
2356     if (PrivateModes & PrivMode_vt52)
2357     {
2358     process_escape_vt52 (ch);
2359     return;
2360     }
2361 pcg 1.1
2362 pcg 1.36 switch (ch)
2363     {
2364     /* case 1: do_tek_mode (); break; */
2365     case '#':
2366     if (cmd_getc () == '8')
2367     scr_E ();
2368     break;
2369     case '(':
2370     scr_charset_set (0, (unsigned int)cmd_getc ());
2371     break;
2372     case ')':
2373     scr_charset_set (1, (unsigned int)cmd_getc ());
2374     break;
2375     case '*':
2376     scr_charset_set (2, (unsigned int)cmd_getc ());
2377     break;
2378     case '+':
2379     scr_charset_set (3, (unsigned int)cmd_getc ());
2380     break;
2381 pcg 1.1 #ifdef MULTICHAR_SET
2382 pcg 1.36 case '$':
2383     scr_charset_set (-2, (unsigned int)cmd_getc ());
2384     break;
2385 pcg 1.1 #endif
2386     #ifndef NO_FRILLS
2387 pcg 1.36 case '6':
2388     scr_backindex ();
2389     break;
2390     #endif
2391     case '7':
2392     scr_cursor (SAVE);
2393     break;
2394     case '8':
2395     scr_cursor (RESTORE);
2396     break;
2397 pcg 1.1 #ifndef NO_FRILLS
2398 pcg 1.36 case '9':
2399     scr_forwardindex ();
2400     break;
2401     #endif
2402     case '=':
2403     case '>':
2404     PrivMode((ch == '='), PrivMode_aplKP);
2405     break;
2406    
2407     case C1_40:
2408     cmd_getc ();
2409     break;
2410     case C1_44:
2411     scr_index (UP);
2412     break;
2413 pcg 1.1
2414 pcg 1.36 /* 8.3.87: NEXT LINE */
2415     case C1_NEL: /* ESC E */
2416 pcg 1.1 {
2417     uint32_t nlcr[] = { '\n', '\r' };
2418 pcg 1.34 scr_add_lines (nlcr, 1, 2);
2419 pcg 1.1 }
2420 pcg 1.36 break;
2421    
2422     /* kidnapped escape sequence: Should be 8.3.48 */
2423     case C1_ESA: /* ESC G */
2424     process_graphics ();
2425     break;
2426    
2427     /* 8.3.63: CHARACTER TABULATION SET */
2428     case C1_HTS: /* ESC H */
2429     scr_set_tab (1);
2430     break;
2431    
2432     /* 8.3.105: REVERSE LINE FEED */
2433     case C1_RI: /* ESC M */
2434     scr_index (DN);
2435     break;
2436    
2437     /* 8.3.142: SINGLE-SHIFT TWO */
2438     /*case C1_SS2: scr_single_shift (2); break; */
2439    
2440     /* 8.3.143: SINGLE-SHIFT THREE */
2441     /*case C1_SS3: scr_single_shift (3); break; */
2442    
2443     /* 8.3.27: DEVICE CONTROL STRING */
2444     case C1_DCS: /* ESC P */
2445     process_dcs_seq ();
2446     break;
2447    
2448     /* 8.3.110: SINGLE CHARACTER INTRODUCER */
2449     case C1_SCI: /* ESC Z */
2450     tt_write((const unsigned char *)ESCZ_ANSWER,
2451     (unsigned int)(sizeof(ESCZ_ANSWER) - 1));
2452     break; /* steal obsolete ESC [ c */
2453    
2454     /* 8.3.16: CONTROL SEQUENCE INTRODUCER */
2455     case C1_CSI: /* ESC [ */
2456     process_csi_seq ();
2457     break;
2458 pcg 1.1
2459 pcg 1.36 /* 8.3.90: OPERATING SYSTEM COMMAND */
2460     case C1_OSC: /* ESC ] */
2461     process_osc_seq ();
2462     break;
2463    
2464     /* 8.3.106: RESET TO INITIAL STATE */
2465     case 'c':
2466     scr_poweron ();
2467     scrollbar_show (1);
2468     break;
2469    
2470     /* 8.3.79: LOCKING-SHIFT TWO (see ISO2022) */
2471     case 'n':
2472     scr_charset_choose (2);
2473     break;
2474    
2475     /* 8.3.81: LOCKING-SHIFT THREE (see ISO2022) */
2476     case 'o':
2477     scr_charset_choose (3);
2478     break;
2479 pcg 1.1 }
2480     }
2481     /*}}} */
2482    
2483     /*{{{ process CONTROL SEQUENCE INTRODUCER (CSI) sequences `ESC[' */
2484     /* *INDENT-OFF* */
2485     enum {
2486 pcg 1.36 CSI_ICH = 0x40,
2487     CSI_CUU, CSI_CUD, CSI_CUF, CSI_CUB, CSI_CNL, CSI_CPL, CSI_CHA,
2488     CSI_CUP, CSI_CHT, CSI_ED , CSI_EL , CSI_IL , CSI_DL , CSI_EF , CSI_EA ,
2489     CSI_DCH, CSI_SEE, CSI_CPR, CSI_SU , CSI_SD , CSI_NP , CSI_PP , CSI_CTC,
2490     CSI_ECH, CSI_CVT, CSI_CBT, CSI_SRS, CSI_PTX, CSI_SDS, CSI_SIMD, CSI_5F,
2491     CSI_HPA, CSI_HPR, CSI_REP, CSI_DA , CSI_VPA, CSI_VPR, CSI_HVP, CSI_TBC,
2492     CSI_SM , CSI_MC , CSI_HPB, CSI_VPB, CSI_RM , CSI_SGR, CSI_DSR, CSI_DAQ,
2493     CSI_70 , CSI_71 , CSI_72 , CSI_73 , CSI_74 , CSI_75 , CSI_76 , CSI_77 ,
2494     CSI_78 , CSI_79 , CSI_7A , CSI_7B , CSI_7C , CSI_7D , CSI_7E , CSI_7F
2495 pcg 1.1 };
2496    
2497     #define make_byte(b7,b6,b5,b4,b3,b2,b1,b0) \
2498     (((b7) << 7) | ((b6) << 6) | ((b5) << 5) | ((b4) << 4) \
2499     | ((b3) << 3) | ((b2) << 2) | ((b1) << 1) | (b0))
2500     #define get_byte_array_bit(array, bit) \
2501     (!!((array)[(bit) / 8] & (128 >> ((bit) & 7))))
2502    
2503 pcg 1.36 const unsigned char csi_defaults[] =
2504     {
2505 pcg 1.1 make_byte(1,1,1,1,1,1,1,1), /* @, A, B, C, D, E, F, G, */
2506     make_byte(1,1,0,0,1,1,0,0), /* H, I, J, K, L, M, N, O, */
2507     make_byte(1,0,1,1,1,1,1,0), /* P, Q, R, S, T, U, V, W, */
2508     make_byte(1,1,1,0,0,0,1,0), /* X, Y, Z, [, \, ], ^, _, */
2509     make_byte(1,1,1,0,1,1,1,0), /* `, a, b, c, d, e, f, g, */
2510     make_byte(0,0,1,1,0,0,0,0), /* h, i, j, k, l, m, n, o, */
2511     make_byte(0,0,0,0,0,0,0,0), /* p, q, r, s, t, u, v, w, */
2512     make_byte(0,0,0,0,0,0,0,0) /* x, y, z, {, |, }, ~, */
2513 pcg 1.36 };
2514 pcg 1.1 /* *INDENT-ON* */
2515    
2516     void
2517 pcg 1.34 rxvt_term::process_csi_seq ()
2518 pcg 1.1 {
2519 pcg 1.36 unsigned char ch, priv, i;
2520     unsigned int nargs, p;
2521     int n, ndef;
2522     int arg[ESC_ARGS];
2523    
2524     for (nargs = ESC_ARGS; nargs > 0;)
2525     arg[--nargs] = 0;
2526    
2527     priv = 0;
2528     ch = cmd_getc ();
2529     if (ch >= '<' && ch <= '?')
2530     { /* '<' '=' '>' '?' */
2531     priv = ch;
2532     ch = cmd_getc ();
2533     }
2534     /* read any numerical arguments */
2535     for (n = -1; ch < CSI_ICH; )
2536     {
2537     if (isdigit(ch))
2538     {
2539     if (n < 0)
2540     n = ch - '0';
2541     else
2542     n = n * 10 + ch - '0';
2543     }
2544     else if (ch == ';')
2545     {
2546     if (nargs < ESC_ARGS)
2547     arg[nargs++] = n;
2548     n = -1;
2549     }
2550     else if (ch == '\b')
2551     {
2552     scr_backspace ();
2553     }
2554     else if (ch == C0_ESC)
2555     {
2556     process_escape_seq ();
2557     return;
2558     }
2559     else if (ch < ' ')
2560     {
2561     process_nonprinting (ch);
2562     }
2563     ch = cmd_getc ();
2564     }
2565 pcg 1.1
2566 pcg 1.36 if (ch > CSI_7F)
2567     return;
2568 pcg 1.1
2569 pcg 1.36 if (nargs < ESC_ARGS)
2570     arg[nargs++] = n;
2571    
2572     i = ch - CSI_ICH;
2573     ndef = get_byte_array_bit(csi_defaults, i);
2574     for (p = 0; p < nargs; p++)
2575     if (arg[p] == -1)
2576     arg[p] = ndef;
2577 pcg 1.1
2578     #ifdef DEBUG_CMD
2579 pcg 1.36 fprintf(stderr, "CSI ");
2580     for (p = 0; p < nargs; p++)
2581     fprintf(stderr, "%d%s", arg[p], p < nargs - 1 ? ";" : "");
2582     fprintf(stderr, "%c\n", ch);
2583 pcg 1.1 #endif
2584    
2585 pcg 1.36 /*
2586     * private mode handling
2587     */
2588     if (priv)
2589     {
2590     switch (priv)
2591     {
2592     case '>':
2593     if (ch == CSI_DA) /* secondary device attributes */
2594     tt_printf("\033[>%d;%-.8s;0c", 'R', VSTRING);
2595     break;
2596     case '?':
2597     if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
2598     process_terminal_mode (ch, priv, nargs, arg);
2599     break;
2600     }
2601     return;
2602 pcg 1.1 }
2603    
2604 pcg 1.36 switch (ch)
2605     {
2606     /*
2607     * ISO/IEC 6429:1992(E) CSI sequences (defaults in parentheses)
2608     */
2609 pcg 1.1 #ifdef PRINTPIPE
2610 pcg 1.36 case CSI_MC: /* 8.3.83: (0) MEDIA COPY */
2611     switch (arg[0])
2612     {
2613     case 0: /* initiate transfer to primary aux device */
2614     scr_printscreen (0);
2615     break;
2616     case 5: /* start relay to primary aux device */
2617     process_print_pipe ();
2618     break;
2619     }
2620     break;
2621     #endif
2622 pcg 1.1
2623 pcg 1.36 case CSI_CUU: /* 8.3.22: (1) CURSOR UP */
2624     case CSI_VPR: /* 8.3.161: (1) LINE POSITION FORWARD */
2625     arg[0] = -arg[0];
2626     /* FALLTHROUGH */
2627     case CSI_CUD: /* 8.3.19: (1) CURSOR DOWN */
2628     case CSI_VPB: /* 8.3.160: (1) LINE POSITION BACKWARD */
2629     scr_gotorc (arg[0], 0, RELATIVE);
2630     break;
2631    
2632     case CSI_CUB: /* 8.3.18: (1) CURSOR LEFT */
2633     case CSI_HPB: /* 8.3.59: (1) CHARACTER POSITION BACKWARD */
2634 pcg 1.1 #ifdef ISO6429
2635 pcg 1.36 arg[0] = -arg[0];
2636 pcg 1.1 #else /* emulate common DEC VTs */
2637 pcg 1.36 arg[0] = arg[0] ? -arg[0] : -1;
2638 pcg 1.1 #endif
2639 pcg 1.36 /* FALLTHROUGH */
2640     case CSI_CUF: /* 8.3.20: (1) CURSOR RIGHT */
2641     case CSI_HPR: /* 8.3.60: (1) CHARACTER POSITION FORWARD */
2642 pcg 1.1 #ifdef ISO6429
2643 pcg 1.36 scr_gotorc (0, arg[0], RELATIVE);
2644 pcg 1.1 #else /* emulate common DEC VTs */
2645 pcg 1.36 scr_gotorc (0, arg[0] ? arg[0] : 1, RELATIVE);
2646 pcg 1.1 #endif
2647 pcg 1.36 break;
2648    
2649     case CSI_CPL: /* 8.3.13: (1) CURSOR PRECEDING LINE */
2650     arg[0] = -arg[0];
2651     /* FALLTHROUGH */
2652     case CSI_CNL: /* 8.3.12: (1) CURSOR NEXT LINE */
2653     scr_gotorc (arg[0], 0, R_RELATIVE);
2654     break;
2655    
2656     case CSI_CHA: /* 8.3.9: (1) CURSOR CHARACTER ABSOLUTE */
2657     case CSI_HPA: /* 8.3.58: (1) CURSOR POSITION ABSOLUTE */
2658     scr_gotorc (0, arg[0] - 1, R_RELATIVE);
2659     break;
2660    
2661     case CSI_VPA: /* 8.3.159: (1) LINE POSITION ABSOLUTE */
2662     scr_gotorc (arg[0] - 1, 0, C_RELATIVE);
2663     break;
2664    
2665     case CSI_CUP: /* 8.3.21: (1,1) CURSOR POSITION */
2666     case CSI_HVP: /* 8.3.64: (1,1) CHARACTER AND LINE POSITION */
2667     scr_gotorc (arg[0] - 1, nargs < 2 ? 0 : (arg[1] - 1), 0);
2668     break;
2669 pcg 1.1
2670 pcg 1.36 case CSI_CBT: /* 8.3.7: (1) CURSOR BACKWARD TABULATION */
2671     arg[0] = -arg[0];
2672     /* FALLTHROUGH */
2673     case CSI_CHT: /* 8.3.10: (1) CURSOR FORWARD TABULATION */
2674     scr_tab (arg[0]);
2675     break;
2676    
2677     case CSI_ED: /* 8.3.40: (0) ERASE IN PAGE */
2678     scr_erase_screen (arg[0]);
2679     break;
2680    
2681     case CSI_EL: /* 8.3.42: (0) ERASE IN LINE */
2682     scr_erase_line (arg[0]);
2683     break;
2684    
2685     case CSI_ICH: /* 8.3.65: (1) INSERT CHARACTER */
2686     scr_insdel_chars (arg[0], INSERT);
2687     break;
2688    
2689     case CSI_IL: /* 8.3.68: (1) INSERT LINE */
2690     scr_insdel_lines (arg[0], INSERT);
2691     break;
2692    
2693     case CSI_DL: /* 8.3.33: (1) DELETE LINE */
2694     scr_insdel_lines (arg[0], DELETE);
2695     break;
2696    
2697     case CSI_ECH: /* 8.3.39: (1) ERASE CHARACTER */
2698     scr_insdel_chars (arg[0], ERASE);
2699     break;
2700    
2701     case CSI_DCH: /* 8.3.26: (1) DELETE CHARACTER */
2702     scr_insdel_chars (arg[0], DELETE);
2703     break;
2704    
2705     case CSI_SD: /* 8.3.114: (1) SCROLL DOWN */
2706     arg[0] = -arg[0];
2707     /* FALLTHROUGH */
2708     case CSI_SU: /* 8.3.148: (1) SCROLL UP */
2709     scr_scroll_text (screen.tscroll, screen.bscroll, arg[0], 0);
2710     break;
2711    
2712     case CSI_DA: /* 8.3.24: (0) DEVICE ATTRIBUTES */
2713     tt_write((const unsigned char *)VT100_ANS,
2714     (unsigned int)(sizeof(VT100_ANS) - 1));
2715     break;
2716    
2717     case CSI_SGR: /* 8.3.118: (0) SELECT GRAPHIC RENDITION */
2718     process_sgr_mode (nargs, arg);
2719     break;
2720    
2721     case CSI_DSR: /* 8.3.36: (0) DEVICE STATUS REPORT */
2722     switch (arg[0])
2723     {
2724     case 5: /* DSR requested */
2725     tt_printf("\033[0n");
2726     break;
2727     case 6: /* CPR requested */
2728     scr_report_position ();
2729     break;
2730 pcg 1.1 #if defined (ENABLE_DISPLAY_ANSWER)
2731 pcg 1.36 case 7: /* unofficial extension */
2732     tt_printf("%-.250s\n", rs[Rs_display_name]);
2733     break;
2734     #endif
2735     case 8: /* unofficial extension */
2736     xterm_seq (XTerm_title, APL_NAME "-" VERSION, CHAR_ST);
2737     break;
2738     }
2739     break;
2740 pcg 1.1
2741 pcg 1.36 case CSI_TBC: /* 8.3.155: (0) TABULATION CLEAR */
2742     switch (arg[0])
2743     {
2744     case 0: /* char tab stop cleared at active position */
2745     scr_set_tab (0);
2746     break;
2747     /* case 1: */ /* line tab stop cleared in active line */
2748     /* case 2: */ /* char tab stops cleared in active line */
2749     case 3: /* all char tab stops are cleared */
2750     /* case 4: */ /* all line tab stops are cleared */
2751     case 5: /* all tab stops are cleared */
2752     scr_set_tab (-1);
2753     break;
2754     }
2755     break;
2756    
2757     case CSI_CTC: /* 8.3.17: (0) CURSOR TABULATION CONTROL */
2758     switch (arg[0])
2759     {
2760     case 0: /* char tab stop set at active position */
2761     scr_set_tab (1);
2762     break; /* = ESC H */
2763     /* case 1: */ /* line tab stop set at active line */
2764     case 2: /* char tab stop cleared at active position */
2765     scr_set_tab (0);
2766     break; /* = ESC [ 0 g */
2767     /* case 3: */ /* line tab stop cleared at active line */
2768     /* case 4: */ /* char tab stops cleared at active line */
2769     case 5: /* all char tab stops are cleared */
2770     scr_set_tab (-1);
2771     break; /* = ESC [ 3 g */
2772     /* case 6: */ /* all line tab stops are cleared */
2773     }
2774     break;
2775    
2776     case CSI_RM: /* 8.3.107: RESET MODE */
2777     if (arg[0] == 4)
2778     scr_insert_mode (0);
2779     break;
2780    
2781     case CSI_SM: /* 8.3.126: SET MODE */
2782     if (arg[0] == 4)
2783     scr_insert_mode (1);
2784     break;
2785    
2786     /*
2787     * PRIVATE USE beyond this point. All CSI_7? sequences here
2788     */
2789     case CSI_72: /* DECSTBM: set top and bottom margins */
2790     if (nargs == 1)
2791     scr_scroll_region (arg[0] - 1, MAX_ROWS - 1);
2792     else if (nargs == 0 || arg[0] >= arg[1])
2793     scr_scroll_region (0, MAX_ROWS - 1);
2794     else
2795     scr_scroll_region (arg[0] - 1, arg[1] - 1);
2796     break;
2797    
2798     case CSI_73:
2799     scr_cursor (SAVE);
2800     break;
2801     case CSI_75:
2802     scr_cursor (RESTORE);
2803     break;
2804 pcg 1.1
2805     #ifndef NO_FRILLS
2806 pcg 1.36 case CSI_74:
2807     process_window_ops (arg, nargs);
2808     break;
2809 pcg 1.1 #endif
2810    
2811 pcg 1.36 case CSI_78: /* DECREQTPARM */
2812     if (arg[0] == 0 || arg[0] == 1)
2813     tt_printf("\033[%d;1;1;128;128;1;0x", arg[0] + 2);
2814     /* FALLTHROUGH */
2815 pcg 1.1
2816 pcg 1.36 default:
2817     break;
2818 pcg 1.1 }
2819     }
2820     /*}}} */
2821    
2822     #ifndef NO_FRILLS
2823     /* ARGSUSED */
2824     void
2825 pcg 1.34 rxvt_term::process_window_ops (const int *args, unsigned int nargs)
2826 pcg 1.1 {
2827 pcg 1.36 int x, y;
2828 pcg 1.1 #if 0
2829 pcg 1.36 char *s;
2830 pcg 1.1 #endif
2831 pcg 1.36 XWindowAttributes wattr;
2832     Window wdummy;
2833 pcg 1.1
2834 pcg 1.36 if (nargs == 0)
2835     return;
2836     switch (args[0])
2837     {
2838     /*
2839     * commands
2840     */
2841     case 1: /* deiconify window */
2842 pcg 1.38 XMapWindow(display->display, TermWin.parent[0]);
2843 pcg 1.36 break;
2844     case 2: /* iconify window */
2845 pcg 1.38 XIconifyWindow(display->display, TermWin.parent[0],
2846     DefaultScreen(display->display));
2847 pcg 1.36 break;
2848     case 3: /* set position (pixels) */
2849 pcg 1.38 XMoveWindow(display->display, TermWin.parent[0], args[1], args[2]);
2850 pcg 1.36 break;
2851     case 4: /* set size (pixels) */
2852     set_widthheight ((unsigned int)args[2], (unsigned int)args[1]);
2853     break;
2854     case 5: /* raise window */
2855 pcg 1.38 XRaiseWindow(display->display, TermWin.parent[0]);
2856 pcg 1.36 break;
2857     case 6: /* lower window */
2858 pcg 1.38 XLowerWindow(display->display, TermWin.parent[0]);
2859 pcg 1.36 break;
2860     case 7: /* refresh window */
2861     scr_touch (true);
2862     break;
2863     case 8: /* set size (chars) */
2864     set_widthheight ((unsigned int)(args[2] * TermWin.fwidth),
2865     (unsigned int)(args[1] * TermWin.fheight));
2866     break;
2867     default:
2868     if (args[0] >= 24) /* set height (chars) */
2869     set_widthheight ((unsigned int)TermWin.width,
2870     (unsigned int)(args[1] * TermWin.fheight));
2871     break;
2872     /*
2873     * reports - some output format copied from XTerm
2874     */
2875     case 11: /* report window state */
2876 pcg 1.38 XGetWindowAttributes(display->display, TermWin.parent[0], &wattr);
2877 pcg 1.36 tt_printf("\033[%dt", wattr.map_state == IsViewable ? 1 : 2);
2878     break;
2879     case 13: /* report window position */
2880 pcg 1.38 XGetWindowAttributes(display->display, TermWin.parent[0], &wattr);
2881     XTranslateCoordinates(display->display, TermWin.parent[0], wattr.root,
2882 pcg 1.36 -wattr.border_width, -wattr.border_width,
2883     &x, &y, &wdummy);
2884     tt_printf("\033[3;%d;%dt", x, y);
2885     break;
2886     case 14: /* report window size (pixels) */
2887 pcg 1.38 XGetWindowAttributes(display->display, TermWin.parent[0], &wattr);
2888 pcg 1.36 tt_printf("\033[4;%d;%dt", wattr.height, wattr.width);
2889     break;
2890     case 18: /* report window size (chars) */
2891     tt_printf("\033[8;%d;%dt", TermWin.nrow, TermWin.ncol);
2892     break;
2893 pcg 1.1 #if 0 /* XXX: currently disabled due to security concerns */
2894 pcg 1.36 case 20: /* report icon label */
2895 pcg 1.38 XGetIconName(display->display, TermWin.parent[0], &s);
2896 pcg 1.36 tt_printf("\033]L%-.200s\234", s ? s : ""); /* 8bit ST */
2897     break;
2898     case 21: /* report window title */
2899 pcg 1.38 XFetchName(display->display, TermWin.parent[0], &s);
2900 pcg 1.36 tt_printf("\033]l%-.200s\234", s ? s : ""); /* 8bit ST */
2901     break;
2902 pcg 1.1 #endif
2903 pcg 1.36
2904 pcg 1.1 }
2905     }
2906     #endif
2907    
2908     /*----------------------------------------------------------------------*/
2909     /*
2910     * get input up until STRING TERMINATOR (or BEL)
2911     * ends_how is terminator used. returned input must be free()d
2912     */
2913     unsigned char *
2914 pcg 1.34 rxvt_term::get_to_st (unsigned char *ends_how)
2915 pcg 1.1 {
2916 pcg 1.36 int seen_esc = 0; /* seen escape? */
2917     unsigned int n = 0;
2918     unsigned char *s;
2919     unsigned char ch, string[STRING_MAX];
2920    
2921     for (; (ch = cmd_getc ());)
2922     {
2923     if (ch == C0_BEL
2924     || ch == CHAR_ST
2925     || (ch == 0x5c && seen_esc)) /* 7bit ST */
2926     break;
2927     if (ch == C0_ESC)
2928     {
2929     seen_esc = 1;
2930     continue;
2931     }
2932     else if (ch == '\t')
2933     ch = ' '; /* translate '\t' to space */
2934     else if (ch < 0x08 || (ch > 0x0d && ch < 0x20))
2935     return NULL; /* other control character - exit */
2936     if (n < sizeof(string) - 1)
2937     string[n++] = ch;
2938     seen_esc = 0;
2939     }
2940     string[n++] = '\0';
2941     if ((s = (unsigned char *)rxvt_malloc(n)) == NULL)
2942     return NULL;
2943     *ends_how = (ch == 0x5c ? C0_ESC : ch);
2944     STRNCPY(s, string, n);
2945     return s;
2946 pcg 1.1 }
2947    
2948     /*----------------------------------------------------------------------*/
2949     /*
2950     * process DEVICE CONTROL STRING `ESC P ... (ST|BEL)' or `0x90 ... (ST|BEL)'
2951     */
2952     void
2953 pcg 1.34 rxvt_term::process_dcs_seq ()
2954 pcg 1.1 {
2955 pcg 1.36 unsigned char eh, *s;
2956     /*
2957     * Not handled yet
2958     */
2959     s = get_to_st (&eh);
2960     if (s)
2961     free(s);
2962     return;
2963 pcg 1.1 }
2964    
2965     /*----------------------------------------------------------------------*/
2966     /*
2967     * process OPERATING SYSTEM COMMAND sequence `ESC ] Ps ; Pt (ST|BEL)'
2968     */
2969     void
2970 pcg 1.34 rxvt_term::process_osc_seq ()
2971 pcg 1.1 {
2972 pcg 1.36 unsigned char ch, eh, *s;
2973     int arg;
2974 pcg 1.1
2975 pcg 1.36 ch = cmd_getc ();
2976     for (arg = 0; isdigit(ch); ch = cmd_getc ())
2977     arg = arg * 10 + (ch - '0');
2978 pcg 1.1
2979 pcg 1.36 if (ch == ';')
2980     {
2981     s = get_to_st (&eh);
2982     if (s)
2983     {
2984     /*
2985     * rxvt_menubar_dispatch() violates the constness of the string,
2986     * so do it here
2987     */
2988     if (arg == XTerm_Menu)
2989 pcg 1.1 #if 0 /* XXX: currently disabled due to security concerns */
2990 pcg 1.36 menubar_dispatch ((char *)s);
2991 pcg 1.1 #else
2992 pcg 1.36 (void)0;
2993 pcg 1.1 #endif
2994 pcg 1.36 else
2995     xterm_seq (arg, (char *)s, eh);
2996     free(s);
2997     }
2998 pcg 1.1 }
2999     }
3000     /*
3001     * XTerm escape sequences: ESC ] Ps;Pt (ST|BEL)
3002     * 0 = change iconName/title
3003     * 1 = change iconName
3004     * 2 = change title
3005     * 4 = change color
3006     * 12 = change text color
3007     * 13 = change mouse foreground color
3008     * 17 = change highlight character colour
3009     * 18 = change bold character color
3010     * 19 = change underlined character color
3011     * 46 = change logfile (not implemented)
3012     * 50 = change font
3013     *
3014     * rxvt extensions:
3015     * 10 = menu (may change in future)
3016     * 20 = bg pixmap
3017     * 39 = change default fg color
3018     * 49 = change default bg color
3019     * 55 = dump scrollback buffer and all of screen
3020     */
3021     void
3022 pcg 1.34 rxvt_term::xterm_seq (int op, const char *str, unsigned char resp __attribute__((unused)))
3023 pcg 1.1 {
3024 pcg 1.36 int changed = 0;
3025     int color;
3026     char *buf, *name;
3027    
3028     assert(str != NULL);
3029     switch (op)
3030     {
3031     case XTerm_name:
3032     set_title (str);
3033     /* FALLTHROUGH */
3034     case XTerm_iconName:
3035     set_iconName (str);
3036     break;
3037     case XTerm_title:
3038     set_title (str);
3039     break;
3040     case XTerm_Color:
3041     for (buf = (char *)str; buf && *buf;)
3042     {
3043     if ((name = STRCHR(buf, ';')) == NULL)
3044     break;
3045     *name++ = '\0';
3046     color = atoi(buf);
3047     if (color < 0 || color >= TOTAL_COLORS)
3048     break;
3049     if ((buf = STRCHR(name, ';')) != NULL)
3050     *buf++ = '\0';
3051     set_window_color (color + minCOLOR, name);
3052     }
3053     break;
3054 pcg 1.1 #ifndef NO_CURSORCOLOR
3055 pcg 1.36 case XTerm_Color_cursor:
3056     set_window_color (Color_cursor, str);
3057     break;
3058     #endif
3059     case XTerm_Color_pointer:
3060     set_window_color (Color_pointer, str);
3061     break;
3062 pcg 1.1 #ifndef NO_BOLD_UNDERLINE_REVERSE
3063 pcg 1.36 case XTerm_Color_BD:
3064     set_window_color (Color_BD, str);
3065     break;
3066     case XTerm_Color_UL:
3067     set_window_color (Color_UL, str);
3068     break;
3069     case XTerm_Color_RV:
3070     set_window_color (Color_RV, str);
3071     break;
3072 pcg 1.1 #endif
3073    
3074 pcg 1.36 case XTerm_Menu:
3075 pcg 1.1 /*
3076     * rxvt_menubar_dispatch() violates the constness of the string,
3077     * so DON'T do it here
3078     */
3079 pcg 1.36 break;
3080     case XTerm_Pixmap:
3081     if (*str != ';')
3082     {
3083 pcg 1.1 #if XPM_BACKGROUND
3084 pcg 1.36 scale_pixmap (""); /* reset to default scaling */
3085     set_bgPixmap (str); /* change pixmap */
3086 pcg 1.1 #endif
3087 pcg 1.36 scr_touch (true);
3088     }
3089     while ((str = STRCHR(str, ';')) != NULL)
3090     {
3091     str++;
3092 pcg 1.1 #if XPM_BACKGROUND
3093 pcg 1.36 changed += scale_pixmap (str);
3094 pcg 1.1 #endif
3095 pcg 1.36
3096     }
3097     if (changed)
3098     {
3099 pcg 1.1 #ifdef XPM_BACKGROUND
3100 pcg 1.36 resize_pixmap ();
3101 pcg 1.1 #endif
3102 pcg 1.36 scr_touch (true);
3103     }
3104     break;
3105    
3106     case XTerm_restoreFG:
3107     set_window_color (Color_fg, str);
3108     break;
3109     case XTerm_restoreBG:
3110     set_window_color (Color_bg, str);
3111     break;
3112     case XTerm_logfile:
3113     break;
3114     case XTerm_font:
3115     change_font (0, str);
3116     break;
3117 pcg 1.1 #if 0
3118 pcg 1.36 case XTerm_dumpscreen: /* no error notices */
3119     {
3120     int fd;
3121     if ((fd = open(str, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0)
3122     {
3123     scr_dump (fd);
3124     close(fd);
3125     }
3126     }
3127     break;
3128 pcg 1.1 #endif
3129 pcg 1.36
3130 pcg 1.1 }
3131     }
3132     /*----------------------------------------------------------------------*/
3133    
3134     /*{{{ process DEC private mode sequences `ESC [ ? Ps mode' */
3135     /*
3136     * mode can only have the following values:
3137     * 'l' = low
3138     * 'h' = high
3139     * 's' = save
3140     * 'r' = restore
3141     * 't' = toggle
3142     * so no need for fancy checking
3143     */
3144     int
3145 pcg 1.34 rxvt_term::privcases (int mode, unsigned long bit)
3146 pcg 1.1 {
3147 pcg 1.36 int state;
3148 pcg 1.1
3149 pcg 1.36 if (mode == 's')
3150     {
3151     SavedModes |= (PrivateModes & bit);
3152     return -1;
3153 pcg 1.1 }
3154 pcg 1.36 else
3155     {
3156     if (mode == 'r')
3157     state = (SavedModes & bit) ? 1 : 0; /* no overlapping */
3158     else
3159     state = (mode == 't') ? !(PrivateModes & bit) : mode;
3160     PrivMode(state, bit);
3161     }
3162     return state;
3163 pcg 1.1 }
3164    
3165     /* we're not using priv _yet_ */
3166     void
3167 pcg 1.34 rxvt_term::process_terminal_mode (int mode, int priv __attribute__((unused)), unsigned int nargs, const int *arg)
3168 pcg 1.1 {
3169 pcg 1.36 unsigned int i, j;
3170     int state;
3171     static const struct
3172     {
3173     const int argval;
3174     const unsigned long bit;
3175     }
3176     argtopriv[] = {
3177     { 1, PrivMode_aplCUR },
3178     { 2, PrivMode_vt52 },
3179     { 3, PrivMode_132 },
3180     { 4, PrivMode_smoothScroll },
3181     { 5, PrivMode_rVideo },
3182     { 6, PrivMode_relOrigin },
3183     { 7, PrivMode_Autowrap },
3184     { 9, PrivMode_MouseX10 },
3185 pcg 1.1 #ifdef menuBar_esc
3186 pcg 1.36 { menuBar_esc, PrivMode_menuBar },
3187 pcg 1.1 #endif
3188     #ifdef scrollBar_esc
3189 pcg 1.36 { scrollBar_esc, PrivMode_scrollBar },
3190 pcg 1.1 #endif
3191 pcg 1.36 { 25, PrivMode_VisibleCursor },
3192     { 35, PrivMode_ShiftKeys },
3193     { 40, PrivMode_132OK },
3194     { 47, PrivMode_Screen },
3195     { 66, PrivMode_aplKP },
3196 pcg 1.1 #ifndef NO_BACKSPACE_KEY
3197 pcg 1.36 { 67, PrivMode_BackSpace },
3198 pcg 1.1 #endif
3199 pcg 1.36 { 1000, PrivMode_MouseX11 },
3200     { 1010, PrivMode_TtyOutputInh },
3201     { 1011, PrivMode_Keypress },
3202     { 1047, PrivMode_Screen },
3203     { 1049, PrivMode_Screen }, /* xterm extension, not fully implemented */
3204     };
3205    
3206     if (nargs == 0)
3207     return;
3208    
3209     /* make lo/hi boolean */
3210     if (mode == 'l')
3211     mode = 0; /* reset */
3212     else if (mode == 'h')
3213     mode = 1; /* set */
3214    
3215     for (i = 0; i < nargs; i++)
3216     {
3217     state = -1;
3218    
3219     /* basic handling */
3220     for (j = 0; j < (sizeof(argtopriv)/sizeof(argtopriv[0])); j++)
3221     if (argtopriv[j].argval == arg[i])
3222     {
3223     state = privcases (mode, argtopriv[j].bit);
3224     break;
3225     }
3226 pcg 1.1
3227 pcg 1.36 /* extra handling for values with state unkept */
3228     if (state == -1)
3229     switch (arg[i])
3230     {
3231     case 1048: /* alternative cursor save */
3232     if (mode == 0)
3233     scr_cursor (RESTORE);
3234     else if (mode == 1)
3235     scr_cursor (SAVE);
3236     /* FALLTHROUGH */
3237     default:
3238     continue; /* for(;i;) */
3239     }
3240 pcg 1.1
3241 pcg 1.36 /* extra handling for values with valid 0 or 1 state */
3242     switch (arg[i])
3243     {
3244     /* case 1: - application cursor keys */
3245     case 2: /* VT52 mode */
3246     /* oddball mode. should be set regardless of set/reset
3247     * parameter. Return from VT52 mode with an ESC < from
3248     * within VT52 mode
3249     */
3250     PrivMode(1, PrivMode_vt52);
3251     break;
3252     case 3: /* 80/132 */
3253     if (PrivateModes & PrivMode_132OK)
3254     set_widthheight ( (unsigned int)((state ? 132 : 80) * TermWin.fwidth),
3255     (unsigned int)TermWin.height);
3256     break;
3257     case 4: /* smooth scrolling */
3258     if (state)
3259     Options &= ~Opt_jumpScroll;
3260     else
3261     Options |= Opt_jumpScroll;
3262     break;
3263     case 5: /* reverse video */
3264     scr_rvideo_mode (state);
3265     break;
3266     case 6: /* relative/absolute origins */
3267     scr_relative_origin (state);
3268     break;
3269     case 7: /* autowrap */
3270     scr_autowrap (state);
3271     break;
3272     /* case 8: - auto repeat, can't do on a per window basis */
3273     case 9: /* X10 mouse reporting */
3274     if (state) /* orthogonal */
3275     PrivateModes &= ~(PrivMode_MouseX11);
3276     break;
3277 pcg 1.1 #ifdef menuBar_esc
3278 pcg 1.36 case menuBar_esc:
3279 pcg 1.1 #ifdef MENUBAR
3280 pcg 1.36 map_menuBar (state);
3281 pcg 1.1 #endif
3282 pcg 1.36 break;
3283 pcg 1.1 #endif
3284     #ifdef scrollBar_esc
3285 pcg 1.36 case scrollBar_esc:
3286     if (scrollbar_mapping (state))
3287     {
3288     resize_all_windows (0, 0, 0);
3289 pcg 1.34 scr_touch (true);
3290 pcg 1.36 }
3291     break;
3292 pcg 1.1 #endif
3293 pcg 1.36 case 25: /* visible/invisible cursor */
3294     scr_cursor_visible (state);
3295     break;
3296     /* case 35: - shift keys */
3297     /* case 40: - 80 <--> 132 mode */
3298     case 47: /* secondary screen */
3299     scr_change_screen (state);
3300     break;
3301     /* case 66: - application key pad */
3302     /* case 67: - backspace key */
3303     case 1000: /* X11 mouse reporting */
3304     if (state) /* orthogonal */
3305     PrivateModes &= ~(PrivMode_MouseX10);
3306     break;
3307 pcg 1.1 #if 0
3308 pcg 1.36 case 1001:
3309     break; /* X11 mouse highlighting */
3310 pcg 1.1 #endif
3311 pcg 1.36 case 1010: /* scroll to bottom on TTY output inhibit */
3312     if (state)
3313     Options &= ~Opt_scrollTtyOutput;
3314     else
3315     Options |= Opt_scrollTtyOutput;
3316     break;
3317     case 1011: /* scroll to bottom on key press */
3318     if (state)
3319     Options |= Opt_scrollTtyKeypress;
3320     else
3321     Options &= ~Opt_scrollTtyKeypress;
3322     break;
3323     case 1047: /* secondary screen w/ clearing */
3324     case 1049: /* better secondary screen w/ clearing, but not fully implemented */
3325     if (current_screen != PRIMARY)
3326     scr_erase_screen (2);
3327     scr_change_screen (state);
3328     /* FALLTHROUGH */
3329     default:
3330     break;
3331     }
3332 pcg 1.1 }
3333     }
3334     /*}}} */
3335    
3336     /*{{{ process sgr sequences */
3337     void
3338 pcg 1.34 rxvt_term::process_sgr_mode (unsigned int nargs, const int *arg)
3339 pcg 1.1 {
3340 pcg 1.36 unsigned int i;
3341     short rendset;
3342     int rendstyle;
3343    
3344     if (nargs == 0)
3345     {
3346     scr_rendition (0, ~RS_None);
3347     return;
3348     }
3349     for (i = 0; i < nargs; i++)
3350     {
3351     rendset = -1;
3352     switch (arg[i])
3353     {
3354     case 0:
3355     rendset = 0, rendstyle = ~RS_None;
3356     break;
3357     case 1:
3358     rendset = 1, rendstyle = RS_Bold;
3359     break;
3360     case 4:
3361     rendset = 1, rendstyle = RS_Uline;
3362     break;
3363     case 5:
3364     rendset = 1, rendstyle = RS_Blink;
3365     break;
3366     case 7:
3367     rendset = 1, rendstyle = RS_RVid;
3368     break;
3369     case 22:
3370     rendset = 0, rendstyle = RS_Bold;
3371     break;
3372     case 24:
3373     rendset = 0, rendstyle = RS_Uline;
3374     break;
3375     case 25:
3376     rendset = 0, rendstyle = RS_Blink;
3377     break;
3378     case 27:
3379     rendset = 0, rendstyle = RS_RVid;
3380     break;
3381     }
3382     if (rendset != -1)
3383     {
3384     scr_rendition (rendset, rendstyle);
3385     continue; /* for(;i;) */
3386     }
3387    
3388     switch (arg[i])
3389     {
3390     case 30:
3391     case 31: /* set fg color */
3392     case 32:
3393     case 33:
3394     case 34:
3395     case 35:
3396     case 36:
3397     case 37:
3398     scr_color ((unsigned int)(minCOLOR + (arg[i] - 30)),
3399     Color_fg);
3400     break;
3401 pcg 1.1 #ifdef TTY_256COLOR
3402 pcg 1.36 case 38:
3403     if (nargs > i + 2 && arg[i + 1] == 5)
3404     {
3405     scr_color ((unsigned int)(minCOLOR + arg[i + 2]),
3406     Color_fg);
3407     i += 2;
3408     }
3409     break;
3410     #endif
3411     case 39: /* default fg */
3412     scr_color (Color_fg, Color_fg);
3413     break;
3414    
3415     case 40:
3416     case 41: /* set bg color */
3417     case 42:
3418     case 43:
3419     case 44:
3420     case 45:
3421     case 46:
3422     case 47:
3423     scr_color ((unsigned int)(minCOLOR + (arg[i] - 40)),
3424     Color_bg);
3425     break;
3426 pcg 1.1 #ifdef TTY_256COLOR
3427 pcg 1.36 case 48:
3428     if (nargs > i + 2 && arg[i + 1] == 5)
3429     {
3430     scr_color ((unsigned int)(minCOLOR + arg[i + 2]),
3431     Color_bg);
3432     i += 2;
3433     }
3434     break;
3435     #endif
3436     case 49: /* default bg */
3437     scr_color (Color_bg, Color_bg);
3438     break;
3439 pcg 1.1
3440     #ifndef NO_BRIGHTCOLOR
3441 pcg 1.36 case 90:
3442     case 91: /* set bright fg color */
3443     case 92:
3444     case 93:
3445     case 94:
3446     case 95:
3447     case 96:
3448     case 97:
3449     scr_color ((unsigned int)(minBrightCOLOR + (arg[i] - 90)),
3450     Color_fg);
3451     break;
3452     case 100:
3453     case 101: /* set bright bg color */
3454     case 102:
3455     case 103:
3456     case 104:
3457     case 105:
3458     case 106:
3459     case 107:
3460     scr_color ((unsigned int)(minBrightCOLOR + (arg[i] - 100)),
3461     Color_bg);
3462     break;
3463 pcg 1.1 #endif
3464 pcg 1.36
3465     }
3466 pcg 1.1 }
3467     }
3468     /*}}} */
3469    
3470     /*{{{ process Rob Nation's own graphics mode sequences */
3471     void
3472 pcg 1.34 rxvt_term::process_graphics ()
3473 pcg 1.1 {
3474 pcg 1.36 unsigned char ch, cmd = cmd_getc ();
3475 pcg 1.1
3476     #ifndef RXVT_GRAPHICS
3477 pcg 1.36 if (cmd == 'Q')
3478     { /* query graphics */
3479     tt_printf("\033G0\n"); /* no graphics */
3480     return;
3481     }
3482     /* swallow other graphics sequences until terminating ':' */
3483     do
3484     ch = cmd_getc ();
3485     while (ch != ':');
3486 pcg 1.1 #else
3487 pcg 1.36 unsigned int nargs;
3488     int args[NGRX_PTS];
3489     unsigned char *text = NULL;
3490    
3491     if (cmd == 'Q')
3492     { /* query graphics */
3493     tt_printf("\033G1\n"); /* yes, graphics (color) */
3494     return;
3495 pcg 1.1 }
3496 pcg 1.36 for (nargs = 0; nargs < (sizeof(args) / sizeof(args[0])) - 1;)
3497     {
3498     int neg;
3499 pcg 1.1
3500 pcg 1.36 ch = cmd_getc ();
3501     neg = (ch == '-');
3502     if (neg || ch == '+')
3503     ch = cmd_getc ();
3504    
3505     for (args[nargs] = 0; isdigit(ch); ch = cmd_getc ())
3506     args[nargs] = args[nargs] * 10 + (ch - '0');
3507     if (neg)
3508     args[nargs] = -args[nargs];
3509    
3510     nargs++;
3511     args[nargs] = 0;
3512     if (ch != ';')
3513     break;
3514 pcg 1.1 }
3515    
3516 pcg 1.36 if ((cmd == 'T') && (nargs >= 5))
3517     {
3518     int i, len = args[4];
3519 pcg 1.1
3520 pcg 1.36 text = (unsigned char *)rxvt_malloc((len + 1) * sizeof(char));
3521 pcg 1.1
3522 pcg 1.36 if (text != NULL)
3523     {
3524     for (i = 0; i < len; i++)
3525     text[i] = cmd_getc ();
3526     text[len] = '\0';
3527     }
3528 pcg 1.1 }
3529 pcg 1.36 Gr_do_graphics (cmd, nargs, args, text);
3530 pcg 1.1 #endif
3531     }
3532     /*}}} */
3533    
3534     /* ------------------------------------------------------------------------- */
3535    
3536     /*
3537     * Send printf() formatted output to the command.
3538     * Only use for small amounts of data.
3539     */
3540     void
3541 pcg 1.10 rxvt_term::tt_printf (const char *fmt,...)
3542 pcg 1.1 {
3543 pcg 1.10 va_list arg_ptr;
3544     unsigned char buf[256];
3545 pcg 1.1
3546 pcg 1.10 va_start (arg_ptr, fmt);
3547     vsnprintf ((char *)buf, 256, fmt, arg_ptr);
3548     va_end (arg_ptr);
3549     tt_write (buf, STRLEN (buf));
3550 pcg 1.1 }
3551    
3552     /* ---------------------------------------------------------------------- */
3553 pcg 1.10 /* Write data to the pty as typed by the user, pasted with the mouse,
3554 pcg 1.1 * or generated by us in response to a query ESC sequence.
3555     */
3556     void
3557 pcg 1.10 rxvt_term::tt_write (const unsigned char *data, unsigned int len)
3558 pcg 1.1 {
3559 pcg 1.10 enum { MAX_PTY_WRITE = 255 }; // minimum MAX_INPUT
3560    
3561     if (len)
3562     {
3563     if (v_buflen == 0)
3564     {
3565 pcg 1.34 ssize_t written = write (cmd_fd, data, min (MAX_PTY_WRITE, len));
3566    
3567     if ((unsigned int)written == len)
3568 pcg 1.10 return;
3569    
3570     data += written;
3571     len -= written;
3572     }
3573    
3574    
3575     v_buffer = (unsigned char *)realloc (v_buffer, v_buflen + len);
3576    
3577     memcpy (v_buffer + v_buflen, data, len);
3578     v_buflen += len;
3579 pcg 1.1 }
3580    
3581 pcg 1.10 for (;;)
3582     {
3583     int written = write (cmd_fd, v_buffer, min (MAX_PTY_WRITE, v_buflen));
3584    
3585     if (written > 0)
3586     {
3587     v_buflen -= written;
3588    
3589     if (v_buflen == 0)
3590     {
3591     free (v_buffer);
3592     v_buffer = 0;
3593     v_buflen = 0;
3594    
3595     pty_ev.set (EVENT_READ);
3596     return;
3597     }
3598 pcg 1.1
3599 pcg 1.10 memmove (v_buffer, v_buffer + written, v_buflen);
3600     }
3601     else if (written != -1 || (errno != EAGAIN && errno != EINTR))
3602     // original code just ignores this...
3603     destroy ();
3604     else
3605     {
3606     pty_ev.set (EVENT_READ | EVENT_WRITE);
3607     return;
3608     }
3609 pcg 1.1 }
3610     }
3611 pcg 1.10
3612 pcg 1.1 /*----------------------- end-of-file (C source) -----------------------*/
3613