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

File Contents

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