ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.59
Committed: Wed Feb 25 15:39:48 2004 UTC (20 years, 2 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_9
Changes since 1.58: +2 -0 lines
Log Message:
*** empty log message ***

File Contents

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