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