ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.4
Committed: Tue Nov 25 15:25:16 2003 UTC (20 years, 5 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.3: +162 -178 lines
Log Message:
*** empty log message ***

File Contents

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