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