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

File Contents

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