ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.36
Committed: Sun Feb 1 01:34:41 2004 UTC (20 years, 3 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: after_astyle
Changes since 1.35: +2559 -2400 lines
Log Message:
*** empty log message ***

File Contents

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