ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.15
Committed: Tue Dec 16 23:04:13 2003 UTC (20 years, 4 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.14: +4 -38 lines
Log Message:
*** empty log message ***

File Contents

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