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