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

File Contents

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