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

File Contents

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