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