ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.14
Committed: Mon Dec 8 23:14:40 2003 UTC (20 years, 5 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.13: +32 -41 lines
Log Message:
*** empty log message ***

File Contents

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