ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.19
Committed: Thu Dec 18 05:45:11 2003 UTC (20 years, 4 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.18: +13 -11 lines
Log Message:
*** empty log message ***

File Contents

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