ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.3
Committed: Tue Nov 25 11:52:42 2003 UTC (20 years, 5 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.2: +339 -290 lines
Log Message:
*** empty log message ***

File Contents

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