ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.116
Committed: Wed Aug 4 03:29:28 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_4
Changes since 1.107: +286 -270 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*--------------------------------*-C-*---------------------------------*
2 pcg 1.93 * File: command.C
3 pcg 1.1 *----------------------------------------------------------------------*
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     }
678    
679 pcg 1.42 display->flush ();
680 root 1.116
681     flush_ev.stop ();
682 pcg 1.11 }
683    
684     void
685     rxvt_term::check_cb (check_watcher &w)
686     {
687     SET_R (this);
688 pcg 1.19 SET_LOCALE (locale);
689 pcg 1.11
690 root 1.116 display->flush ();
691    
692     if (!flush_ev.active)
693     flush_ev.start (NOW + 0.01);
694     }
695    
696     void
697     rxvt_term::flush_cb (time_watcher &w)
698     {
699     SET_R (this);
700     SET_LOCALE (locale);
701    
702     refresh_limit = 1;
703     refresh_count = 0;
704 pcg 1.11 flush ();
705     }
706    
707 pcg 1.27 #ifdef CURSOR_BLINK
708 pcg 1.3 void
709 pcg 1.31 rxvt_term::cursor_blink_cb (time_watcher &w)
710 pcg 1.5 {
711     hidden_cursor = !hidden_cursor;
712     want_refresh = 1;
713 pcg 1.28
714     w.start (w.at + BLINK_INTERVAL);
715 pcg 1.5 }
716 pcg 1.27 #endif
717 pcg 1.5
718 pcg 1.31 #ifdef TEXT_BLINK
719     void
720     rxvt_term::text_blink_cb (time_watcher &w)
721     {
722     if (scr_refresh_rend (RS_Blink, RS_Blink))
723     {
724     hidden_text = !hidden_text;
725     want_refresh = 1;
726     w.start (w.at + TEXT_BLINK_INTERVAL);
727     }
728     }
729     #endif
730    
731 root 1.97 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
732     void
733     rxvt_term::cont_scroll_cb (time_watcher &w)
734     {
735     if ((scrollbar_isUp() || scrollbar_isDn()) &&
736     scr_page (scrollbar_isUp() ? UP : DN, 1))
737     {
738     refresh_type |= SMOOTH_REFRESH;
739     want_refresh = 1;
740     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
741     }
742     }
743     #endif
744    
745     #ifdef SELECTION_SCROLLING
746     void
747     rxvt_term::sel_scroll_cb (time_watcher &w)
748     {
749     if (scr_page (scroll_selection_dir, scroll_selection_lines))
750     {
751     selection_extend (selection_save_x, selection_save_y, selection_save_state);
752     refresh_type |= SMOOTH_REFRESH;
753     want_refresh = 1;
754     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
755     }
756     }
757     #endif
758    
759     #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
760     void
761     rxvt_term::slip_wheel_cb (time_watcher &w)
762     {
763     if (mouse_slip_wheel_speed == 0
764     || mouse_slip_wheel_speed < 0 ? scr_page (DN, -mouse_slip_wheel_speed)
765     : scr_page (UP, mouse_slip_wheel_speed))
766     {
767     refresh_type |= SMOOTH_REFRESH;
768     want_refresh = 1;
769     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
770     }
771     }
772     #endif
773    
774 pcg 1.4 bool
775 pcg 1.8 rxvt_term::pty_fill ()
776 pcg 1.4 {
777     ssize_t n = cmdbuf_endp - cmdbuf_ptr;
778    
779 pcg 1.93 if (CBUFSIZ == n)
780     {
781     rxvt_warn ("pty_fill on full buffer, draining input, continuing.\n");
782     n = 0;
783     }
784    
785 pcg 1.4 memmove (cmdbuf_base, cmdbuf_ptr, n);
786     cmdbuf_ptr = cmdbuf_base;
787     cmdbuf_endp = cmdbuf_ptr + n;
788 pcg 1.36
789 pcg 1.81 n = read (cmd_fd, cmdbuf_endp, CBUFSIZ - n);
790 pcg 1.4
791     if (n > 0)
792     {
793     cmdbuf_endp += n;
794     return true;
795     }
796 pcg 1.13 else if (n < 0 && errno != EAGAIN)
797     destroy ();
798 pcg 1.57
799 pcg 1.13 return false;
800 pcg 1.4 }
801    
802 pcg 1.3 void
803     rxvt_term::pty_cb (io_watcher &w, short revents)
804     {
805 pcg 1.9 SET_R (this);
806 pcg 1.19 SET_LOCALE (locale);
807 pcg 1.9
808 pcg 1.10 if (revents & EVENT_WRITE)
809     tt_write (0, 0);
810     else if (revents & EVENT_READ)
811 pcg 1.93 // loop, but don't allow a single term to monopolize us
812     while (pty_fill ())
813     if (cmd_parse ())
814     break;
815 pcg 1.57 }
816    
817 pcg 1.6 void
818     rxvt_term::pointer_unblank ()
819     {
820 pcg 1.38 XDefineCursor (display->display, TermWin.vt, TermWin_cursor);
821 pcg 1.19 recolour_cursor ();
822 pcg 1.7
823 root 1.107 #ifdef POINTER_BLANK
824 pcg 1.6 hidden_pointer = 0;
825 pcg 1.1
826 pcg 1.7 if (Options & Opt_pointerBlank)
827     pointer_ev.start (NOW + pointerBlankDelay);
828 root 1.107 #endif
829 pcg 1.1 }
830    
831 root 1.107 #ifdef POINTER_BLANK
832 pcg 1.1 void
833 pcg 1.6 rxvt_term::pointer_blank ()
834 pcg 1.1 {
835 pcg 1.43 if (! (Options & Opt_pointerBlank))
836 pcg 1.6 return;
837    
838 pcg 1.38 XDefineCursor (display->display, TermWin.vt, blank_cursor);
839     XFlush (display->display);
840 pcg 1.1
841 pcg 1.6 hidden_pointer = 1;
842 pcg 1.1 }
843    
844     void
845 pcg 1.6 rxvt_term::pointer_cb (time_watcher &w)
846 pcg 1.1 {
847 pcg 1.9 SET_R (this);
848 pcg 1.19 SET_LOCALE (locale);
849 pcg 1.9
850 pcg 1.6 pointer_blank ();
851 pcg 1.1 }
852     #endif
853    
854     void
855 pcg 1.56 rxvt_term::mouse_report (XButtonEvent &ev)
856 pcg 1.1 {
857 pcg 1.56 int button_number, key_state = 0;
858     int x, y;
859 pcg 1.36
860 pcg 1.38 x = ev.x;
861     y = ev.y;
862 pcg 1.36 pixel_position (&x, &y);
863    
864     if (MEvent.button == AnyButton)
865     {
866     button_number = 3;
867     }
868     else
869     {
870     button_number = MEvent.button - Button1;
871     /* add 0x3D for wheel events, like xterm does */
872     if (button_number >= 3)
873     button_number += (64 - 3);
874     }
875 pcg 1.1
876 pcg 1.36 if (PrivateModes & PrivMode_MouseX10)
877     {
878     /*
879     * do not report ButtonRelease
880     * no state info allowed
881     */
882     key_state = 0;
883     if (button_number == 3)
884     return;
885     }
886     else
887     {
888     /* XTerm mouse reporting needs these values:
889     * 4 = Shift
890     * 8 = Meta
891     * 16 = Control
892     * plus will add in our own Double-Click reporting
893     * 32 = Double Click
894     */
895     key_state = ((MEvent.state & ShiftMask) ? 4 : 0)
896     + ((MEvent.state & ModMetaMask) ? 8 : 0)
897     + ((MEvent.state & ControlMask) ? 16 : 0);
898 pcg 1.1 #ifdef MOUSE_REPORT_DOUBLECLICK
899 pcg 1.36 key_state += ((MEvent.clicks > 1) ? 32 : 0);
900 pcg 1.1 #endif
901 pcg 1.36
902 pcg 1.1 }
903    
904     #ifdef DEBUG_MOUSEREPORT
905 pcg 1.43 fprintf (stderr, "Mouse [");
906 pcg 1.36 if (key_state & 16)
907 pcg 1.43 fputc ('C', stderr);
908 pcg 1.36 if (key_state & 4)
909 pcg 1.43 fputc ('S', stderr);
910 pcg 1.36 if (key_state & 8)
911 pcg 1.43 fputc ('A', stderr);
912 pcg 1.36 if (key_state & 32)
913 pcg 1.43 fputc ('2', stderr);
914     fprintf (stderr, "]: <%d>, %d/%d\n",
915 pcg 1.36 button_number,
916     x + 1,
917     y + 1);
918 pcg 1.1 #else
919 pcg 1.43 tt_printf ("\033[M%c%c%c",
920 pcg 1.36 (32 + button_number + key_state),
921     (32 + x + 1),
922     (32 + y + 1));
923 pcg 1.1 #endif
924     }
925    
926     #ifdef USING_W11LIB
927     void
928 pcg 1.43 rxvt_W11_process_x_event (XEvent *ev)
929 pcg 1.1 {
930 pcg 1.43 rxvt_t *r = rxvt_get_r ();
931 pcg 1.1
932 pcg 1.38 x_cb (*ev);
933 pcg 1.1 }
934     #endif
935    
936     /*{{{ process an X event */
937     void
938 pcg 1.38 rxvt_term::x_cb (XEvent &ev)
939 pcg 1.1 {
940 pcg 1.38 SET_R (this);
941     SET_LOCALE (locale);
942    
943     #if defined(CURSOR_BLINK)
944     if ((Options & Opt_cursorBlink) && ev.type == KeyPress)
945     {
946     if (hidden_cursor)
947     {
948     hidden_cursor = 0;
949     want_refresh = 1;
950     }
951    
952     cursor_blink_ev.start (NOW + BLINK_INTERVAL);
953     }
954     #endif
955    
956     #if defined(POINTER_BLANK)
957     if ((Options & Opt_pointerBlank) && pointerBlankDelay > 0)
958     {
959     if (ev.type == MotionNotify
960     || ev.type == ButtonPress
961     || ev.type == ButtonRelease)
962     if (hidden_pointer)
963     pointer_unblank ();
964    
965     if (ev.type == KeyPress && hidden_pointer == 0)
966     pointer_blank ();
967     }
968     #endif
969    
970     #ifdef USE_XIM
971     if (XFilterEvent (&ev, None))
972     return;
973     #endif
974    
975 pcg 1.36 Window unused_root, unused_child;
976     int unused_root_x, unused_root_y;
977     unsigned int unused_mask;
978 pcg 1.3
979 pcg 1.1 #ifdef DEBUG_X
980 pcg 1.36 const char *const eventnames[] =
981 pcg 1.1 { /* mason - this matches my system */
982 pcg 1.36 "",
983     "",
984     "KeyPress",
985     "KeyRelease",
986     "ButtonPress",
987     "ButtonRelease",
988     "MotionNotify",
989     "EnterNotify",
990     "LeaveNotify",
991     "FocusIn",
992     "FocusOut",
993     "KeymapNotify",
994     "Expose",
995     "GraphicsExpose",
996     "NoExpose",
997     "VisibilityNotify",
998     "CreateNotify",
999     "DestroyNotify",
1000     "UnmapNotify",
1001     "MapNotify",
1002     "MapRequest",
1003     "ReparentNotify",
1004     "ConfigureNotify",
1005     "ConfigureRequest",
1006     "GravityNotify",
1007     "ResizeRequest",
1008     "CirculateNotify",
1009     "CirculateRequest",
1010     "PropertyNotify",
1011     "SelectionClear",
1012     "SelectionRequest",
1013     "SelectionNotify",
1014     "ColormapNotify",
1015     "ClientMessage",
1016     "MappingNotify"
1017 pcg 1.1 };
1018     #endif
1019    
1020     #ifdef DEBUG_X
1021 pcg 1.36 struct timeval tp;
1022     struct tm *ltt;
1023 pcg 1.43 (void)gettimeofday (&tp, NULL);
1024     ltt = localtime (& (tp.tv_sec));
1025     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));
1026 pcg 1.1 #endif
1027    
1028 pcg 1.38 switch (ev.type)
1029 pcg 1.36 {
1030     case KeyPress:
1031 pcg 1.38 lookup_key (ev.xkey);
1032 pcg 1.36 break;
1033 pcg 1.1
1034     #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
1035 pcg 1.36 case KeyRelease:
1036     {
1037 root 1.97 if (!(ev.xkey.state & ControlMask))
1038     slip_wheel_ev.stop ();
1039 pcg 1.36 else
1040     {
1041 root 1.97 KeySym ks;
1042 pcg 1.36
1043 pcg 1.43 ks = XKeycodeToKeysym (display->display, ev.xkey.keycode, 0);
1044 pcg 1.36 if (ks == XK_Control_L || ks == XK_Control_R)
1045     mouse_slip_wheel_speed = 0;
1046     }
1047     break;
1048     }
1049     #endif
1050    
1051     case ButtonPress:
1052 pcg 1.38 button_press (ev.xbutton);
1053 pcg 1.36 break;
1054    
1055     case ButtonRelease:
1056 pcg 1.38 button_release (ev.xbutton);
1057 pcg 1.36 break;
1058    
1059     case ClientMessage:
1060 pcg 1.38 if (ev.xclient.format == 32
1061     && (Atom)ev.xclient.data.l[0] == xa[XA_WMDELETEWINDOW])
1062 pcg 1.34 destroy ();
1063 pcg 1.1 #ifdef OFFIX_DND
1064 pcg 1.36 /* OffiX Dnd (drag 'n' drop) protocol */
1065 pcg 1.38 else if (ev.xclient.message_type == xa[XA_DNDPROTOCOL]
1066     && (ev.xclient.data.l[0] == DndFile
1067     || ev.xclient.data.l[0] == DndDir
1068     || ev.xclient.data.l[0] == DndLink))
1069 pcg 1.36 {
1070     /* Get Dnd data */
1071 pcg 1.93 Atom ActualType;
1072     int ActualFormat;
1073     unsigned char *data;
1074     unsigned long Size, RemainingBytes;
1075 pcg 1.36
1076 pcg 1.43 XGetWindowProperty (display->display, display->root,
1077 pcg 1.36 xa[XA_DNDSELECTION],
1078     0L, 1000000L,
1079     False, AnyPropertyType,
1080     &ActualType, &ActualFormat,
1081     &Size, &RemainingBytes,
1082     &data);
1083 pcg 1.43 XChangeProperty (display->display, display->root,
1084 pcg 1.36 XA_CUT_BUFFER0, XA_STRING,
1085     8, PropModeReplace,
1086 pcg 1.43 data, STRLEN (data));
1087 pcg 1.93 XFree (data);
1088 pcg 1.38 selection_paste (display->root, XA_CUT_BUFFER0, True);
1089 pcg 1.43 XSetInputFocus (display->display, display->root, RevertToNone, CurrentTime);
1090 pcg 1.36 }
1091 pcg 1.1 #endif /* OFFIX_DND */
1092 pcg 1.36 break;
1093 pcg 1.1
1094 pcg 1.36 case MappingNotify:
1095 root 1.116 XRefreshKeyboardMapping (&ev.xmapping);
1096 pcg 1.36 break;
1097    
1098     /*
1099     * XXX: this is not the _current_ arrangement
1100     * Here's my conclusion:
1101     * If the window is completely unobscured, use bitblt's
1102     * to scroll. Even then, they're only used when doing partial
1103     * screen scrolling. When partially obscured, we have to fill
1104     * in the GraphicsExpose parts, which means that after each refresh,
1105     * we need to wait for the graphics expose or Noexpose events,
1106     * which ought to make things real slow!
1107     */
1108     case VisibilityNotify:
1109 pcg 1.38 switch (ev.xvisibility.state)
1110 pcg 1.8 {
1111     case VisibilityUnobscured:
1112 pcg 1.34 refresh_type = FAST_REFRESH;
1113 pcg 1.8 break;
1114     case VisibilityPartiallyObscured:
1115 pcg 1.34 refresh_type = SLOW_REFRESH;
1116 pcg 1.8 break;
1117     default:
1118 pcg 1.34 refresh_type = NO_REFRESH;
1119 pcg 1.8 break;
1120     }
1121 pcg 1.36 break;
1122 pcg 1.1
1123 pcg 1.36 case FocusIn:
1124     if (!TermWin.focus)
1125     {
1126     TermWin.focus = 1;
1127     want_refresh = 1;
1128 pcg 1.1 #ifdef USE_XIM
1129 pcg 1.36 if (Input_Context != NULL)
1130 pcg 1.43 XSetICFocus (Input_Context);
1131 pcg 1.1 #endif
1132 pcg 1.5 #ifdef CURSOR_BLINK
1133 pcg 1.34 if (Options & Opt_cursorBlink)
1134     cursor_blink_ev.start (NOW + BLINK_INTERVAL);
1135 pcg 1.5 #endif
1136 root 1.107 #ifdef OFF_FOCUS_FADING
1137     if (rs[Rs_fade])
1138     {
1139     PixColors = PixColorsFocused;
1140     set_colorfgbg ();
1141     scr_clear ();
1142     scr_touch (true);
1143     }
1144     #endif
1145 pcg 1.1
1146 pcg 1.36 }
1147     break;
1148    
1149     case FocusOut:
1150     if (TermWin.focus)
1151     {
1152     TermWin.focus = 0;
1153     want_refresh = 1;
1154 pcg 1.1 #ifdef USE_XIM
1155 pcg 1.36 if (Input_Context != NULL)
1156 pcg 1.43 XUnsetICFocus (Input_Context);
1157 pcg 1.5 #endif
1158     #ifdef CURSOR_BLINK
1159 pcg 1.34 if (Options & Opt_cursorBlink)
1160     cursor_blink_ev.stop ();
1161     hidden_cursor = 0;
1162 pcg 1.1 #endif
1163 root 1.107 #ifdef OFF_FOCUS_FADING
1164     if (rs[Rs_fade])
1165     {
1166     PixColors = PixColorsUnFocused;
1167     set_colorfgbg ();
1168     scr_clear ();
1169     scr_touch (true);
1170     }
1171     #endif
1172 pcg 1.1
1173 pcg 1.36 }
1174     break;
1175    
1176     case ConfigureNotify:
1177 pcg 1.38 if (ev.xconfigure.window == TermWin.parent[0])
1178 pcg 1.36 {
1179 pcg 1.38 int height, width;
1180 pcg 1.36
1181     do
1182     { /* Wrap lots of configures into one */
1183 pcg 1.38 width = ev.xconfigure.width;
1184     height = ev.xconfigure.height;
1185 pcg 1.43 D_SIZE ((stderr, "Size: ConfigureNotify: %4d x %4d", width, height));
1186 pcg 1.36 }
1187 pcg 1.43 while (XCheckTypedWindowEvent (display->display, ev.xconfigure.window, ConfigureNotify, &ev));
1188 pcg 1.38
1189 pcg 1.36 if (szHint.width != width || szHint.height != height)
1190 root 1.116 resize_all_windows (width, height, 1);
1191    
1192 pcg 1.1 #ifdef TRANSPARENT /* XXX: maybe not needed - leave in for now */
1193 pcg 1.36 if (Options & Opt_transparent)
1194     {
1195     check_our_parents ();
1196     if (am_transparent)
1197     want_full_refresh = 1;
1198     }
1199     #endif
1200     }
1201     break;
1202    
1203     case SelectionClear:
1204 pcg 1.81 selection_clear ();
1205 pcg 1.36 break;
1206    
1207     case SelectionNotify:
1208     if (selection_wait == Sel_normal)
1209 pcg 1.38 selection_paste (ev.xselection.requestor,
1210     ev.xselection.property, True);
1211 pcg 1.36 break;
1212    
1213     case SelectionRequest:
1214 pcg 1.38 selection_send (ev.xselectionrequest);
1215 pcg 1.36 break;
1216 pcg 1.1
1217 pcg 1.36 case UnmapNotify:
1218     TermWin.mapped = 0;
1219 pcg 1.31 #ifdef TEXT_BLINK
1220 pcg 1.34 text_blink_ev.stop ();
1221 pcg 1.31 #endif
1222 pcg 1.36 break;
1223 pcg 1.1
1224 pcg 1.36 case MapNotify:
1225     TermWin.mapped = 1;
1226 pcg 1.31 #ifdef TEXT_BLINK
1227 pcg 1.34 text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL);
1228 pcg 1.31 #endif
1229 pcg 1.36 break;
1230 pcg 1.1
1231     #ifdef TRANSPARENT
1232 pcg 1.36 case ReparentNotify:
1233 pcg 1.38 rootwin_cb (ev);
1234     break;
1235 pcg 1.1 #endif /* TRANSPARENT */
1236    
1237 pcg 1.36 case GraphicsExpose:
1238     case Expose:
1239 pcg 1.38 if (ev.xany.window == TermWin.vt)
1240 pcg 1.36 {
1241 root 1.116 do
1242     scr_expose (ev.xexpose.x, ev.xexpose.y,
1243     ev.xexpose.width, ev.xexpose.height, False);
1244     while (XCheckTypedWindowEvent (display->display, TermWin.vt, ev.xany.type, &ev));
1245    
1246     ev.xany.type = ev.xany.type == Expose ? GraphicsExpose : Expose;
1247    
1248     while (XCheckTypedWindowEvent (display->display, TermWin.vt, ev.xany.type, &ev))
1249     scr_expose (ev.xexpose.x, ev.xexpose.y,
1250     ev.xexpose.width, ev.xexpose.height, False);
1251    
1252     scr_refresh (refresh_type);
1253 pcg 1.36 }
1254     else
1255     {
1256 pcg 1.38 XEvent unused_event;
1257 pcg 1.36
1258 pcg 1.95 while (XCheckTypedWindowEvent (display->display, ev.xany.window, Expose, &unused_event))
1259     ;
1260     while (XCheckTypedWindowEvent (display->display, ev.xany.window, GraphicsExpose, &unused_event))
1261     ;
1262    
1263 pcg 1.43 if (isScrollbarWindow (ev.xany.window))
1264 pcg 1.36 {
1265 pcg 1.43 scrollBar.setIdle ();
1266 pcg 1.36 scrollbar_show (0);
1267     }
1268 pcg 1.1 #ifdef MENUBAR
1269 pcg 1.43 if (menubar_visible () && isMenuBarWindow (ev.xany.window))
1270 pcg 1.36 menubar_expose ();
1271 pcg 1.1 #endif
1272 root 1.116
1273     #ifdef TRANSPARENT
1274     if (am_transparent && ev.xany.window == TermWin.parent[0])
1275     XClearWindow (display->display, ev.xany.window);
1276     #endif
1277 pcg 1.36 }
1278     break;
1279    
1280     case MotionNotify:
1281 pcg 1.1 #ifdef POINTER_BLANK
1282 pcg 1.36 if (hidden_pointer)
1283     pointer_unblank ();
1284 pcg 1.1 #endif
1285     #if MENUBAR
1286 pcg 1.43 if (isMenuBarWindow (ev.xany.window))
1287 pcg 1.36 {
1288 pcg 1.56 menubar_control (ev.xbutton);
1289 pcg 1.36 break;
1290     }
1291     #endif
1292 pcg 1.43 if ((PrivateModes & PrivMode_mouse_report) && ! (bypass_keystate))
1293 pcg 1.36 break;
1294    
1295 pcg 1.38 if (ev.xany.window == TermWin.vt)
1296 pcg 1.36 {
1297 pcg 1.38 if ((ev.xbutton.state & (Button1Mask | Button3Mask)))
1298 pcg 1.36 {
1299 pcg 1.38 while (XCheckTypedWindowEvent (display->display, TermWin.vt, MotionNotify, &ev))
1300     ;
1301    
1302 pcg 1.43 XQueryPointer (display->display, TermWin.vt,
1303 pcg 1.36 &unused_root, &unused_child,
1304     &unused_root_x, &unused_root_y,
1305 pcg 1.43 & (ev.xbutton.x), & (ev.xbutton.y),
1306 pcg 1.36 &unused_mask);
1307 pcg 1.1 #ifdef MOUSE_THRESHOLD
1308 pcg 1.36 /* deal with a `jumpy' mouse */
1309 pcg 1.38 if ((ev.xmotion.time - MEvent.time) > MOUSE_THRESHOLD)
1310 pcg 1.36 {
1311 pcg 1.1 #endif
1312 pcg 1.38 selection_extend ((ev.xbutton.x), (ev.xbutton.y),
1313     (ev.xbutton.state & Button3Mask) ? 2 : 0);
1314 pcg 1.1 #ifdef SELECTION_SCROLLING
1315 pcg 1.38 if (ev.xbutton.y < TermWin.int_bwidth
1316 pcg 1.43 || Pixel2Row (ev.xbutton.y) > (TermWin.nrow-1))
1317 pcg 1.36 {
1318     int dist;
1319    
1320     /* don't clobber the current delay if we are
1321     * already in the middle of scrolling.
1322     */
1323 root 1.97 if (!sel_scroll_ev.active)
1324     sel_scroll_ev.start (NOW + SCROLLBAR_INITIAL_DELAY);
1325 pcg 1.36
1326     /* save the event params so we can highlight
1327     * the selection in the pending-scroll loop
1328     */
1329 pcg 1.38 selection_save_x=ev.xbutton.x;
1330     selection_save_y=ev.xbutton.y;
1331 pcg 1.36 selection_save_state=
1332 pcg 1.38 (ev.xbutton.state & Button3Mask) ? 2 : 0;
1333 pcg 1.36
1334     /* calc number of lines to scroll */
1335 pcg 1.38 if (ev.xbutton.y<TermWin.int_bwidth)
1336 pcg 1.36 {
1337     scroll_selection_dir = UP;
1338 pcg 1.38 dist = TermWin.int_bwidth - ev.xbutton.y;
1339 pcg 1.36 }
1340     else
1341     {
1342     scroll_selection_dir = DN;
1343 pcg 1.38 dist = ev.xbutton.y -
1344 pcg 1.36 (TermWin.int_bwidth + TermWin.height);
1345     }
1346 pcg 1.43 scroll_selection_lines= (Pixel2Height (dist)/
1347 pcg 1.36 SELECTION_SCROLL_LINE_SPEEDUP)+1;
1348 pcg 1.43 MIN_IT (scroll_selection_lines,
1349 pcg 1.36 SELECTION_SCROLL_MAX_LINES);
1350     }
1351     else
1352     {
1353     /* we are within the text window, so we
1354     * shouldn't be scrolling
1355     */
1356 root 1.97 if (sel_scroll_ev.active)
1357     sel_scroll_ev.stop();
1358 pcg 1.36 }
1359 pcg 1.1 #endif
1360     #ifdef MOUSE_THRESHOLD
1361 pcg 1.36
1362     }
1363 pcg 1.1 #endif
1364 pcg 1.36
1365     }
1366     }
1367 pcg 1.43 else if (isScrollbarWindow (ev.xany.window) && scrollbar_isMotion ())
1368 pcg 1.36 {
1369 pcg 1.43 while (XCheckTypedWindowEvent (display->display, scrollBar.win,
1370 pcg 1.38 MotionNotify, &ev)) ;
1371 pcg 1.43 XQueryPointer (display->display, scrollBar.win,
1372 pcg 1.36 &unused_root, &unused_child,
1373     &unused_root_x, &unused_root_y,
1374 pcg 1.43 & (ev.xbutton.x), & (ev.xbutton.y),
1375 pcg 1.36 &unused_mask);
1376 pcg 1.43 scr_move_to (scrollbar_position (ev.xbutton.y) - csrO,
1377     scrollbar_size ());
1378 pcg 1.36 scr_refresh (refresh_type);
1379     refresh_limit = 0;
1380     scrollbar_show (1);
1381     }
1382     break;
1383     }
1384     }
1385 pcg 1.1
1386     void
1387 pcg 1.38 rxvt_term::rootwin_cb (XEvent &ev)
1388     {
1389     SET_R (this);
1390     SET_LOCALE (locale);
1391    
1392 pcg 1.40 switch (ev.type)
1393 pcg 1.38 {
1394 pcg 1.40 case PropertyNotify:
1395     if (ev.xproperty.atom == xa[XA_VT_SELECTION])
1396     {
1397     if (ev.xproperty.state == PropertyNewValue)
1398     selection_property (ev.xproperty.window, ev.xproperty.atom);
1399     break;
1400     }
1401     #ifdef TRANSPARENT
1402     else
1403     {
1404     /*
1405     * if user used some Esetroot compatible prog to set the root bg,
1406     * use the property to determine the pixmap. We use it later on.
1407     */
1408     if (xa[XA_XROOTPMAPID] == 0)
1409 pcg 1.43 xa[XA_XROOTPMAPID] = XInternAtom (display->display, "_XROOTPMAP_ID", False);
1410 pcg 1.38
1411 pcg 1.40 if (ev.xproperty.atom != xa[XA_XROOTPMAPID])
1412     return;
1413     }
1414 pcg 1.38
1415 pcg 1.40 /* FALLTHROUGH */
1416     case ReparentNotify:
1417 pcg 1.90 if ((Options & Opt_transparent) && check_our_parents () && am_transparent)
1418     want_full_refresh = 1;
1419 pcg 1.40 break;
1420     #endif
1421 pcg 1.38 }
1422     }
1423    
1424     void
1425 pcg 1.56 rxvt_term::button_press (XButtonEvent &ev)
1426 pcg 1.1 {
1427 pcg 1.36 int reportmode = 0, clickintime;
1428 pcg 1.1
1429 pcg 1.38 bypass_keystate = ev.state & (ModMetaMask | ShiftMask);
1430 pcg 1.36 if (!bypass_keystate)
1431 pcg 1.43 reportmode = !! (PrivateModes & PrivMode_mouse_report);
1432 pcg 1.36 /*
1433     * VT window processing of button press
1434     */
1435 pcg 1.38 if (ev.window == TermWin.vt)
1436 pcg 1.36 {
1437 pcg 1.50 clickintime = ev.time - MEvent.time < MULTICLICK_TIME;
1438     if (reportmode)
1439 pcg 1.36 {
1440 pcg 1.50 /* mouse report from vt window */
1441     /* save the xbutton state (for ButtonRelease) */
1442     MEvent.state = ev.state;
1443     #ifdef MOUSE_REPORT_DOUBLECLICK
1444     if (ev.button == MEvent.button && clickintime)
1445 pcg 1.36 {
1446 pcg 1.50 /* same button, within alloted time */
1447     MEvent.clicks++;
1448     if (MEvent.clicks > 1)
1449 pcg 1.36 {
1450 pcg 1.50 /* only report double clicks */
1451     MEvent.clicks = 2;
1452 pcg 1.36 mouse_report (ev);
1453 pcg 1.50
1454     /* don't report the release */
1455     MEvent.clicks = 0;
1456     MEvent.button = AnyButton;
1457 pcg 1.36 }
1458 pcg 1.50 }
1459     else
1460     {
1461     /* different button, or time expired */
1462     MEvent.clicks = 1;
1463 pcg 1.38 MEvent.button = ev.button;
1464 pcg 1.36 mouse_report (ev);
1465 pcg 1.50 }
1466     #else
1467     MEvent.button = ev.button;
1468     mouse_report (ev);
1469 pcg 1.1 #endif /* MOUSE_REPORT_DOUBLECLICK */
1470 pcg 1.36
1471 pcg 1.50 }
1472     else
1473     {
1474     if (ev.button != MEvent.button)
1475     MEvent.clicks = 0;
1476     switch (ev.button)
1477 pcg 1.36 {
1478 pcg 1.50 case Button1:
1479     /* allow shift+left click to extend selection */
1480     if (ev.state & ShiftMask && ! (PrivateModes & PrivMode_mouse_report))
1481     {
1482     if (MEvent.button == Button1 && clickintime)
1483     selection_rotate (ev.x, ev.y);
1484     else
1485     selection_extend (ev.x, ev.y, 1);
1486     }
1487     else
1488     {
1489     if (MEvent.button == Button1 && clickintime)
1490     MEvent.clicks++;
1491 pcg 1.36 else
1492 pcg 1.50 MEvent.clicks = 1;
1493 pcg 1.21
1494 pcg 1.50 selection_click (MEvent.clicks, ev.x, ev.y);
1495     }
1496 pcg 1.21
1497 pcg 1.50 MEvent.button = Button1;
1498     break;
1499 pcg 1.1
1500 pcg 1.50 case Button3:
1501     if (MEvent.button == Button3 && clickintime)
1502     selection_rotate (ev.x, ev.y);
1503     else
1504     selection_extend (ev.x, ev.y, 1);
1505     MEvent.button = Button3;
1506     break;
1507 pcg 1.36 }
1508     }
1509 pcg 1.50 MEvent.time = ev.time;
1510     return;
1511 pcg 1.36 }
1512 pcg 1.1
1513 pcg 1.36 /*
1514     * Scrollbar window processing of button press
1515     */
1516 pcg 1.43 if (isScrollbarWindow (ev.window))
1517 pcg 1.36 {
1518     scrollBar.setIdle ();
1519     /*
1520     * Rxvt-style scrollbar:
1521     * move up if mouse is above slider
1522     * move dn if mouse is below slider
1523     *
1524     * XTerm-style scrollbar:
1525     * Move display proportional to pointer location
1526     * pointer near top -> scroll one line
1527     * pointer near bot -> scroll full page
1528     */
1529 pcg 1.1 #ifndef NO_SCROLLBAR_REPORT
1530 pcg 1.36 if (reportmode)
1531     {
1532     /*
1533     * Mouse report disabled scrollbar:
1534     * arrow buttons - send up/down
1535     * click on scrollbar - send pageup/down
1536     */
1537     if ((scrollBar.style == R_SB_NEXT
1538 pcg 1.43 && scrollbarnext_upButton (ev.y))
1539 pcg 1.36 || (scrollBar.style == R_SB_RXVT
1540 pcg 1.43 && scrollbarrxvt_upButton (ev.y)))
1541     tt_printf ("\033[A");
1542 pcg 1.36 else if ((scrollBar.style == R_SB_NEXT
1543 pcg 1.43 && scrollbarnext_dnButton (ev.y))
1544 pcg 1.36 || (scrollBar.style == R_SB_RXVT
1545 pcg 1.43 && scrollbarrxvt_dnButton (ev.y)))
1546     tt_printf ("\033[B");
1547 pcg 1.36 else
1548 pcg 1.38 switch (ev.button)
1549 pcg 1.36 {
1550     case Button2:
1551 pcg 1.43 tt_printf ("\014");
1552 pcg 1.36 break;
1553     case Button1:
1554 pcg 1.43 tt_printf ("\033[6~");
1555 pcg 1.36 break;
1556     case Button3:
1557 pcg 1.43 tt_printf ("\033[5~");
1558 pcg 1.36 break;
1559     }
1560     }
1561     else
1562 pcg 1.1 #endif /* NO_SCROLLBAR_REPORT */
1563    
1564 pcg 1.36 {
1565     char upordown = 0;
1566    
1567     if (scrollBar.style == R_SB_NEXT)
1568     {
1569 pcg 1.43 if (scrollbarnext_upButton (ev.y))
1570 pcg 1.36 upordown = -1; /* up */
1571 pcg 1.43 else if (scrollbarnext_dnButton (ev.y))
1572 pcg 1.36 upordown = 1; /* down */
1573     }
1574     else if (scrollBar.style == R_SB_RXVT)
1575     {
1576 pcg 1.43 if (scrollbarrxvt_upButton (ev.y))
1577 pcg 1.36 upordown = -1; /* up */
1578 pcg 1.43 else if (scrollbarrxvt_dnButton (ev.y))
1579 pcg 1.36 upordown = 1; /* down */
1580     }
1581     if (upordown)
1582     {
1583 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1584 root 1.97 cont_scroll_ev.start (NOW + SCROLLBAR_INITIAL_DELAY);
1585 pcg 1.1 #endif
1586 pcg 1.36 if (scr_page (upordown < 0 ? UP : DN, 1))
1587     {
1588     if (upordown < 0)
1589     scrollBar.setUp ();
1590     else
1591     scrollBar.setDn ();
1592     }
1593     }
1594     else
1595 pcg 1.38 switch (ev.button)
1596 pcg 1.36 {
1597     case Button2:
1598     switch (scrollbar_align)
1599     {
1600     case R_SB_ALIGN_TOP:
1601     csrO = 0;
1602     break;
1603     case R_SB_ALIGN_CENTRE:
1604     csrO = (scrollBar.bot - scrollBar.top) / 2;
1605     break;
1606     case R_SB_ALIGN_BOTTOM:
1607     csrO = scrollBar.bot - scrollBar.top;
1608     break;
1609     }
1610     if (scrollBar.style == R_SB_XTERM
1611 pcg 1.43 || scrollbar_above_slider (ev.y)
1612     || scrollbar_below_slider (ev.y))
1613     scr_move_to ( scrollbar_position (ev.y) - csrO,
1614     scrollbar_size ());
1615 pcg 1.36 scrollBar.setMotion ();
1616     break;
1617    
1618     case Button1:
1619     if (scrollbar_align == R_SB_ALIGN_CENTRE)
1620 pcg 1.38 csrO = ev.y - scrollBar.top;
1621 pcg 1.36 /* FALLTHROUGH */
1622    
1623     case Button3:
1624     if (scrollBar.style != R_SB_XTERM)
1625     {
1626 pcg 1.43 if (scrollbar_above_slider (ev.y))
1627 pcg 1.1 # ifdef RXVT_SCROLL_FULL
1628 pcg 1.36 scr_page (UP, TermWin.nrow - 1);
1629 pcg 1.1 # else
1630 pcg 1.36 scr_page (UP, TermWin.nrow / 4);
1631 pcg 1.1 # endif
1632 pcg 1.43 else if (scrollbar_below_slider (ev.y))
1633 pcg 1.1 # ifdef RXVT_SCROLL_FULL
1634 pcg 1.36 scr_page (DN, TermWin.nrow - 1);
1635 pcg 1.1 # else
1636 pcg 1.36 scr_page (DN, TermWin.nrow / 4);
1637 pcg 1.1 # endif
1638 pcg 1.36 else
1639     scrollBar.setMotion ();
1640     }
1641     else
1642     {
1643 pcg 1.38 scr_page ((ev.button == Button1 ? DN : UP),
1644 pcg 1.36 (TermWin.nrow
1645 pcg 1.43 * scrollbar_position (ev.y)
1646     / scrollbar_size ()));
1647 pcg 1.36 }
1648     break;
1649     }
1650     }
1651     return;
1652 pcg 1.1 }
1653     #if MENUBAR
1654 pcg 1.36 /*
1655     * Menubar window processing of button press
1656     */
1657 pcg 1.43 if (isMenuBarWindow (ev.window))
1658 pcg 1.36 menubar_control (ev);
1659 pcg 1.1 #endif
1660     }
1661    
1662     void
1663 pcg 1.56 rxvt_term::button_release (XButtonEvent &ev)
1664 pcg 1.1 {
1665 pcg 1.38 int reportmode = 0;
1666 pcg 1.1
1667 pcg 1.36 csrO = 0; /* reset csr Offset */
1668     if (!bypass_keystate)
1669 pcg 1.43 reportmode = !! (PrivateModes & PrivMode_mouse_report);
1670 pcg 1.36
1671 pcg 1.43 if (scrollbar_isUpDn ())
1672 pcg 1.36 {
1673     scrollBar.setIdle ();
1674     scrollbar_show (0);
1675 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1676 pcg 1.36 refresh_type &= ~SMOOTH_REFRESH;
1677 pcg 1.1 #endif
1678 pcg 1.36
1679 pcg 1.1 }
1680     #ifdef SELECTION_SCROLLING
1681 root 1.97 if (sel_scroll_ev.active)
1682     sel_scroll_ev.stop();
1683 pcg 1.1 #endif
1684 pcg 1.38 if (ev.window == TermWin.vt)
1685 pcg 1.36 {
1686 pcg 1.50 if (reportmode)
1687 pcg 1.36 {
1688 pcg 1.50 /* mouse report from vt window */
1689     /* don't report release of wheel "buttons" */
1690     if (ev.button >= 4)
1691     return;
1692     #ifdef MOUSE_REPORT_DOUBLECLICK
1693     /* only report the release of 'slow' single clicks */
1694     if (MEvent.button != AnyButton
1695     && (ev.button != MEvent.button
1696     || (ev.time - MEvent.time
1697     > MULTICLICK_TIME / 2)))
1698 pcg 1.36 {
1699 pcg 1.50 MEvent.clicks = 0;
1700 pcg 1.36 MEvent.button = AnyButton;
1701     mouse_report (ev);
1702 pcg 1.50 }
1703     #else /* MOUSE_REPORT_DOUBLECLICK */
1704     MEvent.button = AnyButton;
1705     mouse_report (ev);
1706 pcg 1.1 #endif /* MOUSE_REPORT_DOUBLECLICK */
1707 pcg 1.50 return;
1708     }
1709     /*
1710     * dumb hack to compensate for the failure of click-and-drag
1711     * when overriding mouse reporting
1712     */
1713     if (PrivateModes & PrivMode_mouse_report
1714     && bypass_keystate
1715     && ev.button == Button1 && MEvent.clicks <= 1)
1716     selection_extend (ev.x, ev.y, 0);
1717    
1718     switch (ev.button)
1719     {
1720     case Button1:
1721     case Button3:
1722     selection_make (ev.time);
1723     break;
1724     case Button2:
1725     selection_request (ev.time, ev.x, ev.y);
1726     break;
1727     #ifdef MOUSE_WHEEL
1728     case Button4:
1729     case Button5:
1730 pcg 1.36 {
1731 pcg 1.50 int i;
1732     page_dirn v;
1733 pcg 1.36
1734 root 1.97 v = ev.button == Button4 ? UP : DN;
1735    
1736 pcg 1.50 if (ev.state & ShiftMask)
1737     i = 1;
1738 root 1.97 else if (Options & Opt_mouseWheelScrollPage)
1739 pcg 1.50 i = TermWin.nrow - 1;
1740     else
1741     i = 5;
1742 root 1.97
1743 pcg 1.1 # ifdef MOUSE_SLIP_WHEELING
1744 pcg 1.50 if (ev.state & ControlMask)
1745     {
1746 root 1.97 mouse_slip_wheel_speed += v ? -1 : 1;
1747 root 1.107 if (mouse_slip_wheel_speed < -TermWin.nrow) mouse_slip_wheel_speed = -TermWin.nrow;
1748     if (mouse_slip_wheel_speed > +TermWin.nrow) mouse_slip_wheel_speed = +TermWin.nrow;
1749    
1750     if (slip_wheel_ev.at < NOW)
1751     slip_wheel_ev.at = NOW + SCROLLBAR_CONTINUOUS_DELAY;
1752    
1753     slip_wheel_ev.start ();
1754 pcg 1.50 }
1755 root 1.107 else
1756     {
1757 pcg 1.1 # endif
1758     # ifdef JUMP_MOUSE_WHEEL
1759 root 1.107 scr_page (v, i);
1760 pcg 1.36 scr_refresh (SMOOTH_REFRESH);
1761     scrollbar_show (1);
1762 root 1.107 # else
1763     while (i--)
1764     {
1765     scr_page (v, 1);
1766     scr_refresh (SMOOTH_REFRESH);
1767     scrollbar_show (1);
1768     }
1769     # endif
1770     # ifdef MOUSE_SLIP_WHEELING
1771 pcg 1.50 }
1772 root 1.107 #endif
1773 pcg 1.50 }
1774     break;
1775 pcg 1.1 #endif
1776 pcg 1.36 }
1777     }
1778 pcg 1.1 #ifdef MENUBAR
1779 pcg 1.43 else if (isMenuBarWindow (ev.window))
1780 pcg 1.36 menubar_control (ev);
1781 pcg 1.1 #endif
1782     }
1783    
1784 pcg 1.90 #ifdef TRANSPARENT
1785     #if TINTING
1786 root 1.116 /* taken from aterm-0.4.2 */
1787    
1788     typedef uint32_t RUINT32T;
1789 pcg 1.90
1790 root 1.116 void ShadeXImage(rxvt_display *display, XImage* srcImage, int shade, int rm, int gm, int bm)
1791 pcg 1.90 {
1792 root 1.116 int sh_r, sh_g, sh_b;
1793     RUINT32T mask_r, mask_g, mask_b;
1794     RUINT32T *lookup, *lookup_r, *lookup_g, *lookup_b;
1795     unsigned int lower_lim_r, lower_lim_g, lower_lim_b;
1796     unsigned int upper_lim_r, upper_lim_g, upper_lim_b;
1797     int i;
1798    
1799     Visual* visual = display->visual;
1800    
1801     if( visual->c_class != TrueColor || srcImage->format != ZPixmap ) return ;
1802    
1803     /* for convenience */
1804     mask_r = visual->red_mask;
1805     mask_g = visual->green_mask;
1806     mask_b = visual->blue_mask;
1807    
1808     /* boring lookup table pre-initialization */
1809     switch (srcImage->bits_per_pixel) {
1810     case 15:
1811     if ((mask_r != 0x7c00) ||
1812     (mask_g != 0x03e0) ||
1813     (mask_b != 0x001f))
1814     return;
1815     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(32+32+32));
1816     lookup_r = lookup;
1817     lookup_g = lookup+32;
1818     lookup_b = lookup+32+32;
1819     sh_r = 10;
1820     sh_g = 5;
1821     sh_b = 0;
1822     break;
1823     case 16:
1824     if ((mask_r != 0xf800) ||
1825     (mask_g != 0x07e0) ||
1826     (mask_b != 0x001f))
1827     return;
1828     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(32+64+32));
1829     lookup_r = lookup;
1830     lookup_g = lookup+32;
1831     lookup_b = lookup+32+64;
1832     sh_r = 11;
1833     sh_g = 5;
1834     sh_b = 0;
1835     break;
1836     case 24:
1837     if ((mask_r != 0xff0000) ||
1838     (mask_g != 0x00ff00) ||
1839     (mask_b != 0x0000ff))
1840     return;
1841     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(256+256+256));
1842     lookup_r = lookup;
1843     lookup_g = lookup+256;
1844     lookup_b = lookup+256+256;
1845     sh_r = 16;
1846     sh_g = 8;
1847     sh_b = 0;
1848     break;
1849     case 32:
1850     if ((mask_r != 0xff0000) ||
1851     (mask_g != 0x00ff00) ||
1852     (mask_b != 0x0000ff))
1853     return;
1854     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(256+256+256));
1855     lookup_r = lookup;
1856     lookup_g = lookup+256;
1857     lookup_b = lookup+256+256;
1858     sh_r = 16;
1859     sh_g = 8;
1860     sh_b = 0;
1861     break;
1862     default:
1863     return; /* we do not support this color depth */
1864     }
1865    
1866     /* prepare limits for color transformation (each channel is handled separately) */
1867     if (shade < 0) {
1868     shade = -shade;
1869     if (shade < 0) shade = 0;
1870     if (shade > 100) shade = 100;
1871    
1872     lower_lim_r = 65535-rm;
1873     lower_lim_g = 65535-gm;
1874     lower_lim_b = 65535-bm;
1875    
1876     lower_lim_r = 65535-(unsigned int)(((RUINT32T)lower_lim_r)*((RUINT32T)shade)/100);
1877     lower_lim_g = 65535-(unsigned int)(((RUINT32T)lower_lim_g)*((RUINT32T)shade)/100);
1878     lower_lim_b = 65535-(unsigned int)(((RUINT32T)lower_lim_b)*((RUINT32T)shade)/100);
1879    
1880     upper_lim_r = upper_lim_g = upper_lim_b = 65535;
1881     } else {
1882     if (shade < 0) shade = 0;
1883     if (shade > 100) shade = 100;
1884    
1885     lower_lim_r = lower_lim_g = lower_lim_b = 0;
1886    
1887     upper_lim_r = (unsigned int)((((RUINT32T)rm)*((RUINT32T)shade))/100);
1888     upper_lim_g = (unsigned int)((((RUINT32T)gm)*((RUINT32T)shade))/100);
1889     upper_lim_b = (unsigned int)((((RUINT32T)bm)*((RUINT32T)shade))/100);
1890     }
1891 pcg 1.90
1892 root 1.116 /* switch red and blue bytes if necessary, we need it for some weird XServers like XFree86 3.3.3.1 */
1893     if ((srcImage->bits_per_pixel == 24) && (mask_r >= 0xFF0000 ))
1894     {
1895     unsigned int tmp;
1896 pcg 1.90
1897 root 1.116 tmp = lower_lim_r;
1898     lower_lim_r = lower_lim_b;
1899     lower_lim_b = tmp;
1900    
1901     tmp = upper_lim_r;
1902     upper_lim_r = upper_lim_b;
1903     upper_lim_b = tmp;
1904     }
1905 pcg 1.90
1906 root 1.116 /* fill our lookup tables */
1907     for (i = 0; i <= mask_r>>sh_r; i++)
1908     {
1909     RUINT32T tmp;
1910     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_r-lower_lim_r));
1911     tmp += ((RUINT32T)(mask_r>>sh_r))*((RUINT32T)lower_lim_r);
1912     lookup_r[i] = (tmp/65535)<<sh_r;
1913     }
1914     for (i = 0; i <= mask_g>>sh_g; i++)
1915     {
1916     RUINT32T tmp;
1917     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_g-lower_lim_g));
1918     tmp += ((RUINT32T)(mask_g>>sh_g))*((RUINT32T)lower_lim_g);
1919     lookup_g[i] = (tmp/65535)<<sh_g;
1920     }
1921     for (i = 0; i <= mask_b>>sh_b; i++)
1922     {
1923     RUINT32T tmp;
1924     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_b-lower_lim_b));
1925     tmp += ((RUINT32T)(mask_b>>sh_b))*((RUINT32T)lower_lim_b);
1926     lookup_b[i] = (tmp/65535)<<sh_b;
1927     }
1928 pcg 1.90
1929 root 1.116 /* apply table to input image (replacing colors by newly calculated ones) */
1930     switch (srcImage->bits_per_pixel)
1931     {
1932     case 15:
1933     {
1934     unsigned short *p1, *pf, *p, *pl;
1935     p1 = (unsigned short *) srcImage->data;
1936     pf = (unsigned short *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1937     while (p1 < pf)
1938     {
1939     p = p1;
1940     pl = p1 + srcImage->width;
1941     for (; p < pl; p++)
1942     {
1943     *p = lookup_r[(*p & 0x7c00)>>10] |
1944     lookup_g[(*p & 0x03e0)>> 5] |
1945     lookup_b[(*p & 0x001f)];
1946     }
1947     p1 = (unsigned short *) ((char *) p1 + srcImage->bytes_per_line);
1948     }
1949     break;
1950     }
1951     case 16:
1952     {
1953     unsigned short *p1, *pf, *p, *pl;
1954     p1 = (unsigned short *) srcImage->data;
1955     pf = (unsigned short *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1956     while (p1 < pf)
1957     {
1958     p = p1;
1959     pl = p1 + srcImage->width;
1960     for (; p < pl; p++)
1961     {
1962     *p = lookup_r[(*p & 0xf800)>>11] |
1963     lookup_g[(*p & 0x07e0)>> 5] |
1964     lookup_b[(*p & 0x001f)];
1965     }
1966     p1 = (unsigned short *) ((char *) p1 + srcImage->bytes_per_line);
1967     }
1968     break;
1969     }
1970     case 24:
1971     {
1972     unsigned char *p1, *pf, *p, *pl;
1973     p1 = (unsigned char *) srcImage->data;
1974     pf = (unsigned char *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1975     while (p1 < pf)
1976     {
1977     p = p1;
1978     pl = p1 + srcImage->width * 3;
1979     for (; p < pl; p += 3)
1980     {
1981     p[0] = lookup_r[(p[0] & 0xff0000)>>16];
1982     p[1] = lookup_r[(p[1] & 0x00ff00)>> 8];
1983     p[2] = lookup_r[(p[2] & 0x0000ff)];
1984     }
1985     p1 = (unsigned char *) ((char *) p1 + srcImage->bytes_per_line);
1986     }
1987     break;
1988     }
1989     case 32:
1990     {
1991     RUINT32T *p1, *pf, *p, *pl;
1992     p1 = (RUINT32T *) srcImage->data;
1993     pf = (RUINT32T *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1994    
1995     while (p1 < pf)
1996     {
1997     p = p1;
1998     pl = p1 + srcImage->width;
1999     for (; p < pl; p++)
2000     {
2001     *p = lookup_r[(*p & 0xff0000)>>16] |
2002     lookup_g[(*p & 0x00ff00)>> 8] |
2003     lookup_b[(*p & 0x0000ff)] |
2004     (*p & ~0xffffff);
2005     }
2006     p1 = (RUINT32T *) ((char *) p1 + srcImage->bytes_per_line);
2007     }
2008     break;
2009 pcg 1.90 }
2010 root 1.116 }
2011    
2012     free (lookup);
2013 pcg 1.90 }
2014     #endif
2015 pcg 1.1
2016     /*
2017     * Check our parents are still who we think they are.
2018     * Do transparency updates if required
2019     */
2020     int
2021 pcg 1.34 rxvt_term::check_our_parents ()
2022 pcg 1.1 {
2023 pcg 1.90 int i, pchanged, aformat, have_pixmap, rootdepth;
2024     unsigned long nitems, bytes_after;
2025     Atom atype;
2026     unsigned char *prop = NULL;
2027     Window root, oldp, *list;
2028     Pixmap rootpixmap = None;
2029 pcg 1.36 XWindowAttributes wattr, wrootattr;
2030    
2031     pchanged = 0;
2032    
2033 pcg 1.90 if (!(Options & Opt_transparent))
2034 pcg 1.36 return pchanged; /* Don't try any more */
2035    
2036 pcg 1.43 XGetWindowAttributes (display->display, display->root, &wrootattr);
2037 pcg 1.36 rootdepth = wrootattr.depth;
2038    
2039 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
2040 pcg 1.90
2041 pcg 1.36 if (rootdepth != wattr.depth)
2042     {
2043     if (am_transparent)
2044     {
2045     pchanged = 1;
2046 root 1.107 XSetWindowBackground (display->display, TermWin.vt, PixColorsFocused[Color_bg]);
2047 pcg 1.36 am_transparent = am_pixmap_trans = 0;
2048     }
2049 pcg 1.90
2050 pcg 1.36 return pchanged; /* Don't try any more */
2051 pcg 1.1 }
2052    
2053 pcg 1.36 /* Get all X ops out of the queue so that our information is up-to-date. */
2054 pcg 1.43 XSync (display->display, False);
2055 pcg 1.1
2056 pcg 1.36 /*
2057     * Make the frame window set by the window manager have
2058     * the root background. Some window managers put multiple nested frame
2059     * windows for each client, so we have to take care about that.
2060     */
2061 pcg 1.90 i = (xa[XA_XROOTPMAPID]
2062     && XGetWindowProperty (display->display, display->root, xa[XA_XROOTPMAPID],
2063 pcg 1.36 0L, 1L, False, XA_PIXMAP, &atype, &aformat,
2064 pcg 1.90 &nitems, &bytes_after, &prop) == Success);
2065    
2066     if (!i || prop == NULL)
2067     i = (xa[XA_XSETROOTID]
2068     && XGetWindowProperty (display->display, display->root, xa[XA_XSETROOTID],
2069     0L, 1L, False, XA_PIXMAP, &atype, &aformat,
2070     &nitems, &bytes_after, &prop) == Success);
2071    
2072 root 1.116 if (!i || prop == NULL
2073     #if TINTING
2074     || !rs[Rs_color + Color_tint]
2075     #endif
2076     )
2077 pcg 1.36 have_pixmap = 0;
2078     else
2079     {
2080     have_pixmap = 1;
2081 pcg 1.93 rootpixmap = *(Pixmap *)prop;
2082 pcg 1.43 XFree (prop);
2083 pcg 1.1 }
2084 pcg 1.90
2085 pcg 1.36 if (have_pixmap)
2086     {
2087     /*
2088 pcg 1.38 * Copy display->root pixmap transparency
2089 pcg 1.36 */
2090 pcg 1.67 int sx, sy, nx, ny;
2091     unsigned int nw, nh;
2092     Window cr;
2093     XImage *image;
2094     GC gc;
2095     XGCValues gcvalue;
2096 pcg 1.36
2097 root 1.116 XTranslateCoordinates (display->display, TermWin.parent[0], display->root,
2098 pcg 1.90 0, 0, &sx, &sy, &cr);
2099 pcg 1.36 nw = (unsigned int)szHint.width;
2100     nh = (unsigned int)szHint.height;
2101     nx = ny = 0;
2102 pcg 1.67
2103 pcg 1.36 if (sx < 0)
2104     {
2105     nw += sx;
2106     nx = -sx;
2107     sx = 0;
2108     }
2109 pcg 1.67
2110 pcg 1.36 if (sy < 0)
2111     {
2112     nh += sy;
2113     ny = -sy;
2114     sy = 0;
2115     }
2116 pcg 1.67
2117 pcg 1.43 MIN_IT (nw, (unsigned int) (wrootattr.width - sx));
2118     MIN_IT (nh, (unsigned int) (wrootattr.height - sy));
2119 pcg 1.36 allowedxerror = -1;
2120 pcg 1.90 image = XGetImage (display->display, rootpixmap, sx, sy, nw, nh, AllPlanes, ZPixmap);
2121    
2122 pcg 1.36 /* XXX: handle BadMatch - usually because we're outside the pixmap */
2123     /* XXX: may need a delay here? */
2124     allowedxerror = 0;
2125 pcg 1.90
2126 pcg 1.36 if (image == NULL)
2127     {
2128     if (am_transparent && am_pixmap_trans)
2129     {
2130     pchanged = 1;
2131     if (TermWin.pixmap != None)
2132     {
2133 pcg 1.43 XFreePixmap (display->display, TermWin.pixmap);
2134 pcg 1.36 TermWin.pixmap = None;
2135     }
2136     }
2137 pcg 1.90
2138 pcg 1.36 am_pixmap_trans = 0;
2139     }
2140     else
2141     {
2142     if (TermWin.pixmap != None)
2143 pcg 1.43 XFreePixmap (display->display, TermWin.pixmap);
2144 pcg 1.90
2145     #if TINTING
2146     if (ISSET_PIXCOLOR (Color_tint))
2147     {
2148 root 1.107 unsigned short rm, gm, bm;
2149 root 1.116 int shade = rs[Rs_shade] ? atoi (rs[Rs_shade]) : 100;
2150 pcg 1.90
2151 root 1.116 PixColorsFocused[Color_tint].get (display, rm, gm, bm);
2152 pcg 1.90
2153 root 1.116 ShadeXImage (display, image, shade, rm, gm, bm);
2154 pcg 1.90 }
2155     #endif
2156    
2157 pcg 1.43 TermWin.pixmap = XCreatePixmap (display->display, TermWin.vt,
2158 pcg 1.90 szHint.width, szHint.height, image->depth);
2159 pcg 1.43 gc = XCreateGC (display->display, TermWin.vt, 0UL, &gcvalue);
2160     XPutImage (display->display, TermWin.pixmap, gc, image, 0, 0,
2161 pcg 1.90 nx, ny, image->width, image->height);
2162 pcg 1.43 XFreeGC (display->display, gc);
2163     XDestroyImage (image);
2164 root 1.116 XSetWindowBackgroundPixmap (display->display, TermWin.parent[0], TermWin.pixmap);
2165     XClearWindow (display->display, TermWin.parent[0]);
2166 pcg 1.90
2167 pcg 1.36 if (!am_transparent || !am_pixmap_trans)
2168     pchanged = 1;
2169 pcg 1.90
2170 pcg 1.36 am_transparent = am_pixmap_trans = 1;
2171     }
2172 pcg 1.1 }
2173 pcg 1.67
2174 pcg 1.36 if (!am_pixmap_trans)
2175     {
2176 pcg 1.90 unsigned int n;
2177 pcg 1.36 /*
2178     * InheritPixmap transparency
2179     */
2180 pcg 1.43 D_X ((stderr, "InheritPixmap Seeking to %08lx", display->root));
2181 pcg 1.90 for (i = 1; i < (int) (sizeof (TermWin.parent) / sizeof (Window)); i++)
2182 pcg 1.36 {
2183     oldp = TermWin.parent[i];
2184 pcg 1.43 XQueryTree (display->display, TermWin.parent[i - 1], &root,
2185 pcg 1.90 &TermWin.parent[i], &list, &n);
2186 pcg 1.43 XFree (list);
2187     D_X ((stderr, "InheritPixmap Parent[%d] = %08lx", i, TermWin.parent[i]));
2188 pcg 1.90
2189 pcg 1.38 if (TermWin.parent[i] == display->root)
2190 pcg 1.36 {
2191     if (oldp != None)
2192     pchanged = 1;
2193 pcg 1.90
2194 pcg 1.36 break;
2195     }
2196 pcg 1.90
2197 pcg 1.36 if (oldp != TermWin.parent[i])
2198     pchanged = 1;
2199     }
2200 pcg 1.67
2201 pcg 1.36 n = 0;
2202 pcg 1.67
2203 pcg 1.36 if (pchanged)
2204     {
2205     for (; n < (unsigned int)i; n++)
2206     {
2207 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[n], &wattr);
2208     D_X ((stderr, "InheritPixmap Checking Parent[%d]: %s", n, (wattr.depth == rootdepth && wattr.class != InputOnly) ? "OK" : "FAIL"));
2209 pcg 1.36 if (wattr.depth != rootdepth || wattr.c_class == InputOnly)
2210     {
2211 pcg 1.43 n = (int) (sizeof (TermWin.parent) / sizeof (Window)) + 1;
2212 pcg 1.36 break;
2213     }
2214     }
2215     }
2216 pcg 1.67
2217 pcg 1.90 if (n > (int) (sizeof (TermWin.parent) / sizeof (TermWin.parent[0])))
2218 pcg 1.36 {
2219 root 1.116 D_X ((stderr, "InheritPixmap Turning off"));
2220 root 1.107 XSetWindowBackground (display->display, TermWin.parent[0], PixColorsFocused[Color_fg]);
2221     XSetWindowBackground (display->display, TermWin.vt, PixColorsFocused[Color_bg]);
2222 pcg 1.36 am_transparent = 0;
2223     /* XXX: also turn off Opt_transparent? */
2224     }
2225     else
2226     {
2227 pcg 1.90 #if WAIT_FOR_WM
2228 pcg 1.36 /* wait (an arbitrary period) for the WM to do its thing
2229     * needed for fvwm2.2.2 (and before?) */
2230 pcg 1.43 sleep (1);
2231 pcg 1.90 #endif
2232 pcg 1.43 D_X ((stderr, "InheritPixmap Turning on (%d parents)", i - 1));
2233 pcg 1.36 for (n = 0; n < (unsigned int)i; n++)
2234 root 1.116 {
2235     XSetWindowBackgroundPixmap (display->display, TermWin.parent[n], ParentRelative);
2236     XClearWindow (display->display, TermWin.parent[n]);
2237     }
2238 pcg 1.90
2239     XSetWindowBackgroundPixmap (display->display, TermWin.vt, ParentRelative);
2240 pcg 1.36 am_transparent = 1;
2241     }
2242 pcg 1.67
2243 pcg 1.43 for (; i < (int) (sizeof (TermWin.parent) / sizeof (Window)); i++)
2244 pcg 1.36 TermWin.parent[i] = None;
2245 pcg 1.1 }
2246 pcg 1.90
2247 root 1.116 // this is experimental
2248     if (scrollBar.win)
2249     {
2250     XSetWindowBackgroundPixmap (display->display, scrollBar.win, ParentRelative);
2251     XClearWindow (display->display, scrollBar.win);
2252     scrollBar.setIdle ();
2253     scrollbar_show (0);
2254     }
2255    
2256 pcg 1.36 return pchanged;
2257 pcg 1.1 }
2258     #endif
2259    
2260     /*}}} */
2261    
2262 pcg 1.81 bool
2263     rxvt_term::cmd_parse ()
2264     {
2265     bool flag = false;
2266     unicode_t ch = NOCHAR;
2267     unsigned char *seq_begin; // remember start of esc-sequence here
2268    
2269     for (;;)
2270     {
2271     if (ch == NOCHAR)
2272     {
2273     seq_begin = cmdbuf_ptr;
2274     ch = next_char ();
2275     }
2276    
2277     if (ch == NOCHAR) // TODO: improve
2278     break;
2279    
2280 pcg 1.93 if (!IS_CONTROL (ch) || ch == C0_LF || ch == C0_CR || ch == C0_HT)
2281 pcg 1.81 {
2282     /* Read a text string from the input buffer */
2283     unicode_t buf[UBUFSIZ];
2284     bool refreshnow = false;
2285     int nlines = 0;
2286     unicode_t *str = buf;
2287    
2288     *str++ = ch;
2289    
2290     for (;;)
2291     {
2292     seq_begin = cmdbuf_ptr;
2293     ch = next_char ();
2294    
2295 pcg 1.93 if (ch == NOCHAR || (IS_CONTROL (ch) && ch != C0_LF && ch != C0_CR && ch != C0_HT))
2296 pcg 1.81 break;
2297    
2298     *str++ = ch;
2299    
2300 pcg 1.93 if (ch == C0_LF)
2301 pcg 1.81 {
2302     nlines++;
2303     refresh_count++;
2304    
2305     if (! (Options & Opt_jumpScroll)
2306 root 1.116 || (refresh_count >= refresh_limit * (TermWin.nrow - 1)))
2307 pcg 1.81 {
2308     refreshnow = true;
2309     ch = NOCHAR;
2310     break;
2311     }
2312    
2313     // scr_add_lines only works for nlines < TermWin.nrow - 1.
2314     if (nlines >= TermWin.nrow - 1)
2315     {
2316     scr_add_lines (buf, nlines, str - buf);
2317     nlines = 0;
2318     str = buf;
2319     }
2320     }
2321    
2322     if (str >= buf + UBUFSIZ)
2323     {
2324     ch = NOCHAR;
2325     break;
2326     }
2327     }
2328    
2329     scr_add_lines (buf, nlines, str - buf);
2330    
2331     /*
2332     * If there have been a lot of new lines, then update the screen
2333     * What the heck I'll cheat and only refresh less than every page-full.
2334     * the number of pages between refreshes is refresh_limit, which
2335     * is incremented here because we must be doing flat-out scrolling.
2336     */
2337     if (refreshnow)
2338     {
2339     if ((Options & Opt_jumpScroll) && refresh_limit < REFRESH_PERIOD)
2340     refresh_limit++;
2341 pcg 1.93 else
2342 root 1.116 {
2343     flag = true;
2344     scr_refresh (refresh_type);
2345     }
2346 pcg 1.81 }
2347    
2348     }
2349     else
2350     {
2351     try
2352     {
2353     process_nonprinting (ch);
2354     }
2355     catch (const class out_of_input &o)
2356     {
2357     // we ran out of input, retry later
2358     cmdbuf_ptr = seq_begin;
2359     break;
2360     }
2361    
2362     ch = NOCHAR;
2363     }
2364     }
2365    
2366     return flag;
2367     }
2368    
2369 root 1.97 // read the next octet
2370     unicode_t
2371     rxvt_term::next_octet ()
2372     {
2373     return cmdbuf_ptr < cmdbuf_endp
2374     ? *cmdbuf_ptr++
2375     : NOCHAR;
2376     }
2377    
2378 pcg 1.81 // read the next character
2379     unicode_t
2380     rxvt_term::next_char ()
2381     {
2382     while (cmdbuf_ptr < cmdbuf_endp)
2383     {
2384     // assume 7-bit to be ascii ALWAYS
2385     if (*cmdbuf_ptr <= 0x7f && *cmdbuf_ptr != 0x1b)
2386     return *cmdbuf_ptr++;
2387    
2388     wchar_t wc;
2389     size_t len = mbrtowc (&wc, (char *)cmdbuf_ptr, cmdbuf_endp - cmdbuf_ptr, mbstate);
2390    
2391     if (len == (size_t)-2)
2392     {
2393     // the mbstate stores incomplete sequences. didn't know this :/
2394     cmdbuf_ptr = cmdbuf_endp;
2395     break;
2396     }
2397    
2398     if (len == (size_t)-1)
2399     return *cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
2400    
2401     // assume wchar == unicode
2402     cmdbuf_ptr += len;
2403     return wc;
2404     }
2405    
2406     return NOCHAR;
2407     }
2408    
2409     /* rxvt_cmd_getc () - Return next input character */
2410     /*
2411     * Return the next input character after first passing any keyboard input
2412     * to the command.
2413     */
2414     unicode_t
2415     rxvt_term::cmd_getc ()
2416     {
2417     unicode_t c = next_char ();
2418    
2419     if (c == NOCHAR)
2420     throw out_of_input;
2421    
2422     return c;
2423     }
2424    
2425 root 1.97 unicode_t
2426     rxvt_term::cmd_get8 ()
2427     {
2428     unicode_t c = next_octet ();
2429    
2430     if (c == NOCHAR)
2431     throw out_of_input;
2432    
2433     return c;
2434     }
2435    
2436 pcg 1.1 /*{{{ print pipe */
2437     /*----------------------------------------------------------------------*/
2438     #ifdef PRINTPIPE
2439 pcg 1.34 FILE *
2440     rxvt_term::popen_printer ()
2441 pcg 1.1 {
2442 pcg 1.67 FILE *stream = popen (rs[Rs_print_pipe], "w");
2443 pcg 1.1
2444 pcg 1.36 if (stream == NULL)
2445 pcg 1.81 rxvt_warn ("can't open printer pipe, not printing.\n");
2446    
2447 pcg 1.36 return stream;
2448 pcg 1.1 }
2449    
2450     int
2451 pcg 1.34 rxvt_term::pclose_printer (FILE *stream)
2452 pcg 1.1 {
2453 pcg 1.11 fflush (stream);
2454     return pclose (stream);
2455 pcg 1.1 }
2456    
2457     /*
2458     * simulate attached vt100 printer
2459     */
2460     void
2461 pcg 1.34 rxvt_term::process_print_pipe ()
2462 pcg 1.1 {
2463 pcg 1.81 int done;
2464     FILE *fd;
2465 pcg 1.36
2466     if ((fd = popen_printer ()) == NULL)
2467     return;
2468    
2469     /*
2470     * Send all input to the printer until either ESC[4i or ESC[?4i
2471     * is received.
2472     */
2473     for (done = 0; !done;)
2474     {
2475 pcg 1.81 unsigned char buf[8];
2476     unicode_t ch;
2477     unsigned int i, len;
2478 pcg 1.1
2479 pcg 1.36 if ((ch = cmd_getc ()) != C0_ESC)
2480     {
2481 pcg 1.43 if (putc (ch, fd) == EOF)
2482 pcg 1.36 break; /* done = 1 */
2483     }
2484     else
2485     {
2486     len = 0;
2487     buf[len++] = ch;
2488 pcg 1.1
2489 pcg 1.36 if ((buf[len++] = cmd_getc ()) == '[')
2490     {
2491     if ((ch = cmd_getc ()) == '?')
2492     {
2493     buf[len++] = '?';
2494     ch = cmd_getc ();
2495     }
2496     if ((buf[len++] = ch) == '4')
2497     {
2498     if ((buf[len++] = cmd_getc ()) == 'i')
2499     break; /* done = 1 */
2500     }
2501     }
2502 pcg 1.81
2503 pcg 1.36 for (i = 0; i < len; i++)
2504 pcg 1.43 if (putc (buf[i], fd) == EOF)
2505 pcg 1.36 {
2506     done = 1;
2507     break;
2508     }
2509     }
2510 pcg 1.1 }
2511 pcg 1.81
2512 pcg 1.36 pclose_printer (fd);
2513 pcg 1.1 }
2514     #endif /* PRINTPIPE */
2515     /*}}} */
2516    
2517     /* *INDENT-OFF* */
2518     enum {
2519 pcg 1.36 C1_40 = 0x40,
2520 pcg 1.90 C1_41 , C1_BPH, C1_NBH, C1_44 , C1_NEL, C1_SSA, C1_ESA,
2521 pcg 1.36 C1_HTS, C1_HTJ, C1_VTS, C1_PLD, C1_PLU, C1_RI , C1_SS2, C1_SS3,
2522     C1_DCS, C1_PU1, C1_PU2, C1_STS, C1_CCH, C1_MW , C1_SPA, C1_EPA,
2523 pcg 1.90 C1_SOS, C1_59 , C1_SCI, C1_CSI, CS_ST , C1_OSC, C1_PM , C1_APC,
2524 pcg 1.1 };
2525     /* *INDENT-ON* */
2526    
2527     /*{{{ process non-printing single characters */
2528     void
2529 pcg 1.81 rxvt_term::process_nonprinting (unicode_t ch)
2530 pcg 1.1 {
2531 pcg 1.36 switch (ch)
2532     {
2533 pcg 1.81 case C0_ESC:
2534     process_escape_seq ();
2535     break;
2536 pcg 1.36 case C0_ENQ: /* terminal Status */
2537     if (rs[Rs_answerbackstring])
2538 pcg 1.90 tt_write ((const unsigned char *)rs[Rs_answerbackstring],
2539     (unsigned int)STRLEN (rs[Rs_answerbackstring]));
2540 pcg 1.36 else
2541 pcg 1.43 tt_write ((unsigned char *)VT100_ANS,
2542 pcg 1.90 (unsigned int)STRLEN (VT100_ANS));
2543 pcg 1.36 break;
2544     case C0_BEL: /* bell */
2545     scr_bell ();
2546     break;
2547     case C0_BS: /* backspace */
2548     scr_backspace ();
2549     break;
2550     case C0_HT: /* tab */
2551     scr_tab (1);
2552     break;
2553     case C0_CR: /* carriage return */
2554     scr_gotorc (0, 0, R_RELATIVE);
2555     break;
2556     case C0_VT: /* vertical tab, form feed */
2557     case C0_FF:
2558     case C0_LF: /* line feed */
2559     scr_index (UP);
2560     break;
2561     case C0_SO: /* shift out - acs */
2562     scr_charset_choose (1);
2563     break;
2564     case C0_SI: /* shift in - acs */
2565     scr_charset_choose (0);
2566     break;
2567 pcg 1.81
2568 root 1.97 #ifdef EIGHT_BIT_CONTROLS
2569 pcg 1.81 // 8-bit controls
2570     case 0x90: /* DCS */
2571     process_dcs_seq ();
2572     break;
2573     case 0x9b: /* CSI */
2574     process_csi_seq ();
2575     break;
2576     case 0x9d: /* CSI */
2577     process_osc_seq ();
2578     break;
2579 root 1.97 #endif
2580 pcg 1.1 }
2581     }
2582     /*}}} */
2583    
2584    
2585     /*{{{ process VT52 escape sequences */
2586     void
2587 pcg 1.81 rxvt_term::process_escape_vt52 (unicode_t ch)
2588 pcg 1.1 {
2589 pcg 1.36 int row, col;
2590    
2591     switch (ch)
2592     {
2593     case 'A': /* cursor up */
2594     scr_gotorc (-1, 0, R_RELATIVE | C_RELATIVE);
2595     break;
2596     case 'B': /* cursor down */
2597     scr_gotorc (1, 0, R_RELATIVE | C_RELATIVE);
2598     break;
2599     case 'C': /* cursor right */
2600     scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
2601     break;
2602     case 'D': /* cursor left */
2603     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
2604     break;
2605     case 'H': /* cursor home */
2606     scr_gotorc (0, 0, 0);
2607     break;
2608     case 'I': /* cursor up and scroll down if needed */
2609     scr_index (DN);
2610     break;
2611     case 'J': /* erase to end of screen */
2612     scr_erase_screen (0);
2613     break;
2614     case 'K': /* erase to end of line */
2615     scr_erase_line (0);
2616     break;
2617     case 'Y': /* move to specified row and col */
2618     /* full command is 'ESC Y row col' where row and col
2619     * are encoded by adding 32 and sending the ascii
2620     * character. eg. SPACE = 0, '+' = 13, '0' = 18,
2621     * etc. */
2622     row = cmd_getc () - ' ';
2623     col = cmd_getc () - ' ';
2624     scr_gotorc (row, col, 0);
2625     break;
2626     case 'Z': /* identify the terminal type */
2627 pcg 1.43 tt_printf ("\033/Z"); /* I am a VT100 emulating a VT52 */
2628 pcg 1.1 break;
2629 pcg 1.36 case '<': /* turn off VT52 mode */
2630 pcg 1.43 PrivMode (0, PrivMode_vt52);
2631 pcg 1.36 break;
2632     case 'F': /* use special graphics character set */
2633     case 'G': /* use regular character set */
2634     /* unimplemented */
2635     break;
2636     case '=': /* use alternate keypad mode */
2637     case '>': /* use regular keypad mode */
2638     /* unimplemented */
2639     break;
2640 pcg 1.1 }
2641     }
2642     /*}}} */
2643    
2644    
2645     /*{{{ process escape sequences */
2646     void
2647 pcg 1.34 rxvt_term::process_escape_seq ()
2648 pcg 1.1 {
2649 pcg 1.81 unicode_t ch = cmd_getc ();
2650 pcg 1.36
2651     if (PrivateModes & PrivMode_vt52)
2652     {
2653     process_escape_vt52 (ch);
2654     return;
2655     }
2656 pcg 1.1
2657 pcg 1.36 switch (ch)
2658     {
2659     /* case 1: do_tek_mode (); break; */
2660     case '#':
2661     if (cmd_getc () == '8')
2662     scr_E ();
2663     break;
2664 pcg 1.44 case '(':
2665 pcg 1.36 scr_charset_set (0, (unsigned int)cmd_getc ());
2666     break;
2667     case ')':
2668     scr_charset_set (1, (unsigned int)cmd_getc ());
2669     break;
2670     case '*':
2671     scr_charset_set (2, (unsigned int)cmd_getc ());
2672     break;
2673     case '+':
2674     scr_charset_set (3, (unsigned int)cmd_getc ());
2675     break;
2676 pcg 1.1 #ifndef NO_FRILLS
2677 pcg 1.36 case '6':
2678     scr_backindex ();
2679     break;
2680     #endif
2681     case '7':
2682     scr_cursor (SAVE);
2683     break;
2684     case '8':
2685     scr_cursor (RESTORE);
2686     break;
2687 pcg 1.1 #ifndef NO_FRILLS
2688 pcg 1.36 case '9':
2689     scr_forwardindex ();
2690     break;
2691     #endif
2692     case '=':
2693     case '>':
2694 pcg 1.43 PrivMode ((ch == '='), PrivMode_aplKP);
2695 pcg 1.36 break;
2696    
2697     case C1_40:
2698     cmd_getc ();
2699     break;
2700     case C1_44:
2701     scr_index (UP);
2702     break;
2703 pcg 1.1
2704 pcg 1.36 /* 8.3.87: NEXT LINE */
2705     case C1_NEL: /* ESC E */
2706 pcg 1.1 {
2707 pcg 1.93 unicode_t nlcr[] = { C0_LF, C0_CR };
2708 pcg 1.34 scr_add_lines (nlcr, 1, 2);
2709 pcg 1.1 }
2710 pcg 1.36 break;
2711    
2712     /* kidnapped escape sequence: Should be 8.3.48 */
2713     case C1_ESA: /* ESC G */
2714     process_graphics ();
2715     break;
2716    
2717     /* 8.3.63: CHARACTER TABULATION SET */
2718     case C1_HTS: /* ESC H */
2719     scr_set_tab (1);
2720     break;
2721    
2722     /* 8.3.105: REVERSE LINE FEED */
2723     case C1_RI: /* ESC M */
2724     scr_index (DN);
2725     break;
2726    
2727     /* 8.3.142: SINGLE-SHIFT TWO */
2728 pcg 1.90 /*case C1_SS2: scr_single_shift (2); break; */
2729 pcg 1.36
2730     /* 8.3.143: SINGLE-SHIFT THREE */
2731 pcg 1.90 /*case C1_SS3: scr_single_shift (3); break; */
2732 pcg 1.36
2733     /* 8.3.27: DEVICE CONTROL STRING */
2734     case C1_DCS: /* ESC P */
2735     process_dcs_seq ();
2736     break;
2737    
2738     /* 8.3.110: SINGLE CHARACTER INTRODUCER */
2739     case C1_SCI: /* ESC Z */
2740 pcg 1.43 tt_write ((const unsigned char *)ESCZ_ANSWER,
2741     (unsigned int) (sizeof (ESCZ_ANSWER) - 1));
2742 pcg 1.36 break; /* steal obsolete ESC [ c */
2743    
2744     /* 8.3.16: CONTROL SEQUENCE INTRODUCER */
2745     case C1_CSI: /* ESC [ */
2746     process_csi_seq ();
2747     break;
2748 pcg 1.1
2749 pcg 1.36 /* 8.3.90: OPERATING SYSTEM COMMAND */
2750     case C1_OSC: /* ESC ] */
2751     process_osc_seq ();
2752     break;
2753    
2754     /* 8.3.106: RESET TO INITIAL STATE */
2755     case 'c':
2756 pcg 1.90 mbstate.reset ();
2757 pcg 1.36 scr_poweron ();
2758     scrollbar_show (1);
2759     break;
2760    
2761     /* 8.3.79: LOCKING-SHIFT TWO (see ISO2022) */
2762     case 'n':
2763     scr_charset_choose (2);
2764     break;
2765    
2766     /* 8.3.81: LOCKING-SHIFT THREE (see ISO2022) */
2767     case 'o':
2768     scr_charset_choose (3);
2769     break;
2770 pcg 1.1 }
2771     }
2772     /*}}} */
2773    
2774     /*{{{ process CONTROL SEQUENCE INTRODUCER (CSI) sequences `ESC[' */
2775     /* *INDENT-OFF* */
2776     enum {
2777 pcg 1.36 CSI_ICH = 0x40,
2778 pcg 1.95 CSI_CUU, CSI_CUD, CSI_CUF, CSI_CUB, CSI_CNL, CSI_CPL, CSI_CHA,
2779 pcg 1.36 CSI_CUP, CSI_CHT, CSI_ED , CSI_EL , CSI_IL , CSI_DL , CSI_EF , CSI_EA ,
2780     CSI_DCH, CSI_SEE, CSI_CPR, CSI_SU , CSI_SD , CSI_NP , CSI_PP , CSI_CTC,
2781     CSI_ECH, CSI_CVT, CSI_CBT, CSI_SRS, CSI_PTX, CSI_SDS, CSI_SIMD, CSI_5F,
2782     CSI_HPA, CSI_HPR, CSI_REP, CSI_DA , CSI_VPA, CSI_VPR, CSI_HVP, CSI_TBC,
2783     CSI_SM , CSI_MC , CSI_HPB, CSI_VPB, CSI_RM , CSI_SGR, CSI_DSR, CSI_DAQ,
2784     CSI_70 , CSI_71 , CSI_72 , CSI_73 , CSI_74 , CSI_75 , CSI_76 , CSI_77 ,
2785     CSI_78 , CSI_79 , CSI_7A , CSI_7B , CSI_7C , CSI_7D , CSI_7E , CSI_7F
2786 pcg 1.1 };
2787    
2788     #define make_byte(b7,b6,b5,b4,b3,b2,b1,b0) \
2789     (((b7) << 7) | ((b6) << 6) | ((b5) << 5) | ((b4) << 4) \
2790     | ((b3) << 3) | ((b2) << 2) | ((b1) << 1) | (b0))
2791     #define get_byte_array_bit(array, bit) \
2792 pcg 1.43 (!! ((array)[ (bit) / 8] & (128 >> ((bit) & 7))))
2793 pcg 1.1
2794 pcg 1.36 const unsigned char csi_defaults[] =
2795     {
2796 pcg 1.43 make_byte (1,1,1,1,1,1,1,1), /* @, A, B, C, D, E, F, G, */
2797     make_byte (1,1,0,0,1,1,0,0), /* H, I, J, K, L, M, N, O, */
2798     make_byte (1,0,1,1,1,1,1,0), /* P, Q, R, S, T, U, V, W, */
2799     make_byte (1,1,1,0,0,0,1,0), /* X, Y, Z, [, \, ], ^, _, */
2800     make_byte (1,1,1,0,1,1,1,0), /* `, a, b, c, d, e, f, g, */
2801     make_byte (0,0,1,1,0,0,0,0), /* h, i, j, k, l, m, n, o, */
2802     make_byte (0,0,0,0,0,0,0,0), /* p, q, r, s, t, u, v, w, */
2803 pcg 1.90 make_byte (0,0,0,0,0,0,0,0), /* x, y, z, {, |, }, ~, */
2804 pcg 1.36 };
2805 pcg 1.1 /* *INDENT-ON* */
2806    
2807     void
2808 pcg 1.34 rxvt_term::process_csi_seq ()
2809 pcg 1.1 {
2810 pcg 1.81 unicode_t ch, priv, i;
2811     unsigned int nargs, p;
2812     int n, ndef;
2813     int arg[ESC_ARGS];
2814 pcg 1.36
2815     for (nargs = ESC_ARGS; nargs > 0;)
2816     arg[--nargs] = 0;
2817    
2818     priv = 0;
2819     ch = cmd_getc ();
2820     if (ch >= '<' && ch <= '?')
2821     { /* '<' '=' '>' '?' */
2822     priv = ch;
2823     ch = cmd_getc ();
2824     }
2825 pcg 1.81
2826 pcg 1.36 /* read any numerical arguments */
2827     for (n = -1; ch < CSI_ICH; )
2828     {
2829 pcg 1.43 if (isdigit (ch))
2830 pcg 1.36 {
2831     if (n < 0)
2832     n = ch - '0';
2833     else
2834     n = n * 10 + ch - '0';
2835     }
2836     else if (ch == ';')
2837     {
2838     if (nargs < ESC_ARGS)
2839     arg[nargs++] = n;
2840     n = -1;
2841     }
2842 pcg 1.81 else if (IS_CONTROL (ch))
2843     process_nonprinting (ch);
2844    
2845 pcg 1.36 ch = cmd_getc ();
2846     }
2847 pcg 1.1
2848 pcg 1.36 if (ch > CSI_7F)
2849     return;
2850 pcg 1.1
2851 pcg 1.36 if (nargs < ESC_ARGS)
2852     arg[nargs++] = n;
2853    
2854     i = ch - CSI_ICH;
2855 pcg 1.43 ndef = get_byte_array_bit (csi_defaults, i);
2856 pcg 1.36 for (p = 0; p < nargs; p++)
2857     if (arg[p] == -1)
2858     arg[p] = ndef;
2859 pcg 1.1
2860     #ifdef DEBUG_CMD
2861 pcg 1.43 fprintf (stderr, "CSI ");
2862 pcg 1.36 for (p = 0; p < nargs; p++)
2863 pcg 1.43 fprintf (stderr, "%d%s", arg[p], p < nargs - 1 ? ";" : "");
2864     fprintf (stderr, "%c\n", ch);
2865 pcg 1.1 #endif
2866    
2867 pcg 1.36 /*
2868     * private mode handling
2869     */
2870     if (priv)
2871     {
2872     switch (priv)
2873     {
2874     case '>':
2875     if (ch == CSI_DA) /* secondary device attributes */
2876 pcg 1.43 tt_printf ("\033[>%d;%-.8s;0c", 'R', VSTRING);
2877 pcg 1.36 break;
2878     case '?':
2879     if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
2880     process_terminal_mode (ch, priv, nargs, arg);
2881     break;
2882     }
2883     return;
2884 pcg 1.1 }
2885    
2886 pcg 1.36 switch (ch)
2887     {
2888     /*
2889 pcg 1.43 * ISO/IEC 6429:1992 (E) CSI sequences (defaults in parentheses)
2890 pcg 1.36 */
2891 pcg 1.1 #ifdef PRINTPIPE
2892 pcg 1.36 case CSI_MC: /* 8.3.83: (0) MEDIA COPY */
2893     switch (arg[0])
2894     {
2895     case 0: /* initiate transfer to primary aux device */
2896     scr_printscreen (0);
2897     break;
2898     case 5: /* start relay to primary aux device */
2899     process_print_pipe ();
2900     break;
2901     }
2902     break;
2903     #endif
2904 pcg 1.1
2905 pcg 1.36 case CSI_CUU: /* 8.3.22: (1) CURSOR UP */
2906     case CSI_VPR: /* 8.3.161: (1) LINE POSITION FORWARD */
2907     arg[0] = -arg[0];
2908     /* FALLTHROUGH */
2909     case CSI_CUD: /* 8.3.19: (1) CURSOR DOWN */
2910     case CSI_VPB: /* 8.3.160: (1) LINE POSITION BACKWARD */
2911     scr_gotorc (arg[0], 0, RELATIVE);
2912     break;
2913    
2914     case CSI_CUB: /* 8.3.18: (1) CURSOR LEFT */
2915     case CSI_HPB: /* 8.3.59: (1) CHARACTER POSITION BACKWARD */
2916 pcg 1.1 #ifdef ISO6429
2917 pcg 1.36 arg[0] = -arg[0];
2918 pcg 1.1 #else /* emulate common DEC VTs */
2919 pcg 1.36 arg[0] = arg[0] ? -arg[0] : -1;
2920 pcg 1.1 #endif
2921 pcg 1.36 /* FALLTHROUGH */
2922     case CSI_CUF: /* 8.3.20: (1) CURSOR RIGHT */
2923     case CSI_HPR: /* 8.3.60: (1) CHARACTER POSITION FORWARD */
2924 pcg 1.1 #ifdef ISO6429
2925 pcg 1.36 scr_gotorc (0, arg[0], RELATIVE);
2926 pcg 1.1 #else /* emulate common DEC VTs */
2927 pcg 1.36 scr_gotorc (0, arg[0] ? arg[0] : 1, RELATIVE);
2928 pcg 1.1 #endif
2929 pcg 1.36 break;
2930    
2931     case CSI_CPL: /* 8.3.13: (1) CURSOR PRECEDING LINE */
2932     arg[0] = -arg[0];
2933     /* FALLTHROUGH */
2934     case CSI_CNL: /* 8.3.12: (1) CURSOR NEXT LINE */
2935     scr_gotorc (arg[0], 0, R_RELATIVE);
2936     break;
2937    
2938     case CSI_CHA: /* 8.3.9: (1) CURSOR CHARACTER ABSOLUTE */
2939     case CSI_HPA: /* 8.3.58: (1) CURSOR POSITION ABSOLUTE */
2940     scr_gotorc (0, arg[0] - 1, R_RELATIVE);
2941     break;
2942    
2943     case CSI_VPA: /* 8.3.159: (1) LINE POSITION ABSOLUTE */
2944     scr_gotorc (arg[0] - 1, 0, C_RELATIVE);
2945     break;
2946    
2947     case CSI_CUP: /* 8.3.21: (1,1) CURSOR POSITION */
2948     case CSI_HVP: /* 8.3.64: (1,1) CHARACTER AND LINE POSITION */
2949     scr_gotorc (arg[0] - 1, nargs < 2 ? 0 : (arg[1] - 1), 0);
2950     break;
2951 pcg 1.1
2952 pcg 1.36 case CSI_CBT: /* 8.3.7: (1) CURSOR BACKWARD TABULATION */
2953     arg[0] = -arg[0];
2954     /* FALLTHROUGH */
2955     case CSI_CHT: /* 8.3.10: (1) CURSOR FORWARD TABULATION */
2956     scr_tab (arg[0]);
2957     break;
2958    
2959     case CSI_ED: /* 8.3.40: (0) ERASE IN PAGE */
2960     scr_erase_screen (arg[0]);
2961     break;
2962    
2963     case CSI_EL: /* 8.3.42: (0) ERASE IN LINE */
2964     scr_erase_line (arg[0]);
2965     break;
2966    
2967     case CSI_ICH: /* 8.3.65: (1) INSERT CHARACTER */
2968     scr_insdel_chars (arg[0], INSERT);
2969     break;
2970    
2971     case CSI_IL: /* 8.3.68: (1) INSERT LINE */
2972     scr_insdel_lines (arg[0], INSERT);
2973     break;
2974    
2975     case CSI_DL: /* 8.3.33: (1) DELETE LINE */
2976     scr_insdel_lines (arg[0], DELETE);
2977     break;
2978    
2979     case CSI_ECH: /* 8.3.39: (1) ERASE CHARACTER */
2980     scr_insdel_chars (arg[0], ERASE);
2981     break;
2982    
2983     case CSI_DCH: /* 8.3.26: (1) DELETE CHARACTER */
2984     scr_insdel_chars (arg[0], DELETE);
2985     break;
2986    
2987     case CSI_SD: /* 8.3.114: (1) SCROLL DOWN */
2988     arg[0] = -arg[0];
2989     /* FALLTHROUGH */
2990     case CSI_SU: /* 8.3.148: (1) SCROLL UP */
2991     scr_scroll_text (screen.tscroll, screen.bscroll, arg[0], 0);
2992     break;
2993    
2994     case CSI_DA: /* 8.3.24: (0) DEVICE ATTRIBUTES */
2995 pcg 1.43 tt_write ((const unsigned char *)VT100_ANS,
2996     (unsigned int) (sizeof (VT100_ANS) - 1));
2997 pcg 1.36 break;
2998    
2999     case CSI_SGR: /* 8.3.118: (0) SELECT GRAPHIC RENDITION */
3000     process_sgr_mode (nargs, arg);
3001     break;
3002    
3003     case CSI_DSR: /* 8.3.36: (0) DEVICE STATUS REPORT */
3004     switch (arg[0])
3005     {
3006     case 5: /* DSR requested */
3007 pcg 1.43 tt_printf ("\033[0n");
3008 pcg 1.36 break;
3009     case 6: /* CPR requested */
3010     scr_report_position ();
3011     break;
3012     case 7: /* unofficial extension */
3013 pcg 1.90 if (Options & Opt_insecure)
3014     tt_printf ("%-.250s\n", rs[Rs_display_name]);
3015 pcg 1.36 break;
3016     case 8: /* unofficial extension */
3017 pcg 1.90 process_xterm_seq (XTerm_title, RESNAME "-" VERSION, CHAR_ST);
3018 pcg 1.36 break;
3019     }
3020     break;
3021 pcg 1.1
3022 pcg 1.36 case CSI_TBC: /* 8.3.155: (0) TABULATION CLEAR */
3023     switch (arg[0])
3024     {
3025     case 0: /* char tab stop cleared at active position */
3026     scr_set_tab (0);
3027     break;
3028     /* case 1: */ /* line tab stop cleared in active line */
3029     /* case 2: */ /* char tab stops cleared in active line */
3030     case 3: /* all char tab stops are cleared */
3031     /* case 4: */ /* all line tab stops are cleared */
3032     case 5: /* all tab stops are cleared */
3033     scr_set_tab (-1);
3034     break;
3035     }
3036     break;
3037    
3038     case CSI_CTC: /* 8.3.17: (0) CURSOR TABULATION CONTROL */
3039     switch (arg[0])
3040     {
3041     case 0: /* char tab stop set at active position */
3042     scr_set_tab (1);
3043     break; /* = ESC H */
3044     /* case 1: */ /* line tab stop set at active line */
3045     case 2: /* char tab stop cleared at active position */
3046     scr_set_tab (0);
3047     break; /* = ESC [ 0 g */
3048     /* case 3: */ /* line tab stop cleared at active line */
3049     /* case 4: */ /* char tab stops cleared at active line */
3050     case 5: /* all char tab stops are cleared */
3051     scr_set_tab (-1);
3052     break; /* = ESC [ 3 g */
3053     /* case 6: */ /* all line tab stops are cleared */
3054     }
3055     break;
3056    
3057     case CSI_RM: /* 8.3.107: RESET MODE */
3058     if (arg[0] == 4)
3059     scr_insert_mode (0);
3060     break;
3061    
3062     case CSI_SM: /* 8.3.126: SET MODE */
3063     if (arg[0] == 4)
3064     scr_insert_mode (1);
3065     break;
3066    
3067     /*
3068     * PRIVATE USE beyond this point. All CSI_7? sequences here
3069     */
3070     case CSI_72: /* DECSTBM: set top and bottom margins */
3071     if (nargs == 1)
3072     scr_scroll_region (arg[0] - 1, MAX_ROWS - 1);
3073     else if (nargs == 0 || arg[0] >= arg[1])
3074     scr_scroll_region (0, MAX_ROWS - 1);
3075     else
3076     scr_scroll_region (arg[0] - 1, arg[1] - 1);
3077     break;
3078    
3079     case CSI_73:
3080     scr_cursor (SAVE);
3081     break;
3082     case CSI_75:
3083     scr_cursor (RESTORE);
3084     break;
3085 pcg 1.1
3086     #ifndef NO_FRILLS
3087 pcg 1.36 case CSI_74:
3088     process_window_ops (arg, nargs);
3089     break;
3090 pcg 1.1 #endif
3091    
3092 pcg 1.36 case CSI_78: /* DECREQTPARM */
3093     if (arg[0] == 0 || arg[0] == 1)
3094 pcg 1.43 tt_printf ("\033[%d;1;1;128;128;1;0x", arg[0] + 2);
3095 pcg 1.81 break;
3096 pcg 1.1
3097 pcg 1.36 default:
3098     break;
3099 pcg 1.1 }
3100     }
3101     /*}}} */
3102    
3103     #ifndef NO_FRILLS
3104     /* ARGSUSED */
3105     void
3106 pcg 1.34 rxvt_term::process_window_ops (const int *args, unsigned int nargs)
3107 pcg 1.1 {
3108 pcg 1.81 int x, y;
3109 pcg 1.36 XWindowAttributes wattr;
3110 pcg 1.81 Window wdummy;
3111 pcg 1.1
3112 pcg 1.36 if (nargs == 0)
3113     return;
3114 pcg 1.81
3115 pcg 1.36 switch (args[0])
3116     {
3117 pcg 1.81 /*
3118     * commands
3119     */
3120 pcg 1.36 case 1: /* deiconify window */
3121 pcg 1.43 XMapWindow (display->display, TermWin.parent[0]);
3122 pcg 1.36 break;
3123     case 2: /* iconify window */
3124 pcg 1.43 XIconifyWindow (display->display, TermWin.parent[0],
3125     DefaultScreen (display->display));
3126 pcg 1.36 break;
3127     case 3: /* set position (pixels) */
3128 pcg 1.43 XMoveWindow (display->display, TermWin.parent[0], args[1], args[2]);
3129 pcg 1.36 break;
3130     case 4: /* set size (pixels) */
3131     set_widthheight ((unsigned int)args[2], (unsigned int)args[1]);
3132     break;
3133     case 5: /* raise window */
3134 pcg 1.43 XRaiseWindow (display->display, TermWin.parent[0]);
3135 pcg 1.36 break;
3136     case 6: /* lower window */
3137 pcg 1.43 XLowerWindow (display->display, TermWin.parent[0]);
3138 pcg 1.36 break;
3139     case 7: /* refresh window */
3140     scr_touch (true);
3141     break;
3142     case 8: /* set size (chars) */
3143 pcg 1.43 set_widthheight ((unsigned int) (args[2] * TermWin.fwidth),
3144     (unsigned int) (args[1] * TermWin.fheight));
3145 pcg 1.36 break;
3146 pcg 1.81
3147     //case 9: NYI, TODO, restore maximized window or maximize window
3148 pcg 1.36 default:
3149     if (args[0] >= 24) /* set height (chars) */
3150     set_widthheight ((unsigned int)TermWin.width,
3151 pcg 1.43 (unsigned int) (args[1] * TermWin.fheight));
3152 pcg 1.36 break;
3153 pcg 1.81
3154    
3155     /*
3156     * reports - some output format copied from XTerm
3157     */
3158 pcg 1.36 case 11: /* report window state */
3159 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
3160     tt_printf ("\033[%dt", wattr.map_state == IsViewable ? 1 : 2);
3161 pcg 1.36 break;
3162     case 13: /* report window position */
3163 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
3164     XTranslateCoordinates (display->display, TermWin.parent[0], wattr.root,
3165 pcg 1.90 -wattr.border_width, -wattr.border_width,
3166     &x, &y, &wdummy);
3167 pcg 1.43 tt_printf ("\033[3;%d;%dt", x, y);
3168 pcg 1.36 break;
3169     case 14: /* report window size (pixels) */
3170 pcg 1.43 XGetWindowAttributes (display->display, TermWin.parent[0], &wattr);
3171     tt_printf ("\033[4;%d;%dt", wattr.height, wattr.width);
3172 pcg 1.36 break;
3173 pcg 1.81 case 18: /* report text area size (chars) */
3174 pcg 1.43 tt_printf ("\033[8;%d;%dt", TermWin.nrow, TermWin.ncol);
3175 pcg 1.36 break;
3176 pcg 1.81 case 19: /* report window size (chars) */
3177     tt_printf ("\033[9;%d;%dt", TermWin.nrow, TermWin.ncol);
3178     break;
3179 pcg 1.36 case 20: /* report icon label */
3180 pcg 1.90 if (Options & Opt_insecure)
3181     {
3182     char *s;
3183     XGetIconName (display->display, TermWin.parent[0], &s);
3184     tt_printf ("\033]L%-.200s\234", s ? s : ""); /* 8bit ST */
3185     }
3186 pcg 1.36 break;
3187     case 21: /* report window title */
3188 pcg 1.90 if (Options & Opt_insecure)
3189     {
3190     char *s;
3191     XFetchName (display->display, TermWin.parent[0], &s);
3192     tt_printf ("\033]l%-.200s\234", s ? s : ""); /* 8bit ST */
3193     }
3194 pcg 1.36 break;
3195 pcg 1.1 }
3196     }
3197     #endif
3198    
3199     /*----------------------------------------------------------------------*/
3200     /*
3201     * get input up until STRING TERMINATOR (or BEL)
3202 pcg 1.93 * ends_how is terminator used. returned input must be free()'d
3203 pcg 1.1 */
3204 pcg 1.81 unsigned char *
3205     rxvt_term::get_to_st (unicode_t &ends_how)
3206 pcg 1.1 {
3207 root 1.97 unicode_t prev = 0, ch;
3208 pcg 1.81 unsigned int n = 0;
3209     unsigned char *s;
3210     unsigned char string[STRING_MAX];
3211 pcg 1.36
3212 root 1.97 while ((ch = cmd_getc ()) != NOCHAR)
3213 pcg 1.36 {
3214 root 1.97 if (prev == C0_ESC)
3215 pcg 1.36 {
3216 root 1.97 if (ch == 0x5c) /* 7bit ST */
3217     break;
3218     else
3219     return NULL;
3220 pcg 1.36 }
3221 root 1.97 else if (ch == C0_BEL || ch == CHAR_ST)
3222     break;
3223     else if (ch < 0x20)
3224 pcg 1.36 return NULL; /* other control character - exit */
3225 pcg 1.81
3226 pcg 1.90 if (n >= sizeof (string) - 1)
3227     // stop at some sane length
3228     return NULL;
3229 pcg 1.81
3230 root 1.97 if (ch == C0_SYN)
3231     {
3232     string[n++] = cmd_get8 ();
3233     prev = 0;
3234     }
3235     else
3236     string[n++] = prev = ch;
3237 pcg 1.36 }
3238 pcg 1.81
3239 pcg 1.36 string[n++] = '\0';
3240 pcg 1.81
3241 pcg 1.43 if ((s = (unsigned char *)rxvt_malloc (n)) == NULL)
3242 pcg 1.36 return NULL;
3243 pcg 1.81
3244     ends_how = (ch == 0x5c ? C0_ESC : ch);
3245 pcg 1.43 STRNCPY (s, string, n);
3246 pcg 1.36 return s;
3247 pcg 1.1 }
3248    
3249     /*----------------------------------------------------------------------*/
3250     /*
3251     * process DEVICE CONTROL STRING `ESC P ... (ST|BEL)' or `0x90 ... (ST|BEL)'
3252     */
3253     void
3254 pcg 1.34 rxvt_term::process_dcs_seq ()
3255 pcg 1.1 {
3256 pcg 1.81 unsigned char *s;
3257     unicode_t eh;
3258    
3259 pcg 1.36 /*
3260     * Not handled yet
3261     */
3262 pcg 1.81 s = get_to_st (eh);
3263 pcg 1.36 if (s)
3264 pcg 1.43 free (s);
3265 pcg 1.81
3266 pcg 1.36 return;
3267 pcg 1.1 }
3268    
3269     /*----------------------------------------------------------------------*/
3270     /*
3271     * process OPERATING SYSTEM COMMAND sequence `ESC ] Ps ; Pt (ST|BEL)'
3272     */
3273     void
3274 pcg 1.34 rxvt_term::process_osc_seq ()
3275 pcg 1.1 {
3276 pcg 1.81 unicode_t ch, eh;
3277     int arg;
3278 pcg 1.1
3279 pcg 1.36 ch = cmd_getc ();
3280 pcg 1.43 for (arg = 0; isdigit (ch); ch = cmd_getc ())
3281 pcg 1.36 arg = arg * 10 + (ch - '0');
3282 pcg 1.1
3283 pcg 1.36 if (ch == ';')
3284     {
3285 pcg 1.81 unsigned char *s = get_to_st (eh);
3286    
3287 pcg 1.36 if (s)
3288     {
3289 pcg 1.90 process_xterm_seq (arg, (char *)s, eh);
3290     free (s);
3291     }
3292     }
3293     }
3294 pcg 1.81
3295 pcg 1.90 void
3296     rxvt_term::process_color_seq (int report, int color, const char *str, unsigned char resp)
3297     {
3298     if (str[0] == '?' && !str[1])
3299     {
3300     if (Options & Opt_insecure)
3301     {
3302     unsigned short r, g, b;
3303 root 1.107 PixColorsFocused[color].get (display, r, g, b);
3304 pcg 1.90 tt_printf ("\033]%d;rgb:%04x/%04x/%04x%c", report, r, g, b, resp);
3305 pcg 1.36 }
3306 pcg 1.1 }
3307 pcg 1.90 else
3308     set_window_color (color, str);
3309 pcg 1.1 }
3310 pcg 1.90
3311 pcg 1.1 /*
3312     * XTerm escape sequences: ESC ] Ps;Pt (ST|BEL)
3313     * 0 = change iconName/title
3314     * 1 = change iconName
3315     * 2 = change title
3316     * 4 = change color
3317 pcg 1.90 * 10 = change fg color
3318     * 11 = change bg color
3319 pcg 1.1 * 12 = change text color
3320     * 13 = change mouse foreground color
3321     * 17 = change highlight character colour
3322     * 18 = change bold character color
3323     * 19 = change underlined character color
3324     * 46 = change logfile (not implemented)
3325     * 50 = change font
3326     *
3327     * rxvt extensions:
3328     * 20 = bg pixmap
3329     * 39 = change default fg color
3330     * 49 = change default bg color
3331     * 55 = dump scrollback buffer and all of screen
3332 pcg 1.67 * 701 = change locale
3333     * 702 = find font
3334 pcg 1.90 * 703 = menu
3335 pcg 1.1 */
3336     void
3337 pcg 1.90 rxvt_term::process_xterm_seq (int op, const char *str, unsigned char resp)
3338 pcg 1.1 {
3339 pcg 1.81 int changed = 0;
3340     int color;
3341     char *buf, *name;
3342 pcg 1.90 bool query = str[0] == '?' && !str[1];
3343 pcg 1.36
3344 pcg 1.43 assert (str != NULL);
3345 pcg 1.36 switch (op)
3346     {
3347     case XTerm_name:
3348     set_title (str);
3349     /* FALLTHROUGH */
3350     case XTerm_iconName:
3351 pcg 1.81 set_icon_name (str);
3352 pcg 1.36 break;
3353     case XTerm_title:
3354     set_title (str);
3355     break;
3356 pcg 1.90 case XTerm_property:
3357     if (str[0] == '?')
3358     {
3359     Atom prop = XInternAtom (display->display, str + 1, True);
3360     Atom actual_type;
3361     int actual_format;
3362     unsigned long nitems;
3363     unsigned long bytes_after;
3364     unsigned char *value = 0;
3365     const char *str = "";
3366    
3367     if (prop
3368     && XGetWindowProperty (display->display, TermWin.parent[0],
3369     prop, 0, 1<<16, 0, AnyPropertyType,
3370     &actual_type, &actual_format,
3371     &nitems, &bytes_after, &value) == Success
3372     && actual_type != None
3373     && actual_format == 8)
3374     str = (const char *)(value);
3375    
3376     tt_printf ("\033]%d;%s%c", XTerm_property, str, resp);
3377    
3378     XFree (value);
3379     }
3380     else
3381     {
3382     char *eq = strchr (str, '='); // constness lost, but verified to be ok
3383    
3384     if (eq)
3385     {
3386     *eq = 0;
3387     XChangeProperty (display->display, TermWin.parent[0],
3388     display->atom (str), XA_STRING, 8,
3389     PropModeReplace, (unsigned char *)eq + 1,
3390     strlen (eq + 1));
3391     }
3392     else
3393     XDeleteProperty (display->display, TermWin.parent[0],
3394     display->atom (str));
3395     }
3396     break;
3397    
3398 pcg 1.36 case XTerm_Color:
3399     for (buf = (char *)str; buf && *buf;)
3400     {
3401 pcg 1.43 if ((name = STRCHR (buf, ';')) == NULL)
3402 pcg 1.36 break;
3403 pcg 1.81
3404 pcg 1.36 *name++ = '\0';
3405 pcg 1.43 color = atoi (buf);
3406 pcg 1.81
3407 pcg 1.36 if (color < 0 || color >= TOTAL_COLORS)
3408     break;
3409 pcg 1.81
3410 pcg 1.43 if ((buf = STRCHR (name, ';')) != NULL)
3411 pcg 1.36 *buf++ = '\0';
3412 pcg 1.81
3413 pcg 1.90 if (name[0] == '?' && !name[1])
3414     {
3415     if (Options & Opt_insecure)
3416     {
3417     unsigned short r, g, b;
3418 root 1.107 PixColorsFocused[color + minCOLOR].get (display, r, g, b);
3419 pcg 1.90 tt_printf ("\033]%d;%d;rgb:%04x/%04x/%04x%c", XTerm_Color, color, r, g, b, resp);
3420     }
3421     }
3422     else
3423     set_window_color (color + minCOLOR, name);
3424 pcg 1.36 }
3425     break;
3426 pcg 1.90 case XTerm_Color00:
3427     process_color_seq (XTerm_Color00, Color_fg, str, resp);
3428     break;
3429     case XTerm_Color01:
3430     process_color_seq (XTerm_Color00, Color_bg, str, resp);
3431     break;
3432 pcg 1.1 #ifndef NO_CURSORCOLOR
3433 pcg 1.36 case XTerm_Color_cursor:
3434 pcg 1.90 process_color_seq (XTerm_Color_cursor, Color_cursor, str, resp);
3435 pcg 1.36 break;
3436     #endif
3437 pcg 1.90 case XTerm_Color_pointer_fg:
3438     process_color_seq (XTerm_Color_pointer_fg, Color_pointer_fg, str, resp);
3439     break;
3440     case XTerm_Color_pointer_bg:
3441     process_color_seq (XTerm_Color_pointer_bg, Color_pointer_bg, str, resp);
3442 pcg 1.36 break;
3443 pcg 1.1 #ifndef NO_BOLD_UNDERLINE_REVERSE
3444 pcg 1.36 case XTerm_Color_BD:
3445 pcg 1.90 process_color_seq (XTerm_Color_BD, Color_BD, str, resp);
3446 pcg 1.36 break;
3447     case XTerm_Color_UL:
3448 pcg 1.90 process_color_seq (XTerm_Color_UL, Color_UL, str, resp);
3449 pcg 1.36 break;
3450     case XTerm_Color_RV:
3451 pcg 1.90 process_color_seq (XTerm_Color_RV, Color_RV, str, resp);
3452 pcg 1.36 break;
3453 pcg 1.1 #endif
3454    
3455 pcg 1.36 case XTerm_Pixmap:
3456     if (*str != ';')
3457     {
3458 pcg 1.1 #if XPM_BACKGROUND
3459 pcg 1.36 scale_pixmap (""); /* reset to default scaling */
3460     set_bgPixmap (str); /* change pixmap */
3461 pcg 1.1 #endif
3462 pcg 1.36 scr_touch (true);
3463     }
3464 pcg 1.43 while ((str = STRCHR (str, ';')) != NULL)
3465 pcg 1.36 {
3466     str++;
3467 pcg 1.1 #if XPM_BACKGROUND
3468 pcg 1.36 changed += scale_pixmap (str);
3469 pcg 1.1 #endif
3470 pcg 1.36
3471     }
3472     if (changed)
3473     {
3474 pcg 1.1 #ifdef XPM_BACKGROUND
3475 pcg 1.36 resize_pixmap ();
3476 pcg 1.1 #endif
3477 pcg 1.36 scr_touch (true);
3478     }
3479     break;
3480    
3481     case XTerm_restoreFG:
3482     set_window_color (Color_fg, str);
3483     break;
3484     case XTerm_restoreBG:
3485     set_window_color (Color_bg, str);
3486     break;
3487 pcg 1.90
3488 pcg 1.36 case XTerm_logfile:
3489 pcg 1.81 // TODO, when secure mode?
3490 pcg 1.36 break;
3491 pcg 1.90
3492 pcg 1.36 case XTerm_font:
3493 pcg 1.90 if (query)
3494     {
3495     if (Options & Opt_insecure)
3496     tt_printf ("\33]%d;%-.250s%c", XTerm_font,
3497     TermWin.fontset->fontdesc
3498     ? TermWin.fontset->fontdesc
3499     : "",
3500     resp);
3501     }
3502     else
3503     change_font (str);
3504 pcg 1.51 break;
3505 pcg 1.90
3506 pcg 1.60 #ifndef NO_FRILLS
3507 pcg 1.51 case XTerm_locale:
3508 pcg 1.90 if (query)
3509     {
3510     if (Options & Opt_insecure)
3511     tt_printf ("\33]%d;%-.250s%c", XTerm_locale, locale, resp);
3512     }
3513 pcg 1.54 else
3514     {
3515     set_locale (str);
3516 pcg 1.60 # ifdef USE_XIM
3517 pcg 1.54 im_cb ();
3518 pcg 1.60 # endif
3519 pcg 1.54 }
3520 pcg 1.36 break;
3521 pcg 1.90
3522 pcg 1.67 case XTerm_findfont:
3523 pcg 1.90 if (Options & Opt_insecure)
3524     {
3525     int fid = TermWin.fontset->find_font (atoi (str));
3526     tt_printf ("\33]%d;%d;%-.250s%c", XTerm_findfont,
3527     fid, (*TermWin.fontset)[fid]->name, resp);
3528     }
3529 pcg 1.67 break;
3530 pcg 1.60 #endif
3531 pcg 1.90
3532     #ifdef MENUBAR
3533     case XTerm_Menu:
3534     if (Options & Opt_insecure)
3535     menubar_dispatch (const_cast<char *>(str)); // casting away constness is checked
3536     break;
3537     #endif
3538 pcg 1.1 #if 0
3539 pcg 1.36 case XTerm_dumpscreen: /* no error notices */
3540     {
3541 pcg 1.90 int fd;
3542 pcg 1.43 if ((fd = open (str, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0)
3543 pcg 1.36 {
3544     scr_dump (fd);
3545 pcg 1.43 close (fd);
3546 pcg 1.36 }
3547     }
3548     break;
3549 pcg 1.1 #endif
3550     }
3551     }
3552     /*----------------------------------------------------------------------*/
3553    
3554     /*{{{ process DEC private mode sequences `ESC [ ? Ps mode' */
3555     /*
3556     * mode can only have the following values:
3557     * 'l' = low
3558     * 'h' = high
3559     * 's' = save
3560     * 'r' = restore
3561     * 't' = toggle
3562     * so no need for fancy checking
3563     */
3564     int
3565 pcg 1.34 rxvt_term::privcases (int mode, unsigned long bit)
3566 pcg 1.1 {
3567 pcg 1.81 int state;
3568 pcg 1.1
3569 pcg 1.36 if (mode == 's')
3570     {
3571     SavedModes |= (PrivateModes & bit);
3572     return -1;
3573 pcg 1.1 }
3574 pcg 1.36 else
3575     {
3576     if (mode == 'r')
3577     state = (SavedModes & bit) ? 1 : 0; /* no overlapping */
3578     else
3579 pcg 1.43 state = (mode == 't') ? ! (PrivateModes & bit) : mode;
3580     PrivMode (state, bit);
3581 pcg 1.36 }
3582 pcg 1.81
3583 pcg 1.36 return state;
3584 pcg 1.1 }
3585    
3586     /* we're not using priv _yet_ */
3587     void
3588 pcg 1.43 rxvt_term::process_terminal_mode (int mode, int priv __attribute__ ((unused)), unsigned int nargs, const int *arg)
3589 pcg 1.1 {
3590 pcg 1.81 unsigned int i, j;
3591     int state;
3592    
3593 pcg 1.36 static const struct
3594     {
3595     const int argval;
3596     const unsigned long bit;
3597     }
3598 pcg 1.81
3599 pcg 1.36 argtopriv[] = {
3600     { 1, PrivMode_aplCUR },
3601     { 2, PrivMode_vt52 },
3602     { 3, PrivMode_132 },
3603     { 4, PrivMode_smoothScroll },
3604     { 5, PrivMode_rVideo },
3605     { 6, PrivMode_relOrigin },
3606     { 7, PrivMode_Autowrap },
3607     { 9, PrivMode_MouseX10 },
3608 pcg 1.1 #ifdef menuBar_esc
3609 pcg 1.36 { menuBar_esc, PrivMode_menuBar },
3610 pcg 1.1 #endif
3611     #ifdef scrollBar_esc
3612 pcg 1.36 { scrollBar_esc, PrivMode_scrollBar },
3613 pcg 1.1 #endif
3614 pcg 1.73 // 18, 19 printing-related
3615 pcg 1.36 { 25, PrivMode_VisibleCursor },
3616 pcg 1.73 // 30 show scrollbar rxvt. extension
3617     { 35, PrivMode_ShiftKeys }, // rxvt extension
3618 pcg 1.36 { 40, PrivMode_132OK },
3619 pcg 1.73 // 41 xterm more fixes NYI
3620     // 45 margin bell NYI
3621     // 46 start logging
3622 pcg 1.36 { 47, PrivMode_Screen },
3623     { 66, PrivMode_aplKP },
3624 pcg 1.1 #ifndef NO_BACKSPACE_KEY
3625 pcg 1.36 { 67, PrivMode_BackSpace },
3626 pcg 1.1 #endif
3627 pcg 1.36 { 1000, PrivMode_MouseX11 },
3628 pcg 1.73 // 1001 Use Hilite Mouse Tracking. NYI, TODO
3629     // 1002 Use Cell Motion Mouse Tracking. NYI, TODO
3630     // 1003 Use All Motion Mouse Tracking. NYI, TODO
3631     { 1010, PrivMode_TtyOutputInh }, // rxvt extension
3632     { 1011, PrivMode_Keypress }, // rxvt extension
3633     // 1035 enable modifiers for alt, numlock NYI
3634     // 1036 send ESC for meta keys NYI
3635     // 1037 send DEL for keypad delete NYI
3636 pcg 1.36 { 1047, PrivMode_Screen },
3637 pcg 1.73 // 1048 save and restore cursor
3638 pcg 1.90 { 1049, PrivMode_Screen }, /* xterm extension, clear screen on ti rather than te */
3639 pcg 1.73 // 1051, 1052, 1060, 1061 keyboard emulation NYI
3640 pcg 1.36 };
3641    
3642     if (nargs == 0)
3643     return;
3644    
3645     /* make lo/hi boolean */
3646     if (mode == 'l')
3647     mode = 0; /* reset */
3648     else if (mode == 'h')
3649     mode = 1; /* set */
3650    
3651     for (i = 0; i < nargs; i++)
3652     {
3653     state = -1;
3654    
3655     /* basic handling */
3656 pcg 1.43 for (j = 0; j < (sizeof (argtopriv)/sizeof (argtopriv[0])); j++)
3657 pcg 1.36 if (argtopriv[j].argval == arg[i])
3658     {
3659     state = privcases (mode, argtopriv[j].bit);
3660     break;
3661     }
3662 pcg 1.1
3663 pcg 1.36 /* extra handling for values with state unkept */
3664 pcg 1.73 switch (arg[i])
3665     {
3666     case 1048: /* alternative cursor save */
3667 pcg 1.90 if (Options & Opt_secondaryScreen)
3668     if (mode == 0)
3669     scr_cursor (RESTORE);
3670     else if (mode == 1)
3671     scr_cursor (SAVE);
3672     break;
3673 pcg 1.73 }
3674    
3675     if (state >= 0)
3676     /* extra handling for values with valid 0 or 1 state */
3677 pcg 1.36 switch (arg[i])
3678     {
3679 pcg 1.73 /* case 1: - application cursor keys */
3680     case 2: /* VT52 mode */
3681     /* oddball mode. should be set regardless of set/reset
3682     * parameter. Return from VT52 mode with an ESC < from
3683     * within VT52 mode
3684     */
3685     PrivMode (1, PrivMode_vt52);
3686     break;
3687     case 3: /* 80/132 */
3688     if (PrivateModes & PrivMode_132OK)
3689     set_widthheight (((state ? 132 : 80) * TermWin.fwidth), TermWin.height);
3690     break;
3691     case 4: /* smooth scrolling */
3692     if (state)
3693     Options &= ~Opt_jumpScroll;
3694     else
3695     Options |= Opt_jumpScroll;
3696     break;
3697     case 5: /* reverse video */
3698     scr_rvideo_mode (state);
3699     break;
3700     case 6: /* relative/absolute origins */
3701     scr_relative_origin (state);
3702     break;
3703     case 7: /* autowrap */
3704     scr_autowrap (state);
3705     break;
3706 pcg 1.90 /* case 8: - auto repeat, can't do on a per window basis */
3707 pcg 1.73 case 9: /* X10 mouse reporting */
3708     if (state) /* orthogonal */
3709 pcg 1.81 PrivateModes &= ~PrivMode_MouseX11;
3710 pcg 1.73 break;
3711 pcg 1.1 #ifdef menuBar_esc
3712 pcg 1.73 case menuBar_esc:
3713 pcg 1.1 #ifdef MENUBAR
3714 pcg 1.73 map_menuBar (state);
3715 pcg 1.1 #endif
3716 pcg 1.73 break;
3717 pcg 1.1 #endif
3718     #ifdef scrollBar_esc
3719 pcg 1.73 case scrollBar_esc:
3720     if (scrollbar_mapping (state))
3721     {
3722     resize_all_windows (0, 0, 0);
3723     scr_touch (true);
3724     }
3725     break;
3726 pcg 1.1 #endif
3727 pcg 1.73 case 25: /* visible/invisible cursor */
3728     scr_cursor_visible (state);
3729     break;
3730 pcg 1.90 /* case 35: - shift keys */
3731     /* case 40: - 80 <--> 132 mode */
3732 pcg 1.73 case 47: /* secondary screen */
3733     scr_change_screen (state);
3734     break;
3735 pcg 1.90 /* case 66: - application key pad */
3736     /* case 67: - backspace key */
3737 pcg 1.73 case 1000: /* X11 mouse reporting */
3738     if (state) /* orthogonal */
3739 pcg 1.81 PrivateModes &= ~PrivMode_MouseX10;
3740 pcg 1.73 break;
3741 pcg 1.1 #if 0
3742 pcg 1.73 case 1001:
3743     break; /* X11 mouse highlighting */
3744 pcg 1.1 #endif
3745 pcg 1.73 case 1010: /* scroll to bottom on TTY output inhibit */
3746     if (state)
3747     Options &= ~Opt_scrollTtyOutput;
3748     else
3749     Options |= Opt_scrollTtyOutput;
3750     break;
3751     case 1011: /* scroll to bottom on key press */
3752     if (state)
3753     Options |= Opt_scrollTtyKeypress;
3754     else
3755     Options &= ~Opt_scrollTtyKeypress;
3756     break;
3757 pcg 1.90 case 1047: /* secondary screen w/ clearing last */
3758     if (Options & Opt_secondaryScreen)
3759     if (current_screen != PRIMARY)
3760     scr_erase_screen (2);
3761     scr_change_screen (state);
3762     break;
3763     case 1049: /* secondary screen w/ clearing first */
3764 pcg 1.73 scr_change_screen (state);
3765 pcg 1.90 if (Options & Opt_secondaryScreen)
3766     if (current_screen != PRIMARY)
3767     scr_erase_screen (2);
3768     break;
3769 pcg 1.73 default:
3770     break;
3771     }
3772 pcg 1.1 }
3773     }
3774     /*}}} */
3775    
3776     /*{{{ process sgr sequences */
3777     void
3778 pcg 1.34 rxvt_term::process_sgr_mode (unsigned int nargs, const int *arg)
3779 pcg 1.1 {
3780 pcg 1.81 unsigned int i;
3781     short rendset;
3782     int rendstyle;
3783 pcg 1.36
3784     if (nargs == 0)
3785     {
3786     scr_rendition (0, ~RS_None);
3787     return;
3788     }
3789 pcg 1.81
3790 pcg 1.36 for (i = 0; i < nargs; i++)
3791     {
3792     rendset = -1;
3793     switch (arg[i])
3794     {
3795     case 0:
3796     rendset = 0, rendstyle = ~RS_None;
3797     break;
3798     case 1:
3799     rendset = 1, rendstyle = RS_Bold;
3800     break;
3801 root 1.107 //case 2: // faint or second colour
3802 pcg 1.36 case 4:
3803     rendset = 1, rendstyle = RS_Uline;
3804     break;
3805 root 1.107 case 5: // slowly blinking
3806     case 6: // rapidly blinking
3807 pcg 1.36 rendset = 1, rendstyle = RS_Blink;
3808     break;
3809 pcg 1.93 //case 6: // scoansi light background
3810 pcg 1.36 case 7:
3811     rendset = 1, rendstyle = RS_RVid;
3812     break;
3813 pcg 1.73 case 8:
3814     // invisible. NYI
3815     break;
3816 root 1.107 //case 9: // crossed out
3817     //case 10: // scoansi acs off, primary font
3818     //case 11: // scoansi acs on, first alt font
3819     //case 12: // scoansi acs on, |0x80, second alt font
3820     //...
3821     //case 19: // ninth alt font
3822     //case 20: // gothic
3823     case 21: // disable bold, faint
3824     rendset = 0, rendstyle = RS_Bold;
3825 pcg 1.93 break;
3826 pcg 1.36 case 22:
3827     rendset = 0, rendstyle = RS_Bold;
3828     break;
3829 root 1.107 //case 23: disable italic
3830 pcg 1.36 case 24:
3831     rendset = 0, rendstyle = RS_Uline;
3832     break;
3833     case 25:
3834     rendset = 0, rendstyle = RS_Blink;
3835     break;
3836     case 27:
3837     rendset = 0, rendstyle = RS_RVid;
3838     break;
3839 root 1.107 //case 28: // visible. NYI
3840     //case 29: // not crossed-out
3841 pcg 1.36 }
3842 pcg 1.73
3843 pcg 1.36 if (rendset != -1)
3844     {
3845     scr_rendition (rendset, rendstyle);
3846 pcg 1.43 continue; /* for (;i;) */
3847 pcg 1.36 }
3848    
3849     switch (arg[i])
3850     {
3851     case 30:
3852     case 31: /* set fg color */
3853     case 32:
3854     case 33:
3855     case 34:
3856     case 35:
3857     case 36:
3858     case 37:
3859 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 30)), Color_fg);
3860 pcg 1.36 break;
3861 pcg 1.1 #ifdef TTY_256COLOR
3862 pcg 1.36 case 38:
3863     if (nargs > i + 2 && arg[i + 1] == 5)
3864     {
3865 pcg 1.73 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_fg);
3866 pcg 1.36 i += 2;
3867     }
3868     break;
3869     #endif
3870     case 39: /* default fg */
3871     scr_color (Color_fg, Color_fg);
3872     break;
3873    
3874     case 40:
3875     case 41: /* set bg color */
3876     case 42:
3877     case 43:
3878     case 44:
3879     case 45:
3880     case 46:
3881     case 47:
3882 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 40)), Color_bg);
3883 pcg 1.36 break;
3884 pcg 1.1 #ifdef TTY_256COLOR
3885 pcg 1.36 case 48:
3886     if (nargs > i + 2 && arg[i + 1] == 5)
3887     {
3888 pcg 1.73 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_bg);
3889 pcg 1.36 i += 2;
3890     }
3891     break;
3892     #endif
3893     case 49: /* default bg */
3894     scr_color (Color_bg, Color_bg);
3895     break;
3896 pcg 1.1
3897     #ifndef NO_BRIGHTCOLOR
3898 pcg 1.36 case 90:
3899     case 91: /* set bright fg color */
3900     case 92:
3901     case 93:
3902     case 94:
3903     case 95:
3904     case 96:
3905     case 97:
3906 pcg 1.43 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 90)),
3907 pcg 1.36 Color_fg);
3908     break;
3909     case 100:
3910     case 101: /* set bright bg color */
3911     case 102:
3912     case 103:
3913     case 104:
3914     case 105:
3915     case 106:
3916     case 107:
3917 pcg 1.43 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 100)),
3918 pcg 1.36 Color_bg);
3919     break;
3920 pcg 1.1 #endif
3921 pcg 1.36
3922     }
3923 pcg 1.1 }
3924     }
3925     /*}}} */
3926    
3927 pcg 1.93 /*{{{ (do not) process Rob Nation's own graphics mode sequences */
3928 pcg 1.1 void
3929 pcg 1.34 rxvt_term::process_graphics ()
3930 pcg 1.1 {
3931 pcg 1.81 unicode_t ch, cmd = cmd_getc ();
3932 pcg 1.1
3933 pcg 1.36 if (cmd == 'Q')
3934     { /* query graphics */
3935 pcg 1.43 tt_printf ("\033G0\n"); /* no graphics */
3936 pcg 1.36 return;
3937     }
3938     /* swallow other graphics sequences until terminating ':' */
3939     do
3940     ch = cmd_getc ();
3941     while (ch != ':');
3942 pcg 1.1 }
3943     /*}}} */
3944    
3945     /* ------------------------------------------------------------------------- */
3946    
3947     /*
3948 pcg 1.43 * Send printf () formatted output to the command.
3949 pcg 1.1 * Only use for small amounts of data.
3950     */
3951     void
3952 pcg 1.10 rxvt_term::tt_printf (const char *fmt,...)
3953 pcg 1.1 {
3954 pcg 1.10 va_list arg_ptr;
3955     unsigned char buf[256];
3956 pcg 1.1
3957 pcg 1.10 va_start (arg_ptr, fmt);
3958     vsnprintf ((char *)buf, 256, fmt, arg_ptr);
3959     va_end (arg_ptr);
3960     tt_write (buf, STRLEN (buf));
3961 pcg 1.1 }
3962    
3963     /* ---------------------------------------------------------------------- */
3964 pcg 1.10 /* Write data to the pty as typed by the user, pasted with the mouse,
3965 pcg 1.1 * or generated by us in response to a query ESC sequence.
3966     */
3967     void
3968 pcg 1.10 rxvt_term::tt_write (const unsigned char *data, unsigned int len)
3969 pcg 1.1 {
3970 pcg 1.10 enum { MAX_PTY_WRITE = 255 }; // minimum MAX_INPUT
3971    
3972     if (len)
3973     {
3974     if (v_buflen == 0)
3975     {
3976 pcg 1.34 ssize_t written = write (cmd_fd, data, min (MAX_PTY_WRITE, len));
3977    
3978     if ((unsigned int)written == len)
3979 pcg 1.10 return;
3980    
3981     data += written;
3982     len -= written;
3983     }
3984    
3985    
3986     v_buffer = (unsigned char *)realloc (v_buffer, v_buflen + len);
3987    
3988     memcpy (v_buffer + v_buflen, data, len);
3989     v_buflen += len;
3990 pcg 1.1 }
3991    
3992 pcg 1.10 for (;;)
3993     {
3994     int written = write (cmd_fd, v_buffer, min (MAX_PTY_WRITE, v_buflen));
3995    
3996     if (written > 0)
3997     {
3998     v_buflen -= written;
3999    
4000     if (v_buflen == 0)
4001     {
4002     free (v_buffer);
4003     v_buffer = 0;
4004     v_buflen = 0;
4005    
4006     pty_ev.set (EVENT_READ);
4007     return;
4008     }
4009 pcg 1.1
4010 pcg 1.10 memmove (v_buffer, v_buffer + written, v_buflen);
4011     }
4012     else if (written != -1 || (errno != EAGAIN && errno != EINTR))
4013     // original code just ignores this...
4014     destroy ();
4015     else
4016     {
4017     pty_ev.set (EVENT_READ | EVENT_WRITE);
4018     return;
4019     }
4020 pcg 1.1 }
4021     }
4022 pcg 1.10
4023 pcg 1.1 /*----------------------- end-of-file (C source) -----------------------*/
4024