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