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

File Contents

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