ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.12
Committed: Fri Dec 5 04:05:13 2003 UTC (20 years, 5 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.11: +107 -102 lines
Log Message:
*** empty log message ***

File Contents

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