ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.68
Committed: Sun Mar 14 17:33:07 2004 UTC (20 years, 1 month ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_3
Changes since 1.67: +9 -24 lines
Log Message:
*** empty log message ***

File Contents

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