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