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