ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.2
Committed: Mon Nov 24 17:31:27 2003 UTC (20 years, 5 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.1: +0 -0 lines
Log Message:
*** empty log message ***

File Contents

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