ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.324
Committed: Fri Jun 8 20:04:12 2007 UTC (16 years, 11 months ago) by sasha
Content type: text/plain
Branch: MAIN
Changes since 1.323: +218 -60 lines
Log Message:
added preliminary support to use libAfterImage for background pixmap loading and rendering of transparency effects including blending of pixmap over background using several methods, and gaussian blurr of the transparency background

File Contents

# User Rev Content
1 root 1.309 /*----------------------------------------------------------------------*
2 pcg 1.93 * File: command.C
3 pcg 1.1 *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6     * Copyright (c) 1992 John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
7     * - original version
8     * Copyright (c) 1994 Robert Nation <nation@rocket.sanders.lockheed.com>
9     * - extensive modifications
10     * Copyright (c) 1995 Garrett D'Amore <garrett@netcom.com>
11     * - vt100 printing
12     * Copyright (c) 1995 Steven Hirsch <hirsch@emba.uvm.edu>
13     * - X11 mouse report mode and support for
14     * DEC "private mode" save/restore functions.
15     * Copyright (c) 1995 Jakub Jelinek <jj@gnu.ai.mit.edu>
16     * - key-related changes to handle Shift+function
17     * keys properly.
18     * Copyright (c) 1997 MJ Olesen <olesen@me.queensu.ca>
19     * - extensive modifications
20     * Copyright (c) 1997 Raul Garcia Garcia <rgg@tid.es>
21     * - modification and cleanups for Solaris 2.x
22     * and Linux 1.2.x
23     * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
24     * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
25     * - extensive modifications
26     * Copyright (c) 1998 Alfredo K. Kojima <kojima@windowmaker.org>
27     * Copyright (c) 2001 Marius Gedminas
28     * - Ctrl/Mod4+Tab works like Meta+Tab (options)
29     * Copyright (c) 2003 Rob McMullen <robm@flipturn.org>
30 root 1.242 * Copyright (c) 2003-2006 Marc Lehmann <pcg@goof.com>
31 pcg 1.1 *
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 root 1.227 #include "../config.h"
49     #include "rxvt.h"
50     #include "rxvtperl.h"
51 pcg 1.1 #include "version.h"
52     #include "command.h"
53    
54 root 1.190 #ifdef KEYSYM_RESOURCE
55     # include "keyboard.h"
56     #endif
57    
58 root 1.183 #include <csignal>
59 pcg 1.20
60 root 1.303 #if LINUX_YIELD_HACK
61     # include <ctime>
62     #endif
63    
64 pcg 1.1 /*----------------------------------------------------------------------*/
65    
66 pcg 1.81 #define IS_CONTROL(ch) !((ch) & 0xffffff60UL)
67    
68 root 1.145 #if ENABLE_FRILLS || ISO_14755
69 root 1.131
70 root 1.145 #define ISO_14755_STARTED 0x80000000UL
71     #define ISO_14755_51 0x40000000UL // basic (section 5.1)
72     #define ISO_14755_52 0x20000000UL // keycap (section 5.2)
73     #define ISO_14755_54 0x10000000UL // code feedback (section 5.4)
74     #define ISO_14755_MASK 0x0fffffffUL
75 root 1.131
76 root 1.145 #if ISO_14755
77 root 1.131 static unsigned short iso14755_symtab[] = {
78     // keysym, unicode
79     XK_Left, 0x2190,
80     XK_KP_Left, 0x2190,
81     XK_Up, 0x2191,
82     XK_KP_Up, 0x2191,
83     XK_Right, 0x2192,
84     XK_KP_Right, 0x2192,
85     XK_Down, 0x2193,
86     XK_KP_Down, 0x2193,
87     XK_Linefeed, 0x21b4,
88     XK_Return, 0x21b5,
89     XK_KP_Enter, 0x21b5,
90    
91     XK_Prior, 0x21de,
92     XK_Next, 0x21df,
93     XK_Tab, 0x21e5,
94     XK_ISO_Left_Tab, 0x21e6,
95     XK_Shift_L, 0x21e7,
96     XK_Shift_R, 0x21e7,
97    
98     XK_Shift_Lock, 0x21eb,
99     XK_ISO_Lock, 0x21eb,
100     XK_ISO_Lock, 0x21eb,
101     XK_Caps_Lock, 0x21ec,
102     XK_Num_Lock, 0x21ed,
103     XK_ISO_Level3_Shift, 0x21ee,
104     XK_ISO_Level3_Lock, 0x21ef,
105     XK_ISO_Group_Lock, 0x21f0,
106     XK_Home, 0x21f1,
107     XK_End, 0x21f2,
108    
109     XK_Execute, 0x2318,
110     XK_Begin, 0x2320,
111     XK_Delete, 0x2326,
112     XK_Clear, 0x2327,
113     XK_BackSpace, 0x232b,
114     XK_Insert, 0x2380,
115     XK_Control_L, 0x2388,
116     XK_Control_R, 0x2388,
117     XK_Pause, 0x2389,
118     XK_Break, 0x238a,
119     XK_Escape, 0x238b,
120     XK_Undo, 0x238c,
121     XK_Print, 0x2399,
122    
123     XK_space, 0x2423,
124 root 1.196
125     #ifdef XK_KP_Begin
126     XK_KP_Prior, 0x21de,
127     XK_KP_Next, 0x21df,
128     XK_KP_Begin, 0x2320,
129     XK_KP_Insert, 0x2380,
130     XK_KP_Delete, 0x2326,
131 root 1.131 XK_KP_Space, 0x2422,
132 root 1.196 #endif
133 root 1.131 0,
134     };
135    
136     void
137 root 1.145 rxvt_term::iso14755_54 (int x, int y)
138     {
139     x = Pixel2Col (x);
140     y = Pixel2Row (y);
141    
142 root 1.211 if (!IN_RANGE_EXC (x, 0, ncol)
143     || !IN_RANGE_EXC (y, 0, nrow))
144 root 1.145 return;
145    
146     for (;;)
147     {
148 root 1.262 const line_t &l = ROW(y + view_start);
149 root 1.208
150     text_t t = l.t[x];
151 root 1.145
152     if (t != NOCHAR || !x)
153     {
154 root 1.217 iso14755_51 (l.t[x], l.r[x], x, y);
155 root 1.145 iso14755buf = ISO_14755_54;
156     break;
157     }
158    
159     x--;
160     }
161     }
162    
163     void
164 root 1.217 rxvt_term::iso14755_51 (unicode_t ch, rend_t r, int x, int y)
165 root 1.145 {
166 root 1.163 rxvt_fontset *fs = FONTSET (r);
167     rxvt_font *f = (*fs)[fs->find_font (ch)];
168 root 1.203 wchar_t *chr, *alloc, ch2, *fname;
169 root 1.145 int len;
170    
171 root 1.203 fname = rxvt_utf8towcs (f->name);
172    
173 root 1.217 # if ENABLE_COMBINING
174 root 1.145 if (IS_COMPOSE (ch))
175     {
176     len = rxvt_composite.expand (ch, 0);
177     alloc = chr = new wchar_t[len];
178     rxvt_composite.expand (ch, chr);
179     }
180     else
181 root 1.217 # endif
182 root 1.145 {
183 root 1.163 ch2 = ch;
184    
185 root 1.145 alloc = 0;
186 root 1.163 chr = &ch2;
187 root 1.145 len = 1;
188     }
189    
190 root 1.216 char attr[80]; // plenty
191    
192     sprintf (attr, "%08x = fg %d bg %d%s%s%s%s%s%s",
193     (int)r,
194 root 1.218 fgcolor_of (r), bgcolor_of (r),
195 root 1.216 r & RS_Bold ? " bold" : "",
196     r & RS_Italic ? " italic" : "",
197     r & RS_Blink ? " blink" : "",
198     r & RS_RVid ? " rvid" : "",
199     r & RS_Uline ? " uline" : "",
200     r & RS_Careful ? " careful" : "");
201    
202 root 1.203 int width = wcswidth (fname, wcslen (fname));
203 root 1.163
204 root 1.216 max_it (width, 8+5); // for char + hey
205     max_it (width, strlen (attr));
206    
207 root 1.217 if (y >= 0)
208     {
209     y = (y >= nrow - len - 4 && x < width + 2) ? 0 : -1;
210     x = 0;
211     }
212    
213     scr_overlay_new (x, y, width, len + 2);
214 root 1.163
215     r = SET_STYLE (OVERLAY_RSTYLE, GET_STYLE (r));
216 root 1.145
217     for (int y = 0; y < len; y++)
218     {
219     char buf[9];
220    
221     ch = *chr++;
222    
223     sprintf (buf, "%8x", ch);
224     scr_overlay_set (0, y, buf);
225     scr_overlay_set (9, y, '=');
226 root 1.217 # if !UNICODE3
227 root 1.145 if (ch >= 0x10000)
228     ch = 0xfffd;
229 root 1.217 # endif
230 root 1.163 scr_overlay_set (11, y, ch, r);
231 root 1.293
232     if (WCWIDTH (ch) >= 2)
233     scr_overlay_set (12, y, NOCHAR, r);
234 root 1.145 }
235    
236 root 1.293 // {
237     // char buf[4+4+3+1];
238     // snprintf (buf, sizeof (buf), "(%.4d|%.4d)", x, y);
239     // scr_overlay_set (0, 0, buf);
240     // }
241 root 1.216 scr_overlay_set (0, len , attr);
242     scr_overlay_set (0, len + 1, fname);
243 root 1.203
244     free (fname);
245 root 1.163
246 root 1.217 # if ENABLE_COMBINING
247 root 1.145 if (alloc)
248     delete [] alloc;
249 root 1.217 # endif
250 root 1.220 }
251 root 1.145 #endif
252    
253     void
254 root 1.131 rxvt_term::commit_iso14755 ()
255     {
256     wchar_t ch[2];
257    
258 root 1.145 ch[0] = iso14755buf & ISO_14755_MASK;
259 root 1.131 ch[1] = 0;
260    
261 root 1.145 if (iso14755buf & ISO_14755_51)
262 root 1.131 {
263     char mb[16];
264     int len;
265    
266     // allow verbatim 0-bytes and control-bytes to be entered
267     if (ch[0] >= 0x20)
268     len = wcstombs (mb, ch, 16);
269     else
270     {
271     mb[0] = ch[0];
272     len = 1;
273     }
274    
275     if (len > 0)
276 root 1.234 tt_write (mb, len);
277 root 1.131 else
278     scr_bell ();
279     }
280    
281     iso14755buf = 0;
282     }
283    
284     int
285     rxvt_term::hex_keyval (XKeyEvent &ev)
286     {
287     // check wether this event corresponds to a hex digit
288     // if the modifiers had not been pressed.
289     for (int index = 0; index < 8; index++)
290     {
291     KeySym k = XLookupKeysym (&ev, index);
292    
293     if (k >= XK_KP_0 && k <= XK_KP_9) return k - XK_KP_0;
294     else if (k >= XK_0 && k <= XK_9) return k - XK_0;
295     else if (k >= XK_a && k <= XK_f) return k - XK_a + 10;
296     else if (k >= XK_A && k <= XK_F) return k - XK_A + 10;
297     }
298    
299     return -1;
300     }
301     #endif
302    
303 pcg 1.1 void
304 root 1.306 rxvt_term::key_press (XKeyEvent &ev)
305 pcg 1.1 {
306 pcg 1.49 int ctrl, meta, shft, len;
307     unsigned int newlen;
308     KeySym keysym;
309     int valid_keysym;
310 root 1.234 char kbuf[KBUFSZ];
311 pcg 1.1
312 root 1.306 #if ISO_14755
313     if (iso14755buf & ISO_14755_52)
314     return;
315     #endif
316    
317 pcg 1.36 /*
318     * use Num_Lock to toggle Keypad on/off. If Num_Lock is off, allow an
319     * escape sequence to toggle the Keypad.
320     *
321     * Always permit `shift' to override the current setting
322     */
323 root 1.195 shft = ev.state & ShiftMask;
324     ctrl = ev.state & ControlMask;
325     meta = ev.state & ModMetaMask;
326 pcg 1.14
327 pcg 1.38 if (numlock_state || (ev.state & ModNumLockMask))
328 pcg 1.36 {
329 pcg 1.38 numlock_state = (ev.state & ModNumLockMask);
330 pcg 1.43 PrivMode ((!numlock_state), PrivMode_aplKP);
331 pcg 1.36 }
332 pcg 1.14
333 pcg 1.36 kbuf[0] = 0;
334 pcg 1.14
335 pcg 1.1 #ifdef USE_XIM
336 pcg 1.36 if (Input_Context)
337     {
338     Status status_return;
339 pcg 1.1
340 pcg 1.81 #if 0
341 pcg 1.1 #ifdef X_HAVE_UTF8_STRING
342 pcg 1.48 if (enc_utf8 && 0) // currently disabled, doesn't seem to work, nor is useful
343 root 1.234 len = Xutf8LookupString (Input_Context, &ev, kbuf,
344 pcg 1.36 KBUFSZ, &keysym, &status_return);
345     else
346 pcg 1.20 #endif
347 pcg 1.81 #endif
348 pcg 1.36 {
349     wchar_t wkbuf[KBUFSZ + 1];
350    
351     // the XOpenIM manpage lies about hardcoding the locale
352     // at the point of XOpenIM, so temporarily switch locales
353     if (rs[Rs_imLocale])
354     SET_LOCALE (rs[Rs_imLocale]);
355 root 1.202
356 pcg 1.36 // assume wchar_t == unicode or better
357 pcg 1.38 len = XwcLookupString (Input_Context, &ev, wkbuf,
358 pcg 1.36 KBUFSZ, &keysym, &status_return);
359 root 1.202
360 pcg 1.36 if (rs[Rs_imLocale])
361     SET_LOCALE (locale);
362 pcg 1.17
363 pcg 1.36 if (status_return == XLookupChars
364 pcg 1.49 || status_return == XLookupBoth)
365 pcg 1.36 {
366 pcg 1.55 /* make sure the user can type ctrl-@, i.e. NUL */
367     if (len == 1 && *wkbuf == 0)
368     {
369     kbuf[0] = 0;
370     len = 1;
371     }
372     else
373     {
374     wkbuf[len] = 0;
375     len = wcstombs ((char *)kbuf, wkbuf, KBUFSZ);
376     if (len < 0)
377     len = 0;
378     }
379 pcg 1.36 }
380     else
381     len = 0;
382     }
383 pcg 1.20
384 pcg 1.36 valid_keysym = status_return == XLookupKeySym
385 pcg 1.49 || status_return == XLookupBoth;
386 pcg 1.36 }
387     else
388 pcg 1.14 #endif
389 pcg 1.36 {
390 root 1.234 len = XLookupString (&ev, kbuf, KBUFSZ, &keysym, &compose);
391 pcg 1.49 valid_keysym = keysym != NoSymbol;
392 pcg 1.36 }
393    
394     if (valid_keysym)
395     {
396 root 1.190 #ifdef KEYSYM_RESOURCE
397     if (keyboard->dispatch (this, keysym, ev.state))
398     return;
399     #endif
400    
401 root 1.208 if (saveLines)
402 pcg 1.36 {
403 pcg 1.1 #ifdef UNSHIFTED_SCROLLKEYS
404 pcg 1.36 if (!ctrl && !meta)
405 pcg 1.1 #else
406 pcg 1.36 if (IS_SCROLL_MOD)
407 root 1.131 #endif
408 pcg 1.36 {
409 pcg 1.49 int lnsppg;
410 pcg 1.1
411     #ifdef PAGING_CONTEXT_LINES
412 root 1.208 lnsppg = nrow - PAGING_CONTEXT_LINES;
413 pcg 1.1 #else
414 root 1.208 lnsppg = nrow * 4 / 5;
415 pcg 1.1 #endif
416 pcg 1.36 if (keysym == XK_Prior)
417     {
418     scr_page (UP, lnsppg);
419     return;
420     }
421     else if (keysym == XK_Next)
422     {
423     scr_page (DN, lnsppg);
424     return;
425     }
426     }
427 pcg 1.1 #ifdef SCROLL_ON_UPDOWN_KEYS
428 pcg 1.36 if (IS_SCROLL_MOD)
429     {
430     if (keysym == XK_Up)
431     {
432     scr_page (UP, 1);
433     return;
434     }
435     else if (keysym == XK_Down)
436     {
437     scr_page (DN, 1);
438     return;
439     }
440     }
441 pcg 1.1 #endif
442     #ifdef SCROLL_ON_HOMEEND_KEYS
443 pcg 1.36 if (IS_SCROLL_MOD)
444     {
445     if (keysym == XK_Home)
446     {
447     scr_move_to (0, 1);
448     return;
449     }
450     else if (keysym == XK_End)
451     {
452 root 1.263 scr_move_to (1, 1);
453 pcg 1.36 return;
454     }
455     }
456     #endif
457     }
458    
459     if (shft)
460     {
461     /* Shift + F1 - F10 generates F11 - F20 */
462     if (keysym >= XK_F1 && keysym <= XK_F10)
463     {
464     keysym += (XK_F11 - XK_F1);
465     shft = 0; /* turn off Shift */
466     }
467 root 1.145 else if (!ctrl && !meta && (priv_modes & PrivMode_ShiftKeys))
468 pcg 1.36 {
469     switch (keysym)
470     {
471     /* normal XTerm key bindings */
472     case XK_Insert: /* Shift+Insert = paste mouse selection */
473 root 1.275 selection_request (ev.time);
474 pcg 1.36 return;
475 root 1.170 #if TODO
476 pcg 1.36 /* rxvt extras */
477     case XK_KP_Add: /* Shift+KP_Add = bigger font */
478 pcg 1.51 change_font (FONT_UP);
479 pcg 1.36 return;
480     case XK_KP_Subtract: /* Shift+KP_Subtract = smaller font */
481 pcg 1.51 change_font (FONT_DN);
482 pcg 1.36 return;
483 root 1.131 #endif
484 pcg 1.36 }
485     }
486     }
487 root 1.131
488 root 1.145 #if ENABLE_FRILLS || ISO_14755
489 root 1.131 // ISO 14755 support
490     if (shft && ctrl)
491     {
492     int hv;
493    
494 root 1.145 if (iso14755buf & ISO_14755_51
495     && (keysym == XK_space || keysym == XK_KP_Space
496     || keysym == XK_Return || keysym == XK_KP_Enter))
497 root 1.131 {
498     commit_iso14755 ();
499 root 1.145 iso14755buf = ISO_14755_51;
500     # if ISO_14755
501     iso14755_51 (0);
502     # endif
503 root 1.131 return;
504     }
505 ayin 1.323 else if (keysym == XK_BackSpace)
506     {
507     iso14755buf = ((iso14755buf & ISO_14755_MASK) >> 4) | ISO_14755_51;
508     # if ISO_14755
509     iso14755_51 (iso14755buf & ISO_14755_MASK);
510     # endif
511     return;
512     }
513 root 1.131 else if ((hv = hex_keyval (ev)) >= 0)
514     {
515 root 1.145 iso14755buf = ((iso14755buf << 4) & ISO_14755_MASK)
516     | hv | ISO_14755_51;
517     # if ISO_14755
518     iso14755_51 (iso14755buf & ISO_14755_MASK);
519     # endif
520 root 1.131 return;
521     }
522     else
523 root 1.145 {
524     # if ENABLE_OVERLAY
525     scr_overlay_off ();
526     # endif
527     iso14755buf = 0;
528     }
529 root 1.131 }
530     else if ((ctrl && (keysym == XK_Shift_L || keysym == XK_Shift_R))
531     || (shft && (keysym == XK_Control_L || keysym == XK_Control_R)))
532 root 1.145 if (!(iso14755buf & ISO_14755_STARTED))
533     {
534     iso14755buf |= ISO_14755_STARTED;
535     # if ENABLE_OVERLAY
536     scr_overlay_new (0, -1, sizeof ("ISO 14755 mode") - 1, 1);
537     scr_overlay_set (0, 0, "ISO 14755 mode");
538     # endif
539     }
540 root 1.131 #endif
541    
542 pcg 1.1 #ifdef PRINTPIPE
543 pcg 1.36 if (keysym == XK_Print)
544     {
545     scr_printscreen (ctrl | shft);
546     return;
547     }
548 pcg 1.1 #endif
549    
550 pcg 1.36 if (keysym >= 0xFF00 && keysym <= 0xFFFF)
551     {
552     {
553     newlen = 1;
554     switch (keysym)
555     {
556 pcg 1.1 #ifndef NO_BACKSPACE_KEY
557 pcg 1.36 case XK_BackSpace:
558 root 1.145 if (priv_modes & PrivMode_HaveBackSpace)
559 pcg 1.36 {
560 root 1.145 kbuf[0] = (!! (priv_modes & PrivMode_BackSpace)
561 pcg 1.36 ^ !!ctrl) ? '\b' : '\177';
562     kbuf[1] = '\0';
563     }
564     else
565 root 1.145 strcpy (kbuf, key_backspace);
566 pcg 1.36 break;
567 pcg 1.1 #endif
568     #ifndef NO_DELETE_KEY
569 root 1.196 # ifdef XK_KP_Prior
570     case XK_KP_Delete:
571     /* allow shift to override */
572     if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
573     {
574     strcpy (kbuf, "\033On");
575     break;
576     }
577     /* FALLTHROUGH */
578     # endif
579 pcg 1.36 case XK_Delete:
580 root 1.145 strcpy (kbuf, key_delete);
581 pcg 1.36 break;
582 pcg 1.1 #endif
583 pcg 1.36 case XK_Tab:
584     if (shft)
585 root 1.145 strcpy (kbuf, "\033[Z");
586 pcg 1.36 else
587     {
588 pcg 1.1 #ifdef CTRL_TAB_MAKES_META
589 pcg 1.36 if (ctrl)
590     meta = 1;
591 pcg 1.1 #endif
592     #ifdef MOD4_TAB_MAKES_META
593 pcg 1.38 if (ev.state & Mod4Mask)
594 pcg 1.36 meta = 1;
595 pcg 1.1 #endif
596 pcg 1.36 newlen = 0;
597     }
598     break;
599 pcg 1.1
600     #ifdef XK_KP_Left
601 root 1.120 case XK_KP_Up: /* \033Ox or standard */
602 pcg 1.36 case XK_KP_Down: /* \033Or or standard */
603     case XK_KP_Right: /* \033Ov or standard */
604     case XK_KP_Left: /* \033Ot or standard */
605 root 1.145 if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
606 pcg 1.36 {
607 root 1.145 strcpy (kbuf, "\033OZ");
608 pcg 1.46 kbuf[2] = "txvr"[keysym - XK_KP_Left];
609 pcg 1.36 break;
610     }
611     else
612     /* translate to std. cursor key */
613     keysym = XK_Left + (keysym - XK_KP_Left);
614     /* FALLTHROUGH */
615     #endif
616     case XK_Up: /* "\033[A" */
617     case XK_Down: /* "\033[B" */
618     case XK_Right: /* "\033[C" */
619     case XK_Left: /* "\033[D" */
620 root 1.145 strcpy (kbuf, "\033[Z");
621 pcg 1.47 kbuf[2] = "DACB"[keysym - XK_Left];
622 pcg 1.36 /* do Shift first */
623     if (shft)
624 pcg 1.47 kbuf[2] = "dacb"[keysym - XK_Left];
625 pcg 1.36 else if (ctrl)
626     {
627     kbuf[1] = 'O';
628 pcg 1.47 kbuf[2] = "dacb"[keysym - XK_Left];
629 pcg 1.36 }
630 root 1.145 else if (priv_modes & PrivMode_aplCUR)
631 pcg 1.36 kbuf[1] = 'O';
632     break;
633 pcg 1.1
634     #ifndef UNSHIFTED_SCROLLKEYS
635     # ifdef XK_KP_Prior
636 pcg 1.36 case XK_KP_Prior:
637     /* allow shift to override */
638 root 1.145 if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
639 pcg 1.36 {
640 root 1.145 strcpy (kbuf, "\033Oy");
641 pcg 1.36 break;
642     }
643     /* FALLTHROUGH */
644 pcg 1.1 # endif
645 pcg 1.36 case XK_Prior:
646 root 1.145 strcpy (kbuf, "\033[5~");
647 pcg 1.36 break;
648 pcg 1.1 # ifdef XK_KP_Next
649 pcg 1.36 case XK_KP_Next:
650     /* allow shift to override */
651 root 1.145 if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
652 pcg 1.36 {
653 root 1.145 strcpy (kbuf, "\033Os");
654 pcg 1.36 break;
655     }
656     /* FALLTHROUGH */
657 pcg 1.1 # endif
658 pcg 1.36 case XK_Next:
659 root 1.145 strcpy (kbuf, "\033[6~");
660 pcg 1.36 break;
661     #endif
662     case XK_KP_Enter:
663     /* allow shift to override */
664 root 1.145 if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
665 pcg 1.36 {
666 root 1.145 strcpy (kbuf, "\033OM");
667     break;
668     }
669    
670     /* FALLTHROUGH */
671    
672     case XK_Return:
673     if (priv_modes & PrivMode_LFNL)
674     {
675     kbuf[0] = '\015';
676     kbuf[1] = '\012';
677     kbuf[2] = '\0';
678 pcg 1.36 }
679     else
680     {
681 root 1.145 kbuf[0] = '\015';
682 pcg 1.36 kbuf[1] = '\0';
683     }
684     break;
685 pcg 1.1
686     #ifdef XK_KP_Begin
687 pcg 1.36 case XK_KP_Begin:
688 root 1.145 strcpy (kbuf, "\033Ou");
689 pcg 1.36 break;
690    
691     #endif
692     case XK_KP_F1: /* "\033OP" */
693     case XK_KP_F2: /* "\033OQ" */
694     case XK_KP_F3: /* "\033OR" */
695     case XK_KP_F4: /* "\033OS" */
696 root 1.145 strcpy (kbuf, "\033OP");
697 pcg 1.36 kbuf[2] += (keysym - XK_KP_F1);
698     break;
699    
700     case XK_KP_Multiply: /* "\033Oj" : "*" */
701 pcg 1.49 case XK_KP_Add: /* "\033Ok" : "+" */
702 pcg 1.36 case XK_KP_Separator: /* "\033Ol" : "," */
703     case XK_KP_Subtract: /* "\033Om" : "-" */
704     case XK_KP_Decimal: /* "\033On" : "." */
705     case XK_KP_Divide: /* "\033Oo" : "/" */
706     case XK_KP_0: /* "\033Op" : "0" */
707     case XK_KP_1: /* "\033Oq" : "1" */
708     case XK_KP_2: /* "\033Or" : "2" */
709     case XK_KP_3: /* "\033Os" : "3" */
710     case XK_KP_4: /* "\033Ot" : "4" */
711     case XK_KP_5: /* "\033Ou" : "5" */
712     case XK_KP_6: /* "\033Ov" : "6" */
713     case XK_KP_7: /* "\033Ow" : "7" */
714     case XK_KP_8: /* "\033Ox" : "8" */
715     case XK_KP_9: /* "\033Oy" : "9" */
716     /* allow shift to override */
717 root 1.145 if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
718 pcg 1.36 {
719 root 1.145 strcpy (kbuf, "\033Oj");
720 pcg 1.36 kbuf[2] += (keysym - XK_KP_Multiply);
721     }
722     else
723     {
724     kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
725     kbuf[1] = '\0';
726     }
727     break;
728    
729     case XK_Find:
730 root 1.145 strcpy (kbuf, "\033[1~");
731 pcg 1.36 break;
732 root 1.196
733     #ifdef XK_KP_End
734     case XK_KP_Insert:
735     /* allow shift to override */
736     if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
737     {
738     strcpy (kbuf, "\033Op");
739     break;
740     }
741     /* FALLTHROUGH */
742     #endif
743 pcg 1.36 case XK_Insert:
744 root 1.145 strcpy (kbuf, "\033[2~");
745 pcg 1.36 break;
746 pcg 1.1 #ifdef DXK_Remove /* support for DEC remove like key */
747 pcg 1.36 case DXK_Remove:
748     /* FALLTHROUGH */
749 pcg 1.1 #endif
750 pcg 1.36 case XK_Execute:
751 root 1.145 strcpy (kbuf, "\033[3~");
752 pcg 1.36 break;
753     case XK_Select:
754 root 1.145 strcpy (kbuf, "\033[4~");
755 pcg 1.36 break;
756 pcg 1.1 #ifdef XK_KP_End
757 pcg 1.36 case XK_KP_End:
758     /* allow shift to override */
759 root 1.145 if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
760 pcg 1.36 {
761 root 1.145 strcpy (kbuf, "\033Oq");
762 pcg 1.36 break;
763     }
764     /* FALLTHROUGH */
765     #endif
766     case XK_End:
767 root 1.145 strcpy (kbuf, KS_END);
768 pcg 1.36 break;
769 pcg 1.1 #ifdef XK_KP_Home
770 pcg 1.36 case XK_KP_Home:
771     /* allow shift to override */
772 root 1.145 if ((priv_modes & PrivMode_aplKP) ? !shft : shft)
773 pcg 1.36 {
774 root 1.145 strcpy (kbuf, "\033Ow");
775 pcg 1.36 break;
776     }
777     /* FALLTHROUGH */
778     #endif
779     case XK_Home:
780 root 1.145 strcpy (kbuf, KS_HOME);
781 pcg 1.36 break;
782 pcg 1.1
783     #define FKEY(n, fkey) \
784 pcg 1.43 sprintf ((char *)kbuf,"\033[%2d~", (int) ((n) + (keysym - fkey)))
785 pcg 1.1
786 pcg 1.36 case XK_F1: /* "\033[11~" */
787     case XK_F2: /* "\033[12~" */
788     case XK_F3: /* "\033[13~" */
789     case XK_F4: /* "\033[14~" */
790     case XK_F5: /* "\033[15~" */
791 pcg 1.43 FKEY (11, XK_F1);
792 pcg 1.36 break;
793     case XK_F6: /* "\033[17~" */
794     case XK_F7: /* "\033[18~" */
795     case XK_F8: /* "\033[19~" */
796     case XK_F9: /* "\033[20~" */
797     case XK_F10: /* "\033[21~" */
798 pcg 1.43 FKEY (17, XK_F6);
799 pcg 1.36 break;
800     case XK_F11: /* "\033[23~" */
801     case XK_F12: /* "\033[24~" */
802     case XK_F13: /* "\033[25~" */
803     case XK_F14: /* "\033[26~" */
804 pcg 1.43 FKEY (23, XK_F11);
805 pcg 1.36 break;
806     case XK_F15: /* "\033[28~" */
807     case XK_F16: /* "\033[29~" */
808 pcg 1.43 FKEY (28, XK_F15);
809 pcg 1.36 break;
810     case XK_Help: /* "\033[28~" */
811 pcg 1.43 FKEY (28, XK_Help);
812 pcg 1.36 break;
813     case XK_Menu: /* "\033[29~" */
814 pcg 1.43 FKEY (29, XK_Menu);
815 pcg 1.36 break;
816     case XK_F17: /* "\033[31~" */
817     case XK_F18: /* "\033[32~" */
818     case XK_F19: /* "\033[33~" */
819     case XK_F20: /* "\033[34~" */
820     case XK_F21: /* "\033[35~" */
821     case XK_F22: /* "\033[36~" */
822     case XK_F23: /* "\033[37~" */
823     case XK_F24: /* "\033[38~" */
824     case XK_F25: /* "\033[39~" */
825     case XK_F26: /* "\033[40~" */
826     case XK_F27: /* "\033[41~" */
827     case XK_F28: /* "\033[42~" */
828     case XK_F29: /* "\033[43~" */
829     case XK_F30: /* "\033[44~" */
830     case XK_F31: /* "\033[45~" */
831     case XK_F32: /* "\033[46~" */
832     case XK_F33: /* "\033[47~" */
833     case XK_F34: /* "\033[48~" */
834     case XK_F35: /* "\033[49~" */
835 pcg 1.43 FKEY (31, XK_F17);
836 pcg 1.36 break;
837 pcg 1.1 #undef FKEY
838 pcg 1.36 default:
839 root 1.190 newlen = 0;
840     break;
841 pcg 1.36 }
842 root 1.183
843 pcg 1.36 if (newlen)
844 root 1.145 len = strlen (kbuf);
845 pcg 1.36 }
846 pcg 1.68
847 pcg 1.36 /*
848     * Pass meta for all function keys, if 'meta' option set
849     */
850 pcg 1.1 #ifdef META8_OPTION
851 pcg 1.36 if (meta && (meta_char == 0x80) && len > 0)
852     kbuf[len - 1] |= 0x80;
853 pcg 1.1 #endif
854 pcg 1.36
855     }
856     else if (ctrl && keysym == XK_minus)
857     {
858     len = 1;
859     kbuf[0] = '\037'; /* Ctrl-Minus generates ^_ (31) */
860     }
861 root 1.183 else if (keysym == XK_ISO_Left_Tab)
862     {
863     strcpy (kbuf, "\033[Z");
864     len = 3;
865     }
866 pcg 1.36 else
867     {
868 pcg 1.1 #ifdef META8_OPTION
869 pcg 1.36 /* set 8-bit on */
870     if (meta && (meta_char == 0x80))
871     {
872 root 1.234 char *ch;
873 pcg 1.36
874     for (ch = kbuf; ch < kbuf + len; ch++)
875     *ch |= 0x80;
876 pcg 1.68
877 pcg 1.36 meta = 0;
878     }
879 pcg 1.1 #endif
880 pcg 1.36 /* nil */ ;
881     }
882     }
883 pcg 1.1
884 root 1.252 if (HOOK_INVOKE ((this, HOOK_KEY_PRESS, DT_XEVENT, &ev, DT_INT, keysym, DT_STR_LEN, kbuf, len, DT_END)))
885 root 1.240 return;
886    
887 pcg 1.36 if (len <= 0)
888     return; /* not mapped */
889 pcg 1.1
890 root 1.321 if (option (Opt_scrollTtyKeypress))
891 root 1.208 if (view_start)
892 pcg 1.36 {
893 root 1.208 view_start = 0;
894 pcg 1.36 want_refresh = 1;
895     }
896 pcg 1.1
897 pcg 1.36 /*
898     * these modifications only affect the static keybuffer
899     * pass Shift/Control indicators for function keys ending with `~'
900     *
901     * eg,
902     * Prior = "ESC[5~"
903     * Shift+Prior = "ESC[5$"
904     * Ctrl+Prior = "ESC[5^"
905     * Ctrl+Shift+Prior = "ESC[5@"
906     * Meta adds an Escape prefix (with META8_OPTION, if meta == <escape>).
907     */
908     if (kbuf[0] == C0_ESC && kbuf[1] == '[' && kbuf[len - 1] == '~')
909     kbuf[len - 1] = (shft ? (ctrl ? '@' : '$') : (ctrl ? '^' : '~'));
910 pcg 1.1
911 pcg 1.36 /* escape prefix */
912     if (meta
913 pcg 1.1 #ifdef META8_OPTION
914 pcg 1.55 && meta_char == C0_ESC
915 pcg 1.1 #endif
916 pcg 1.36 )
917     {
918 root 1.234 const char ch = C0_ESC;
919 pcg 1.43 tt_write (&ch, 1);
920 pcg 1.1 }
921 pcg 1.55
922 pcg 1.36 tt_write (kbuf, (unsigned int)len);
923 pcg 1.1 }
924 root 1.306
925     void
926     rxvt_term::key_release (XKeyEvent &ev)
927     {
928     #if (MOUSE_WHEEL && MOUSE_SLIP_WHEELING) || ISO_14755 || ENABLE_PERL
929     KeySym keysym;
930    
931     keysym = XLookupKeysym (&ev, ev.state & ShiftMask ? 1 : 0); // sorry, only shift supported :/
932     #endif
933    
934     #if ENABLE_FRILLS || ISO_14755
935     // ISO 14755 support
936     if (iso14755buf)
937     if (iso14755buf & ISO_14755_52)
938     {
939     # if ENABLE_OVERLAY
940     scr_overlay_off ();
941     # endif
942     # if ISO_14755
943     // iso14755 part 5.2 handling: release time
944     // first: controls
945     if ((ev.state & ControlMask)
946     && ((keysym >= 0x40 && keysym <= 0x5f)
947     || (keysym >= 0x61 && keysym <= 0x7f)))
948     {
949     iso14755buf = ISO_14755_51 | 0x2400 | (keysym & 0x1f);
950     commit_iso14755 ();
951    
952     return;
953     }
954    
955     for (unsigned short *i = iso14755_symtab; i[0]; i+= 2)
956     if (i[0] == keysym)
957     {
958     iso14755buf = ISO_14755_51 | i[1];
959     commit_iso14755 ();
960    
961     return;
962     }
963    
964     scr_bell ();
965     # endif
966     iso14755buf = 0;
967    
968     return;
969     }
970     else if ((ev.state & (ShiftMask | ControlMask)) != (ShiftMask | ControlMask))
971     {
972     # if ENABLE_OVERLAY
973     scr_overlay_off ();
974     # endif
975     if (iso14755buf & ISO_14755_51)
976     commit_iso14755 ();
977     #if ISO_14755
978     else if (iso14755buf & ISO_14755_STARTED)
979     {
980     iso14755buf = ISO_14755_52; // iso14755 part 5.2: remember empty begin/end pair
981    
982     scr_overlay_new (0, -1, sizeof ("KEYCAP PICTURE INSERT MODE") - 1, 1);
983     scr_overlay_set (0, 0, "KEYCAP PICTURE INSERT MODE");
984     }
985     # endif
986     else
987     iso14755buf = 0;
988     }
989     #endif
990    
991     if (HOOK_INVOKE ((this, HOOK_KEY_RELEASE, DT_XEVENT, &ev, DT_INT, keysym, DT_END)))
992     return;
993    
994     #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
995     if (!(ev.state & ControlMask))
996     slip_wheel_ev.stop ();
997     else if (keysym == XK_Control_L || keysym == XK_Control_R)
998     mouse_slip_wheel_speed = 0;
999     #endif
1000     }
1001 pcg 1.1
1002 root 1.267 #if defined (KEYSYM_RESOURCE)
1003 pcg 1.1 unsigned int
1004 root 1.234 rxvt_term::cmd_write (const char *str, unsigned int count)
1005 pcg 1.1 {
1006 pcg 1.81 unsigned int n, s;
1007 pcg 1.1
1008 pcg 1.36 n = cmdbuf_ptr - cmdbuf_base;
1009 pcg 1.81 s = cmdbuf_base + CBUFSIZ - 1 - cmdbuf_endp;
1010 pcg 1.57
1011 pcg 1.36 if (n > 0 && s < count)
1012     {
1013 root 1.145 memmove (cmdbuf_base, cmdbuf_ptr,
1014 pcg 1.43 (unsigned int) (cmdbuf_endp - cmdbuf_ptr));
1015 pcg 1.36 cmdbuf_ptr = cmdbuf_base;
1016     cmdbuf_endp -= n;
1017     s += n;
1018     }
1019 pcg 1.57
1020 pcg 1.36 if (count > s)
1021     {
1022 pcg 1.81 rxvt_warn ("data loss: cmd_write too large, continuing.\n");
1023 pcg 1.36 count = s;
1024     }
1025 pcg 1.57
1026 pcg 1.36 for (; count--;)
1027     *cmdbuf_endp++ = *str++;
1028 pcg 1.57
1029     cmd_parse ();
1030    
1031 pcg 1.36 return 0;
1032 pcg 1.1 }
1033 root 1.190 #endif
1034 pcg 1.1
1035 pcg 1.3 void
1036 pcg 1.11 rxvt_term::flush ()
1037     {
1038 root 1.168 flush_ev.stop ();
1039    
1040 pcg 1.11 #ifdef TRANSPARENT
1041     if (want_full_refresh)
1042     {
1043     want_full_refresh = 0;
1044 pcg 1.22 scr_clear ();
1045     scr_touch (false);
1046 pcg 1.11 }
1047     #endif
1048    
1049     if (want_refresh)
1050     {
1051 root 1.237 if (SHOULD_INVOKE (HOOK_LINE_UPDATE))
1052     {
1053 root 1.262 int row = view_start;
1054 root 1.250 int end_row = row + nrow;
1055 root 1.237
1056 root 1.262 while (row > top_row && ROW (row - 1).is_longer ())
1057 root 1.237 --row;
1058    
1059 root 1.250 do
1060 root 1.237 {
1061     int start_row = row;
1062     line_t *l;
1063    
1064     do
1065     {
1066 root 1.255 l = &ROW (row++);
1067 root 1.237
1068 root 1.255 if (!(l->f & LINE_FILTERED))
1069 root 1.237 {
1070     // line not filtered, mark it as filtered
1071     l->f |= LINE_FILTERED;
1072     while (l->is_longer ())
1073     {
1074 root 1.255 l = &ROW (row++);
1075 root 1.237 l->f |= LINE_FILTERED;
1076     }
1077    
1078     // and filter it
1079     HOOK_INVOKE ((this, HOOK_LINE_UPDATE, DT_INT, start_row, DT_END));
1080    
1081     break;
1082     }
1083     }
1084 root 1.250 while (l->is_longer () && row < end_row);
1085 root 1.237 }
1086 root 1.255 while (row < end_row);
1087 root 1.237 }
1088    
1089 root 1.268 scr_refresh ();
1090 pcg 1.34 scrollbar_show (1);
1091 pcg 1.11 #ifdef USE_XIM
1092 pcg 1.34 IMSendSpot ();
1093 pcg 1.11 #endif
1094     }
1095    
1096 pcg 1.42 display->flush ();
1097 pcg 1.11 }
1098    
1099     void
1100     rxvt_term::check_cb (check_watcher &w)
1101     {
1102 root 1.264 make_current ();
1103 pcg 1.11
1104 root 1.116 display->flush ();
1105    
1106 root 1.120 if (want_refresh && !flush_ev.active)
1107 root 1.226 flush_ev.start (NOW + 1. / 60.); // refresh at max. 60 hz normally
1108 root 1.116 }
1109    
1110     void
1111     rxvt_term::flush_cb (time_watcher &w)
1112     {
1113 root 1.264 make_current ();
1114 root 1.116
1115     refresh_limit = 1;
1116     refresh_count = 0;
1117 pcg 1.11 flush ();
1118     }
1119    
1120 pcg 1.27 #ifdef CURSOR_BLINK
1121 pcg 1.3 void
1122 pcg 1.31 rxvt_term::cursor_blink_cb (time_watcher &w)
1123 pcg 1.5 {
1124     hidden_cursor = !hidden_cursor;
1125     want_refresh = 1;
1126 pcg 1.28
1127 root 1.274 w.start (w.at + CURSOR_BLINK_INTERVAL);
1128 pcg 1.5 }
1129 pcg 1.27 #endif
1130 pcg 1.5
1131 pcg 1.31 #ifdef TEXT_BLINK
1132     void
1133     rxvt_term::text_blink_cb (time_watcher &w)
1134     {
1135     if (scr_refresh_rend (RS_Blink, RS_Blink))
1136     {
1137     hidden_text = !hidden_text;
1138     want_refresh = 1;
1139     w.start (w.at + TEXT_BLINK_INTERVAL);
1140     }
1141     }
1142     #endif
1143    
1144 root 1.97 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1145     void
1146     rxvt_term::cont_scroll_cb (time_watcher &w)
1147     {
1148     if ((scrollbar_isUp() || scrollbar_isDn()) &&
1149     scr_page (scrollbar_isUp() ? UP : DN, 1))
1150     {
1151     want_refresh = 1;
1152     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
1153     }
1154     }
1155     #endif
1156    
1157     #ifdef SELECTION_SCROLLING
1158     void
1159     rxvt_term::sel_scroll_cb (time_watcher &w)
1160     {
1161     if (scr_page (scroll_selection_dir, scroll_selection_lines))
1162     {
1163     selection_extend (selection_save_x, selection_save_y, selection_save_state);
1164     want_refresh = 1;
1165     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
1166     }
1167     }
1168     #endif
1169    
1170     #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
1171     void
1172     rxvt_term::slip_wheel_cb (time_watcher &w)
1173     {
1174     if (mouse_slip_wheel_speed == 0
1175     || mouse_slip_wheel_speed < 0 ? scr_page (DN, -mouse_slip_wheel_speed)
1176     : scr_page (UP, mouse_slip_wheel_speed))
1177     {
1178 root 1.262 if (view_start == top_row || view_start == 0)
1179 root 1.190 mouse_slip_wheel_speed = 0;
1180    
1181 root 1.97 want_refresh = 1;
1182     w.start (w.at + SCROLLBAR_CONTINUOUS_DELAY);
1183     }
1184     }
1185     #endif
1186    
1187 root 1.302 #if LINUX_YIELD_HACK
1188     static struct event_handler
1189     {
1190     check_watcher yield_ev;
1191    
1192     void yield_cb (check_watcher &w)
1193     {
1194 root 1.303 // this should really be sched_yield(), but the linux guys thought
1195     // that giving a process calling sched_yield () less cpu time than
1196 root 1.304 // ones with high nice levels is a useful thing to do. It surely is is
1197     // allowed by the sus... as is returning ENOSYS.
1198 root 1.303
1199     struct timespec ts = { 0, 0 };
1200     nanosleep (&ts, 0);
1201    
1202 root 1.302 w.stop ();
1203     }
1204    
1205     event_handler ()
1206     : yield_ev (this, &event_handler::yield_cb)
1207     {
1208     }
1209     } event_handler;
1210     #endif
1211    
1212 pcg 1.4 bool
1213 pcg 1.8 rxvt_term::pty_fill ()
1214 pcg 1.4 {
1215     ssize_t n = cmdbuf_endp - cmdbuf_ptr;
1216    
1217 pcg 1.93 if (CBUFSIZ == n)
1218     {
1219 root 1.233 rxvt_warn ("PLEASE REPORT: pty_fill on full buffer, draining input, continuing.\n");
1220 pcg 1.93 n = 0;
1221     }
1222    
1223 pcg 1.4 memmove (cmdbuf_base, cmdbuf_ptr, n);
1224     cmdbuf_ptr = cmdbuf_base;
1225     cmdbuf_endp = cmdbuf_ptr + n;
1226 pcg 1.36
1227 root 1.269 ssize_t r = read (pty->pty, cmdbuf_endp, CBUFSIZ - n);
1228 pcg 1.4
1229 root 1.223 if (r > 0)
1230 pcg 1.4 {
1231 root 1.223 cmdbuf_endp += r;
1232 pcg 1.4 return true;
1233     }
1234 root 1.223 else if (r < 0 && (errno == EAGAIN || errno == EINTR))
1235     {
1236 root 1.302 #if LINUX_YIELD_HACK
1237 root 1.228 if (display->is_local)
1238 root 1.302 event_handler.yield_ev.start ();
1239 root 1.223 #endif
1240     }
1241     else
1242 root 1.215 {
1243     pty_ev.stop ();
1244    
1245 root 1.321 if (!option (Opt_hold))
1246 root 1.215 destroy ();
1247     }
1248 pcg 1.57
1249 pcg 1.13 return false;
1250 pcg 1.4 }
1251    
1252 pcg 1.3 void
1253     rxvt_term::pty_cb (io_watcher &w, short revents)
1254     {
1255 root 1.264 make_current ();
1256 pcg 1.9
1257 root 1.177 if (revents & EVENT_READ)
1258 pcg 1.93 // loop, but don't allow a single term to monopolize us
1259     while (pty_fill ())
1260     if (cmd_parse ())
1261     break;
1262 root 1.177
1263     if (revents & EVENT_WRITE)
1264     pty_write ();
1265 pcg 1.57 }
1266    
1267 pcg 1.6 void
1268     rxvt_term::pointer_unblank ()
1269     {
1270 root 1.305 XDefineCursor (dpy, vt, TermWin_cursor);
1271 pcg 1.19 recolour_cursor ();
1272 pcg 1.7
1273 root 1.107 #ifdef POINTER_BLANK
1274 pcg 1.6 hidden_pointer = 0;
1275 pcg 1.1
1276 root 1.321 if (option (Opt_pointerBlank))
1277 pcg 1.7 pointer_ev.start (NOW + pointerBlankDelay);
1278 root 1.107 #endif
1279 pcg 1.1 }
1280    
1281 root 1.107 #ifdef POINTER_BLANK
1282 pcg 1.1 void
1283 pcg 1.6 rxvt_term::pointer_blank ()
1284 pcg 1.1 {
1285 root 1.321 if (!option (Opt_pointerBlank))
1286 pcg 1.6 return;
1287    
1288 root 1.305 XDefineCursor (dpy, vt, display->blank_cursor);
1289     XFlush (dpy);
1290 pcg 1.1
1291 pcg 1.6 hidden_pointer = 1;
1292 pcg 1.1 }
1293    
1294     void
1295 pcg 1.6 rxvt_term::pointer_cb (time_watcher &w)
1296 pcg 1.1 {
1297 root 1.264 make_current ();
1298 pcg 1.9
1299 pcg 1.6 pointer_blank ();
1300 pcg 1.1 }
1301     #endif
1302    
1303     void
1304 pcg 1.56 rxvt_term::mouse_report (XButtonEvent &ev)
1305 pcg 1.1 {
1306 pcg 1.56 int button_number, key_state = 0;
1307     int x, y;
1308 pcg 1.36
1309 pcg 1.38 x = ev.x;
1310     y = ev.y;
1311 pcg 1.36 pixel_position (&x, &y);
1312    
1313     if (MEvent.button == AnyButton)
1314 root 1.145 button_number = 3;
1315 pcg 1.36 else
1316     {
1317     button_number = MEvent.button - Button1;
1318     /* add 0x3D for wheel events, like xterm does */
1319     if (button_number >= 3)
1320     button_number += (64 - 3);
1321     }
1322 pcg 1.1
1323 root 1.145 if (priv_modes & PrivMode_MouseX10)
1324 pcg 1.36 {
1325     /*
1326     * do not report ButtonRelease
1327     * no state info allowed
1328     */
1329     key_state = 0;
1330     if (button_number == 3)
1331     return;
1332     }
1333     else
1334     {
1335     /* XTerm mouse reporting needs these values:
1336     * 4 = Shift
1337     * 8 = Meta
1338     * 16 = Control
1339     * plus will add in our own Double-Click reporting
1340     * 32 = Double Click
1341     */
1342     key_state = ((MEvent.state & ShiftMask) ? 4 : 0)
1343     + ((MEvent.state & ModMetaMask) ? 8 : 0)
1344     + ((MEvent.state & ControlMask) ? 16 : 0);
1345 pcg 1.1 #ifdef MOUSE_REPORT_DOUBLECLICK
1346 pcg 1.36 key_state += ((MEvent.clicks > 1) ? 32 : 0);
1347 pcg 1.1 #endif
1348     }
1349    
1350 root 1.163 #if DEBUG_MOUSEREPORT
1351 pcg 1.43 fprintf (stderr, "Mouse [");
1352 pcg 1.36 if (key_state & 16)
1353 pcg 1.43 fputc ('C', stderr);
1354 pcg 1.36 if (key_state & 4)
1355 pcg 1.43 fputc ('S', stderr);
1356 pcg 1.36 if (key_state & 8)
1357 pcg 1.43 fputc ('A', stderr);
1358 pcg 1.36 if (key_state & 32)
1359 pcg 1.43 fputc ('2', stderr);
1360     fprintf (stderr, "]: <%d>, %d/%d\n",
1361 pcg 1.36 button_number,
1362     x + 1,
1363     y + 1);
1364 root 1.163 #endif
1365    
1366 pcg 1.43 tt_printf ("\033[M%c%c%c",
1367 pcg 1.36 (32 + button_number + key_state),
1368     (32 + x + 1),
1369     (32 + y + 1));
1370 pcg 1.1 }
1371    
1372     /*{{{ process an X event */
1373     void
1374 pcg 1.38 rxvt_term::x_cb (XEvent &ev)
1375 pcg 1.1 {
1376 root 1.264 make_current ();
1377    
1378 root 1.305 dLocal (Display *, dpy);
1379 root 1.192
1380 root 1.259 if (ev.xany.window == vt
1381 root 1.265 && SHOULD_INVOKE (HOOK_X_EVENT)
1382 root 1.259 && HOOK_INVOKE ((this, HOOK_X_EVENT, DT_XEVENT, &ev, DT_END)))
1383     return;
1384    
1385 root 1.260 // for XQueryPointer
1386 root 1.175 Window unused_root, unused_child;
1387     int unused_root_x, unused_root_y;
1388     unsigned int unused_mask;
1389 pcg 1.3
1390 pcg 1.38 switch (ev.type)
1391 pcg 1.36 {
1392     case KeyPress:
1393 root 1.306 key_press (ev.xkey);
1394 pcg 1.36 break;
1395 pcg 1.1
1396 pcg 1.36 case KeyRelease:
1397 root 1.306 key_release (ev.xkey);
1398     break;
1399 pcg 1.36
1400     case ButtonPress:
1401 pcg 1.38 button_press (ev.xbutton);
1402 pcg 1.36 break;
1403    
1404     case ButtonRelease:
1405 pcg 1.38 button_release (ev.xbutton);
1406 pcg 1.36 break;
1407    
1408     case ClientMessage:
1409 root 1.277 if (ev.xclient.format == 32
1410     && !HOOK_INVOKE ((this, HOOK_CLIENT_MESSAGE, DT_XEVENT, &ev, DT_END)))
1411 root 1.200 {
1412 root 1.276 if (ev.xclient.message_type == xa[XA_WM_PROTOCOLS])
1413     {
1414 root 1.277 if (!HOOK_INVOKE ((this, HOOK_WM_PROTOCOLS, DT_XEVENT, &ev, DT_END)))
1415 root 1.276 {
1416 root 1.277 if (ev.xclient.data.l[0] == xa[XA_WM_DELETE_WINDOW])
1417     {
1418     if (!HOOK_INVOKE ((this, HOOK_WM_DELETE_WINDOW, DT_XEVENT, &ev, DT_END)))
1419     destroy ();
1420     }
1421 root 1.200 #if ENABLE_EWMH
1422 root 1.277 else if (ev.xclient.data.l[0] == xa[XA_NET_WM_PING])
1423 root 1.305 XSendEvent (dpy, ev.xclient.window = display->root,
1424 root 1.277 False, SubstructureRedirectMask | SubstructureNotifyMask,
1425     &ev);
1426 root 1.200 #endif
1427 root 1.277 }
1428 root 1.276 }
1429 root 1.198 #if ENABLE_XEMBED
1430 root 1.276 else if (ev.xclient.format == 32 && ev.xclient.message_type == xa[XA_XEMBED])
1431     {
1432     if (ev.xclient.data.l[1] == XEMBED_FOCUS_IN)
1433     focus_in ();
1434     else if (ev.xclient.data.l[1] == XEMBED_FOCUS_OUT)
1435     focus_out ();
1436     }
1437 root 1.198 #endif
1438 pcg 1.36 }
1439     break;
1440 pcg 1.1
1441 pcg 1.36 case MappingNotify:
1442 root 1.116 XRefreshKeyboardMapping (&ev.xmapping);
1443 pcg 1.36 break;
1444    
1445     /*
1446     * XXX: this is not the _current_ arrangement
1447     * Here's my conclusion:
1448     * If the window is completely unobscured, use bitblt's
1449     * to scroll. Even then, they're only used when doing partial
1450     * screen scrolling. When partially obscured, we have to fill
1451     * in the GraphicsExpose parts, which means that after each refresh,
1452     * we need to wait for the graphics expose or Noexpose events,
1453     * which ought to make things real slow!
1454     */
1455     case VisibilityNotify:
1456 pcg 1.38 switch (ev.xvisibility.state)
1457 pcg 1.8 {
1458     case VisibilityUnobscured:
1459 pcg 1.34 refresh_type = FAST_REFRESH;
1460 pcg 1.8 break;
1461     case VisibilityPartiallyObscured:
1462 pcg 1.34 refresh_type = SLOW_REFRESH;
1463 pcg 1.8 break;
1464     default:
1465 pcg 1.34 refresh_type = NO_REFRESH;
1466 pcg 1.8 break;
1467     }
1468 pcg 1.36 break;
1469 pcg 1.1
1470 pcg 1.36 case FocusIn:
1471 root 1.320 if (ev.xfocus.detail != NotifyInferior
1472     && ev.xfocus.detail != NotifyPointer
1473     && ev.xfocus.mode != NotifyGrab)
1474 root 1.316 focus_in ();
1475 pcg 1.36 break;
1476    
1477     case FocusOut:
1478 root 1.320 if (ev.xfocus.detail != NotifyInferior
1479     && ev.xfocus.detail != NotifyPointer
1480     && ev.xfocus.mode != NotifyGrab)
1481 root 1.316 focus_out ();
1482 pcg 1.36 break;
1483    
1484     case ConfigureNotify:
1485 root 1.208 if (ev.xconfigure.window == parent[0])
1486 pcg 1.36 {
1487 root 1.305 while (XCheckTypedWindowEvent (dpy, ev.xconfigure.window, ConfigureNotify, &ev))
1488 root 1.208 ;
1489 pcg 1.38
1490 root 1.208 if (szHint.width != ev.xconfigure.width || szHint.height != ev.xconfigure.height)
1491 root 1.163 {
1492     seen_resize = 1;
1493 root 1.208 resize_all_windows (ev.xconfigure.width, ev.xconfigure.height, 1);
1494 sasha 1.324 #ifdef XPM_BACKGROUND
1495     if (!option(Opt_transparent) && bgPixmap.auto_resize)
1496     {
1497     resize_pixmap ();
1498     scr_touch (true);
1499     }
1500     #endif
1501 root 1.163 }
1502 root 1.116
1503 root 1.270 HOOK_INVOKE ((this, HOOK_CONFIGURE_NOTIFY, DT_XEVENT, &ev, DT_END));
1504    
1505 root 1.318 #ifdef TRANSPARENT
1506 root 1.321 if (option (Opt_transparent))
1507 root 1.175 check_our_parents ();
1508 pcg 1.36 #endif
1509     }
1510     break;
1511    
1512 root 1.131 case PropertyNotify:
1513 root 1.278 if (!HOOK_INVOKE ((this, HOOK_PROPERTY_NOTIFY, DT_XEVENT, &ev, DT_END)))
1514     if (ev.xproperty.atom == xa[XA_VT_SELECTION]
1515     && ev.xproperty.state == PropertyNewValue)
1516     selection_property (ev.xproperty.window, ev.xproperty.atom);
1517 root 1.131
1518     break;
1519    
1520 pcg 1.36 case SelectionClear:
1521 pcg 1.81 selection_clear ();
1522 pcg 1.36 break;
1523    
1524     case SelectionNotify:
1525     if (selection_wait == Sel_normal)
1526 root 1.176 selection_paste (ev.xselection.requestor, ev.xselection.property, true);
1527 pcg 1.36 break;
1528    
1529     case SelectionRequest:
1530 pcg 1.38 selection_send (ev.xselectionrequest);
1531 pcg 1.36 break;
1532 pcg 1.1
1533 root 1.247 case MapNotify:
1534     mapped = 1;
1535 pcg 1.31 #ifdef TEXT_BLINK
1536 root 1.247 text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL);
1537 pcg 1.31 #endif
1538 root 1.247 HOOK_INVOKE ((this, HOOK_MAP_NOTIFY, DT_XEVENT, &ev, DT_END));
1539 pcg 1.36 break;
1540 pcg 1.1
1541 root 1.247 case UnmapNotify:
1542     mapped = 0;
1543 pcg 1.31 #ifdef TEXT_BLINK
1544 root 1.247 text_blink_ev.stop ();
1545 pcg 1.31 #endif
1546 root 1.247 HOOK_INVOKE ((this, HOOK_UNMAP_NOTIFY, DT_XEVENT, &ev, DT_END));
1547 pcg 1.36 break;
1548 pcg 1.1
1549     #ifdef TRANSPARENT
1550 pcg 1.36 case ReparentNotify:
1551 pcg 1.38 rootwin_cb (ev);
1552     break;
1553 pcg 1.1 #endif /* TRANSPARENT */
1554    
1555 pcg 1.36 case GraphicsExpose:
1556     case Expose:
1557 root 1.208 if (ev.xany.window == vt)
1558 pcg 1.36 {
1559 root 1.116 do
1560     scr_expose (ev.xexpose.x, ev.xexpose.y,
1561     ev.xexpose.width, ev.xexpose.height, False);
1562 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, ev.xany.type, &ev));
1563 root 1.116
1564     ev.xany.type = ev.xany.type == Expose ? GraphicsExpose : Expose;
1565    
1566 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, ev.xany.type, &ev))
1567 root 1.116 scr_expose (ev.xexpose.x, ev.xexpose.y,
1568     ev.xexpose.width, ev.xexpose.height, False);
1569    
1570 root 1.254 want_refresh = 1;
1571 pcg 1.36 }
1572     else
1573     {
1574 pcg 1.38 XEvent unused_event;
1575 pcg 1.36
1576 root 1.305 while (XCheckTypedWindowEvent (dpy, ev.xany.window, Expose, &unused_event))
1577 pcg 1.95 ;
1578 root 1.305 while (XCheckTypedWindowEvent (dpy, ev.xany.window, GraphicsExpose, &unused_event))
1579 pcg 1.95 ;
1580    
1581 pcg 1.43 if (isScrollbarWindow (ev.xany.window))
1582 pcg 1.36 {
1583 pcg 1.43 scrollBar.setIdle ();
1584 pcg 1.36 scrollbar_show (0);
1585     }
1586 root 1.116
1587     #ifdef TRANSPARENT
1588 root 1.208 if (am_transparent && ev.xany.window == parent[0])
1589 root 1.305 XClearWindow (dpy, ev.xany.window);
1590 root 1.116 #endif
1591 pcg 1.36 }
1592     break;
1593    
1594     case MotionNotify:
1595 pcg 1.1 #ifdef POINTER_BLANK
1596 pcg 1.36 if (hidden_pointer)
1597     pointer_unblank ();
1598 pcg 1.1 #endif
1599 root 1.168 if ((priv_modes & PrivMode_mouse_report) && !bypass_keystate)
1600 pcg 1.36 break;
1601    
1602 root 1.208 if (ev.xany.window == vt)
1603 pcg 1.36 {
1604 root 1.265 if (SHOULD_INVOKE (HOOK_MOTION_NOTIFY)
1605     && HOOK_INVOKE ((this, HOOK_MOTION_NOTIFY, DT_XEVENT, &ev, DT_END)))
1606 root 1.240 ; // nop
1607     else if (ev.xbutton.state & (Button1Mask | Button3Mask))
1608 pcg 1.36 {
1609 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, MotionNotify, &ev))
1610 pcg 1.38 ;
1611    
1612 root 1.305 XQueryPointer (dpy, vt,
1613 root 1.145 &unused_root, &unused_child,
1614     &unused_root_x, &unused_root_y,
1615 root 1.168 &ev.xbutton.x, &ev.xbutton.y,
1616     &ev.xbutton.state);
1617 pcg 1.1 #ifdef MOUSE_THRESHOLD
1618 pcg 1.36 /* deal with a `jumpy' mouse */
1619 pcg 1.38 if ((ev.xmotion.time - MEvent.time) > MOUSE_THRESHOLD)
1620 pcg 1.36 {
1621 pcg 1.1 #endif
1622 root 1.145 #if ISO_14755
1623     // 5.4
1624     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
1625     {
1626     iso14755_54 (ev.xbutton.x, ev.xbutton.y);
1627     break;
1628     }
1629     #endif
1630     selection_extend (ev.xbutton.x, ev.xbutton.y,
1631 root 1.168 ev.xbutton.state & Button3Mask ? 2 : 0);
1632    
1633 pcg 1.1 #ifdef SELECTION_SCROLLING
1634 root 1.208 if (ev.xbutton.y < int_bwidth
1635     || Pixel2Row (ev.xbutton.y) > (nrow-1))
1636 pcg 1.36 {
1637     int dist;
1638    
1639     /* don't clobber the current delay if we are
1640     * already in the middle of scrolling.
1641     */
1642 root 1.97 if (!sel_scroll_ev.active)
1643     sel_scroll_ev.start (NOW + SCROLLBAR_INITIAL_DELAY);
1644 pcg 1.36
1645     /* save the event params so we can highlight
1646     * the selection in the pending-scroll loop
1647     */
1648 root 1.145 selection_save_x = ev.xbutton.x;
1649     selection_save_y = ev.xbutton.y;
1650     selection_save_state = (ev.xbutton.state & Button3Mask) ? 2 : 0;
1651 pcg 1.36
1652     /* calc number of lines to scroll */
1653 root 1.208 if (ev.xbutton.y < int_bwidth)
1654 pcg 1.36 {
1655     scroll_selection_dir = UP;
1656 root 1.208 dist = int_bwidth - ev.xbutton.y;
1657 pcg 1.36 }
1658     else
1659     {
1660     scroll_selection_dir = DN;
1661 root 1.208 dist = ev.xbutton.y - (int_bwidth + height);
1662 pcg 1.36 }
1663 root 1.145
1664     scroll_selection_lines = Pixel2Height (dist)
1665     / SELECTION_SCROLL_LINE_SPEEDUP
1666     + 1;
1667 root 1.212 min_it (scroll_selection_lines,
1668 root 1.145 SELECTION_SCROLL_MAX_LINES);
1669 pcg 1.36 }
1670     else
1671     {
1672     /* we are within the text window, so we
1673     * shouldn't be scrolling
1674     */
1675 root 1.97 if (sel_scroll_ev.active)
1676     sel_scroll_ev.stop();
1677 pcg 1.36 }
1678 pcg 1.1 #endif
1679     #ifdef MOUSE_THRESHOLD
1680 pcg 1.36 }
1681 pcg 1.1 #endif
1682 pcg 1.36 }
1683     }
1684 pcg 1.43 else if (isScrollbarWindow (ev.xany.window) && scrollbar_isMotion ())
1685 pcg 1.36 {
1686 root 1.305 while (XCheckTypedWindowEvent (dpy, scrollBar.win,
1687 root 1.168 MotionNotify, &ev))
1688     ;
1689    
1690 root 1.305 XQueryPointer (dpy, scrollBar.win,
1691 pcg 1.36 &unused_root, &unused_child,
1692     &unused_root_x, &unused_root_y,
1693 root 1.168 &ev.xbutton.x, &ev.xbutton.y,
1694 pcg 1.36 &unused_mask);
1695 pcg 1.43 scr_move_to (scrollbar_position (ev.xbutton.y) - csrO,
1696     scrollbar_size ());
1697 root 1.254 want_refresh = 1;
1698 pcg 1.36 refresh_limit = 0;
1699     scrollbar_show (1);
1700     }
1701     break;
1702     }
1703 root 1.248
1704     #if defined(CURSOR_BLINK)
1705 root 1.321 if (option (Opt_cursorBlink) && ev.type == KeyPress)
1706 root 1.248 {
1707     if (hidden_cursor)
1708     {
1709     hidden_cursor = 0;
1710     want_refresh = 1;
1711     }
1712    
1713 root 1.274 cursor_blink_ev.start (NOW + CURSOR_BLINK_INTERVAL);
1714 root 1.248 }
1715     #endif
1716    
1717     #if defined(POINTER_BLANK)
1718 root 1.321 if (option (Opt_pointerBlank) && pointerBlankDelay > 0)
1719 root 1.248 {
1720     if (ev.type == MotionNotify
1721     || ev.type == ButtonPress
1722     || ev.type == ButtonRelease)
1723     if (hidden_pointer)
1724     pointer_unblank ();
1725    
1726     if (ev.type == KeyPress && hidden_pointer == 0)
1727     pointer_blank ();
1728     }
1729     #endif
1730 pcg 1.36 }
1731 pcg 1.1
1732 root 1.198 void
1733     rxvt_term::focus_in ()
1734     {
1735 root 1.208 if (!focus)
1736 root 1.198 {
1737 root 1.208 focus = 1;
1738 root 1.296 want_refresh = 1;
1739 root 1.227
1740 root 1.308 HOOK_INVOKE ((this, HOOK_FOCUS_IN, DT_END));
1741 root 1.227
1742 root 1.206 #if USE_XIM
1743 root 1.198 if (Input_Context != NULL)
1744     {
1745 root 1.307 IMSetPosition ();
1746 root 1.198 XSetICFocus (Input_Context);
1747     }
1748     #endif
1749 root 1.206 #if CURSOR_BLINK
1750 root 1.321 if (option (Opt_cursorBlink))
1751 root 1.274 cursor_blink_ev.start (NOW + CURSOR_BLINK_INTERVAL);
1752 root 1.198 #endif
1753 root 1.206 #if OFF_FOCUS_FADING
1754 root 1.198 if (rs[Rs_fade])
1755     {
1756     pix_colors = pix_colors_focused;
1757     scr_recolour ();
1758     }
1759     #endif
1760 ayin 1.322 #if ENABLE_FRILLS
1761     if (option (Opt_urgentOnBell))
1762     {
1763     XWMHints *h;
1764    
1765     h = XGetWMHints(dpy, parent[0]);
1766     if (h != NULL)
1767     {
1768     h->flags &= ~XUrgencyHint;
1769     XSetWMHints(dpy, parent[0], h);
1770     }
1771     }
1772     #endif
1773 root 1.198 }
1774     }
1775    
1776     void
1777     rxvt_term::focus_out ()
1778     {
1779 root 1.208 if (focus)
1780 root 1.198 {
1781 root 1.208 focus = 0;
1782 root 1.296 want_refresh = 1;
1783 root 1.198
1784 root 1.237 HOOK_INVOKE ((this, HOOK_FOCUS_OUT, DT_END));
1785 root 1.227
1786 root 1.198 #if ENABLE_FRILLS || ISO_14755
1787 root 1.227 if (iso14755buf)
1788     {
1789     iso14755buf = 0;
1790     # if ENABLE_OVERLAY
1791     scr_overlay_off ();
1792     # endif
1793     }
1794 root 1.198 #endif
1795 root 1.206 #if USE_XIM
1796 root 1.198 if (Input_Context != NULL)
1797     XUnsetICFocus (Input_Context);
1798     #endif
1799 root 1.206 #if CURSOR_BLINK
1800 root 1.321 if (option (Opt_cursorBlink))
1801 root 1.198 cursor_blink_ev.stop ();
1802     hidden_cursor = 0;
1803     #endif
1804 root 1.206 #if OFF_FOCUS_FADING
1805 root 1.198 if (rs[Rs_fade])
1806     {
1807     pix_colors = pix_colors_unfocused;
1808     scr_recolour ();
1809     }
1810     #endif
1811     }
1812     }
1813    
1814 root 1.313 void
1815     rxvt_term::update_fade_color (unsigned int idx)
1816     {
1817     #if OFF_FOCUS_FADING
1818     if (rs[Rs_fade])
1819     {
1820     rgba c;
1821     pix_colors [Color_fade].get (c);
1822     pix_colors_focused [idx].fade (this, atoi (rs[Rs_fade]), pix_colors_unfocused [idx], c);
1823     }
1824     #endif
1825     }
1826    
1827 root 1.314 #if TRANSPARENT || ENABLE_PERL
1828 pcg 1.1 void
1829 pcg 1.38 rxvt_term::rootwin_cb (XEvent &ev)
1830     {
1831 root 1.264 make_current ();
1832 pcg 1.38
1833 root 1.314 if (SHOULD_INVOKE (HOOK_ROOT_EVENT)
1834     && HOOK_INVOKE ((this, HOOK_ROOT_EVENT, DT_XEVENT, &ev, DT_END)))
1835     return;
1836    
1837     # if TRANSPARENT
1838 pcg 1.40 switch (ev.type)
1839 pcg 1.38 {
1840 pcg 1.40 case PropertyNotify:
1841 root 1.131 /*
1842     * if user used some Esetroot compatible prog to set the root bg,
1843     * use the property to determine the pixmap. We use it later on.
1844     */
1845 root 1.179 if (ev.xproperty.atom != xa[XA_XROOTPMAP_ID]
1846     && ev.xproperty.atom != xa[XA_ESETROOT_PMAP_ID])
1847 root 1.131 return;
1848 pcg 1.38
1849 pcg 1.40 /* FALLTHROUGH */
1850     case ReparentNotify:
1851 sasha 1.324 if (option (Opt_transparent))
1852     check_our_parents ();
1853 pcg 1.40 break;
1854 pcg 1.38 }
1855 root 1.314 # endif
1856 pcg 1.38 }
1857 root 1.131 #endif
1858 pcg 1.38
1859     void
1860 pcg 1.56 rxvt_term::button_press (XButtonEvent &ev)
1861 pcg 1.1 {
1862 pcg 1.36 int reportmode = 0, clickintime;
1863 pcg 1.1
1864 pcg 1.38 bypass_keystate = ev.state & (ModMetaMask | ShiftMask);
1865 root 1.229
1866 pcg 1.36 if (!bypass_keystate)
1867 root 1.145 reportmode = !! (priv_modes & PrivMode_mouse_report);
1868    
1869 pcg 1.36 /*
1870     * VT window processing of button press
1871     */
1872 root 1.208 if (ev.window == vt)
1873 pcg 1.36 {
1874 root 1.280 if (HOOK_INVOKE ((this, HOOK_BUTTON_PRESS, DT_XEVENT, &ev, DT_END)))
1875     return;
1876    
1877 root 1.145 #if ISO_14755
1878     // 5.4
1879     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
1880     {
1881     iso14755_54 (ev.x, ev.y);
1882     return;
1883     }
1884     #endif
1885    
1886 pcg 1.50 clickintime = ev.time - MEvent.time < MULTICLICK_TIME;
1887 root 1.168
1888 pcg 1.50 if (reportmode)
1889 pcg 1.36 {
1890 pcg 1.50 /* mouse report from vt window */
1891     /* save the xbutton state (for ButtonRelease) */
1892     MEvent.state = ev.state;
1893     #ifdef MOUSE_REPORT_DOUBLECLICK
1894     if (ev.button == MEvent.button && clickintime)
1895 pcg 1.36 {
1896 pcg 1.50 /* same button, within alloted time */
1897     MEvent.clicks++;
1898 root 1.243
1899 pcg 1.50 if (MEvent.clicks > 1)
1900 pcg 1.36 {
1901 pcg 1.50 /* only report double clicks */
1902     MEvent.clicks = 2;
1903 pcg 1.36 mouse_report (ev);
1904 pcg 1.50
1905     /* don't report the release */
1906     MEvent.clicks = 0;
1907     MEvent.button = AnyButton;
1908 pcg 1.36 }
1909 pcg 1.50 }
1910     else
1911     {
1912     /* different button, or time expired */
1913     MEvent.clicks = 1;
1914 pcg 1.38 MEvent.button = ev.button;
1915 pcg 1.36 mouse_report (ev);
1916 pcg 1.50 }
1917     #else
1918     MEvent.button = ev.button;
1919     mouse_report (ev);
1920 pcg 1.1 #endif /* MOUSE_REPORT_DOUBLECLICK */
1921 pcg 1.36
1922 pcg 1.50 }
1923     else
1924     {
1925     if (ev.button != MEvent.button)
1926     MEvent.clicks = 0;
1927 root 1.168
1928 root 1.280 switch (ev.button)
1929     {
1930     case Button1:
1931     /* allow meta + click to select rectangular areas */
1932     /* should be done in screen.C */
1933 root 1.168 #if ENABLE_FRILLS
1934 root 1.280 selection.rect = !!(ev.state & ModMetaMask);
1935 root 1.168 #else
1936 root 1.280 selection.rect = false;
1937 root 1.168 #endif
1938    
1939 root 1.280 /* allow shift+left click to extend selection */
1940     if (ev.state & ShiftMask && !(priv_modes & PrivMode_mouse_report))
1941     {
1942     if (MEvent.button == Button1 && clickintime)
1943     selection_rotate (ev.x, ev.y);
1944     else
1945     selection_extend (ev.x, ev.y, 1);
1946     }
1947     else
1948     {
1949     if (MEvent.button == Button1 && clickintime)
1950     MEvent.clicks++;
1951     else
1952     MEvent.clicks = 1;
1953 pcg 1.21
1954 root 1.280 selection_click (MEvent.clicks, ev.x, ev.y);
1955     }
1956 pcg 1.21
1957 root 1.280 MEvent.button = Button1;
1958     break;
1959 pcg 1.1
1960 root 1.280 case Button3:
1961     if (MEvent.button == Button3 && clickintime)
1962     selection_rotate (ev.x, ev.y);
1963     else
1964     selection_extend (ev.x, ev.y, 1);
1965 root 1.145
1966 root 1.280 MEvent.button = Button3;
1967     break;
1968     }
1969     }
1970 root 1.145
1971 pcg 1.50 MEvent.time = ev.time;
1972     return;
1973 pcg 1.36 }
1974 pcg 1.1
1975 pcg 1.36 /*
1976     * Scrollbar window processing of button press
1977     */
1978 pcg 1.43 if (isScrollbarWindow (ev.window))
1979 pcg 1.36 {
1980     scrollBar.setIdle ();
1981     /*
1982     * Rxvt-style scrollbar:
1983     * move up if mouse is above slider
1984     * move dn if mouse is below slider
1985     *
1986     * XTerm-style scrollbar:
1987     * Move display proportional to pointer location
1988     * pointer near top -> scroll one line
1989     * pointer near bot -> scroll full page
1990     */
1991 pcg 1.1 #ifndef NO_SCROLLBAR_REPORT
1992 pcg 1.36 if (reportmode)
1993     {
1994     /*
1995     * Mouse report disabled scrollbar:
1996     * arrow buttons - send up/down
1997     * click on scrollbar - send pageup/down
1998     */
1999     if ((scrollBar.style == R_SB_NEXT
2000 pcg 1.43 && scrollbarnext_upButton (ev.y))
2001 pcg 1.36 || (scrollBar.style == R_SB_RXVT
2002 pcg 1.43 && scrollbarrxvt_upButton (ev.y)))
2003     tt_printf ("\033[A");
2004 pcg 1.36 else if ((scrollBar.style == R_SB_NEXT
2005 pcg 1.43 && scrollbarnext_dnButton (ev.y))
2006 pcg 1.36 || (scrollBar.style == R_SB_RXVT
2007 pcg 1.43 && scrollbarrxvt_dnButton (ev.y)))
2008     tt_printf ("\033[B");
2009 pcg 1.36 else
2010 pcg 1.38 switch (ev.button)
2011 pcg 1.36 {
2012     case Button2:
2013 pcg 1.43 tt_printf ("\014");
2014 pcg 1.36 break;
2015     case Button1:
2016 pcg 1.43 tt_printf ("\033[6~");
2017 pcg 1.36 break;
2018     case Button3:
2019 pcg 1.43 tt_printf ("\033[5~");
2020 pcg 1.36 break;
2021     }
2022     }
2023     else
2024 pcg 1.1 #endif /* NO_SCROLLBAR_REPORT */
2025    
2026 pcg 1.36 {
2027     char upordown = 0;
2028    
2029     if (scrollBar.style == R_SB_NEXT)
2030     {
2031 pcg 1.43 if (scrollbarnext_upButton (ev.y))
2032 pcg 1.36 upordown = -1; /* up */
2033 pcg 1.43 else if (scrollbarnext_dnButton (ev.y))
2034 pcg 1.36 upordown = 1; /* down */
2035     }
2036     else if (scrollBar.style == R_SB_RXVT)
2037     {
2038 pcg 1.43 if (scrollbarrxvt_upButton (ev.y))
2039 pcg 1.36 upordown = -1; /* up */
2040 pcg 1.43 else if (scrollbarrxvt_dnButton (ev.y))
2041 pcg 1.36 upordown = 1; /* down */
2042     }
2043     if (upordown)
2044     {
2045 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2046 root 1.97 cont_scroll_ev.start (NOW + SCROLLBAR_INITIAL_DELAY);
2047 pcg 1.1 #endif
2048 pcg 1.36 if (scr_page (upordown < 0 ? UP : DN, 1))
2049     {
2050     if (upordown < 0)
2051     scrollBar.setUp ();
2052     else
2053     scrollBar.setDn ();
2054     }
2055     }
2056     else
2057 pcg 1.38 switch (ev.button)
2058 pcg 1.36 {
2059     case Button2:
2060     switch (scrollbar_align)
2061     {
2062     case R_SB_ALIGN_TOP:
2063     csrO = 0;
2064     break;
2065     case R_SB_ALIGN_CENTRE:
2066     csrO = (scrollBar.bot - scrollBar.top) / 2;
2067     break;
2068     case R_SB_ALIGN_BOTTOM:
2069     csrO = scrollBar.bot - scrollBar.top;
2070     break;
2071     }
2072 root 1.120
2073 pcg 1.36 if (scrollBar.style == R_SB_XTERM
2074 pcg 1.43 || scrollbar_above_slider (ev.y)
2075     || scrollbar_below_slider (ev.y))
2076 root 1.120 scr_move_to (scrollbar_position (ev.y) - csrO, scrollbar_size ());
2077    
2078 pcg 1.36 scrollBar.setMotion ();
2079     break;
2080    
2081     case Button1:
2082     if (scrollbar_align == R_SB_ALIGN_CENTRE)
2083 pcg 1.38 csrO = ev.y - scrollBar.top;
2084 pcg 1.36 /* FALLTHROUGH */
2085    
2086     case Button3:
2087     if (scrollBar.style != R_SB_XTERM)
2088     {
2089 pcg 1.43 if (scrollbar_above_slider (ev.y))
2090 pcg 1.1 # ifdef RXVT_SCROLL_FULL
2091 root 1.208 scr_page (UP, nrow - 1);
2092 pcg 1.1 # else
2093 root 1.208 scr_page (UP, nrow / 4);
2094 pcg 1.1 # endif
2095 pcg 1.43 else if (scrollbar_below_slider (ev.y))
2096 pcg 1.1 # ifdef RXVT_SCROLL_FULL
2097 root 1.208 scr_page (DN, nrow - 1);
2098 pcg 1.1 # else
2099 root 1.208 scr_page (DN, nrow / 4);
2100 pcg 1.1 # endif
2101 pcg 1.36 else
2102     scrollBar.setMotion ();
2103     }
2104     else
2105     {
2106 pcg 1.38 scr_page ((ev.button == Button1 ? DN : UP),
2107 root 1.208 (nrow
2108 pcg 1.43 * scrollbar_position (ev.y)
2109     / scrollbar_size ()));
2110 pcg 1.36 }
2111 root 1.120
2112 pcg 1.36 break;
2113     }
2114     }
2115 root 1.243
2116 pcg 1.36 return;
2117 pcg 1.1 }
2118     }
2119    
2120     void
2121 pcg 1.56 rxvt_term::button_release (XButtonEvent &ev)
2122 pcg 1.1 {
2123 pcg 1.38 int reportmode = 0;
2124 pcg 1.1
2125 pcg 1.36 csrO = 0; /* reset csr Offset */
2126     if (!bypass_keystate)
2127 root 1.145 reportmode = !! (priv_modes & PrivMode_mouse_report);
2128 pcg 1.36
2129 pcg 1.43 if (scrollbar_isUpDn ())
2130 pcg 1.36 {
2131     scrollBar.setIdle ();
2132     scrollbar_show (0);
2133 root 1.145 }
2134 pcg 1.36
2135 pcg 1.1 #ifdef SELECTION_SCROLLING
2136 root 1.97 if (sel_scroll_ev.active)
2137     sel_scroll_ev.stop();
2138 pcg 1.1 #endif
2139 root 1.145
2140 root 1.208 if (ev.window == vt)
2141 pcg 1.36 {
2142 root 1.280 if (HOOK_INVOKE ((this, HOOK_BUTTON_RELEASE, DT_XEVENT, &ev, DT_END)))
2143     return;
2144    
2145 root 1.145 #if ISO_14755
2146     // 5.4
2147     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
2148     return;
2149     #endif
2150 root 1.280
2151 pcg 1.50 if (reportmode)
2152 pcg 1.36 {
2153 pcg 1.50 /* mouse report from vt window */
2154     /* don't report release of wheel "buttons" */
2155     if (ev.button >= 4)
2156     return;
2157     #ifdef MOUSE_REPORT_DOUBLECLICK
2158     /* only report the release of 'slow' single clicks */
2159     if (MEvent.button != AnyButton
2160     && (ev.button != MEvent.button
2161     || (ev.time - MEvent.time
2162     > MULTICLICK_TIME / 2)))
2163 pcg 1.36 {
2164 pcg 1.50 MEvent.clicks = 0;
2165 pcg 1.36 MEvent.button = AnyButton;
2166     mouse_report (ev);
2167 pcg 1.50 }
2168     #else /* MOUSE_REPORT_DOUBLECLICK */
2169     MEvent.button = AnyButton;
2170     mouse_report (ev);
2171 pcg 1.1 #endif /* MOUSE_REPORT_DOUBLECLICK */
2172 pcg 1.50 return;
2173     }
2174 root 1.145
2175 pcg 1.50 /*
2176     * dumb hack to compensate for the failure of click-and-drag
2177     * when overriding mouse reporting
2178     */
2179 root 1.145 if (priv_modes & PrivMode_mouse_report
2180 pcg 1.50 && bypass_keystate
2181     && ev.button == Button1 && MEvent.clicks <= 1)
2182     selection_extend (ev.x, ev.y, 0);
2183    
2184     switch (ev.button)
2185     {
2186     case Button1:
2187     case Button3:
2188     selection_make (ev.time);
2189     break;
2190 root 1.272
2191 pcg 1.50 case Button2:
2192 root 1.275 if (IN_RANGE_EXC (ev.x, 0, width) && IN_RANGE_EXC (ev.y, 0, height)) // inside window?
2193 ayin 1.319 selection_request (ev.time, ev.state & ModMetaMask ? Sel_Clipboard : Sel_Primary);
2194 pcg 1.50 break;
2195 root 1.272
2196 pcg 1.50 #ifdef MOUSE_WHEEL
2197     case Button4:
2198     case Button5:
2199 pcg 1.36 {
2200 pcg 1.50 int i;
2201     page_dirn v;
2202 pcg 1.36
2203 root 1.97 v = ev.button == Button4 ? UP : DN;
2204    
2205 pcg 1.50 if (ev.state & ShiftMask)
2206     i = 1;
2207 root 1.321 else if (option (Opt_mouseWheelScrollPage))
2208 root 1.208 i = nrow - 1;
2209 pcg 1.50 else
2210     i = 5;
2211 root 1.97
2212 pcg 1.1 # ifdef MOUSE_SLIP_WHEELING
2213 pcg 1.50 if (ev.state & ControlMask)
2214     {
2215 root 1.97 mouse_slip_wheel_speed += v ? -1 : 1;
2216 root 1.208 if (mouse_slip_wheel_speed < -nrow) mouse_slip_wheel_speed = -nrow;
2217     if (mouse_slip_wheel_speed > +nrow) mouse_slip_wheel_speed = +nrow;
2218 root 1.107
2219     if (slip_wheel_ev.at < NOW)
2220     slip_wheel_ev.at = NOW + SCROLLBAR_CONTINUOUS_DELAY;
2221    
2222     slip_wheel_ev.start ();
2223 pcg 1.50 }
2224 root 1.107 else
2225     {
2226 pcg 1.1 # endif
2227 root 1.107 scr_page (v, i);
2228 pcg 1.36 scrollbar_show (1);
2229 root 1.107 # ifdef MOUSE_SLIP_WHEELING
2230 pcg 1.50 }
2231 root 1.254 # endif
2232 pcg 1.50 }
2233     break;
2234 pcg 1.1 #endif
2235 pcg 1.36 }
2236     }
2237 pcg 1.1 }
2238    
2239 pcg 1.90 #ifdef TRANSPARENT
2240 sasha 1.324 #if TINTING && !defined(HAVE_AFTERIMAGE)
2241 root 1.116 /* taken from aterm-0.4.2 */
2242    
2243     typedef uint32_t RUINT32T;
2244 pcg 1.90
2245 root 1.285 void ShadeXImage(rxvt_term *term, XImage* srcImage, int shade, int rm, int gm, int bm)
2246 pcg 1.90 {
2247 root 1.116 int sh_r, sh_g, sh_b;
2248     RUINT32T mask_r, mask_g, mask_b;
2249     RUINT32T *lookup, *lookup_r, *lookup_g, *lookup_b;
2250     unsigned int lower_lim_r, lower_lim_g, lower_lim_b;
2251     unsigned int upper_lim_r, upper_lim_g, upper_lim_b;
2252     int i;
2253    
2254 root 1.285 Visual *visual = term->visual;
2255 root 1.116
2256     if( visual->c_class != TrueColor || srcImage->format != ZPixmap ) return ;
2257    
2258     /* for convenience */
2259     mask_r = visual->red_mask;
2260     mask_g = visual->green_mask;
2261     mask_b = visual->blue_mask;
2262    
2263     /* boring lookup table pre-initialization */
2264     switch (srcImage->bits_per_pixel) {
2265     case 15:
2266     if ((mask_r != 0x7c00) ||
2267     (mask_g != 0x03e0) ||
2268     (mask_b != 0x001f))
2269     return;
2270     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(32+32+32));
2271     lookup_r = lookup;
2272     lookup_g = lookup+32;
2273     lookup_b = lookup+32+32;
2274     sh_r = 10;
2275     sh_g = 5;
2276     sh_b = 0;
2277     break;
2278     case 16:
2279     if ((mask_r != 0xf800) ||
2280     (mask_g != 0x07e0) ||
2281     (mask_b != 0x001f))
2282     return;
2283     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(32+64+32));
2284     lookup_r = lookup;
2285     lookup_g = lookup+32;
2286     lookup_b = lookup+32+64;
2287     sh_r = 11;
2288     sh_g = 5;
2289     sh_b = 0;
2290     break;
2291     case 24:
2292     if ((mask_r != 0xff0000) ||
2293     (mask_g != 0x00ff00) ||
2294     (mask_b != 0x0000ff))
2295     return;
2296     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(256+256+256));
2297     lookup_r = lookup;
2298     lookup_g = lookup+256;
2299     lookup_b = lookup+256+256;
2300     sh_r = 16;
2301     sh_g = 8;
2302     sh_b = 0;
2303     break;
2304     case 32:
2305     if ((mask_r != 0xff0000) ||
2306     (mask_g != 0x00ff00) ||
2307     (mask_b != 0x0000ff))
2308     return;
2309     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(256+256+256));
2310     lookup_r = lookup;
2311     lookup_g = lookup+256;
2312     lookup_b = lookup+256+256;
2313     sh_r = 16;
2314     sh_g = 8;
2315     sh_b = 0;
2316     break;
2317     default:
2318     return; /* we do not support this color depth */
2319     }
2320    
2321     /* prepare limits for color transformation (each channel is handled separately) */
2322     if (shade < 0) {
2323     shade = -shade;
2324     if (shade < 0) shade = 0;
2325     if (shade > 100) shade = 100;
2326    
2327     lower_lim_r = 65535-rm;
2328     lower_lim_g = 65535-gm;
2329     lower_lim_b = 65535-bm;
2330    
2331     lower_lim_r = 65535-(unsigned int)(((RUINT32T)lower_lim_r)*((RUINT32T)shade)/100);
2332     lower_lim_g = 65535-(unsigned int)(((RUINT32T)lower_lim_g)*((RUINT32T)shade)/100);
2333     lower_lim_b = 65535-(unsigned int)(((RUINT32T)lower_lim_b)*((RUINT32T)shade)/100);
2334    
2335     upper_lim_r = upper_lim_g = upper_lim_b = 65535;
2336     } else {
2337     if (shade < 0) shade = 0;
2338     if (shade > 100) shade = 100;
2339    
2340     lower_lim_r = lower_lim_g = lower_lim_b = 0;
2341    
2342     upper_lim_r = (unsigned int)((((RUINT32T)rm)*((RUINT32T)shade))/100);
2343     upper_lim_g = (unsigned int)((((RUINT32T)gm)*((RUINT32T)shade))/100);
2344     upper_lim_b = (unsigned int)((((RUINT32T)bm)*((RUINT32T)shade))/100);
2345     }
2346 pcg 1.90
2347 root 1.116 /* switch red and blue bytes if necessary, we need it for some weird XServers like XFree86 3.3.3.1 */
2348     if ((srcImage->bits_per_pixel == 24) && (mask_r >= 0xFF0000 ))
2349     {
2350     unsigned int tmp;
2351 pcg 1.90
2352 root 1.116 tmp = lower_lim_r;
2353     lower_lim_r = lower_lim_b;
2354     lower_lim_b = tmp;
2355    
2356     tmp = upper_lim_r;
2357     upper_lim_r = upper_lim_b;
2358     upper_lim_b = tmp;
2359     }
2360 pcg 1.90
2361 root 1.116 /* fill our lookup tables */
2362     for (i = 0; i <= mask_r>>sh_r; i++)
2363     {
2364     RUINT32T tmp;
2365     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_r-lower_lim_r));
2366     tmp += ((RUINT32T)(mask_r>>sh_r))*((RUINT32T)lower_lim_r);
2367     lookup_r[i] = (tmp/65535)<<sh_r;
2368     }
2369     for (i = 0; i <= mask_g>>sh_g; i++)
2370     {
2371     RUINT32T tmp;
2372     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_g-lower_lim_g));
2373     tmp += ((RUINT32T)(mask_g>>sh_g))*((RUINT32T)lower_lim_g);
2374     lookup_g[i] = (tmp/65535)<<sh_g;
2375     }
2376     for (i = 0; i <= mask_b>>sh_b; i++)
2377     {
2378     RUINT32T tmp;
2379     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_b-lower_lim_b));
2380     tmp += ((RUINT32T)(mask_b>>sh_b))*((RUINT32T)lower_lim_b);
2381     lookup_b[i] = (tmp/65535)<<sh_b;
2382     }
2383 pcg 1.90
2384 root 1.116 /* apply table to input image (replacing colors by newly calculated ones) */
2385     switch (srcImage->bits_per_pixel)
2386     {
2387     case 15:
2388     {
2389     unsigned short *p1, *pf, *p, *pl;
2390     p1 = (unsigned short *) srcImage->data;
2391     pf = (unsigned short *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
2392     while (p1 < pf)
2393     {
2394     p = p1;
2395     pl = p1 + srcImage->width;
2396     for (; p < pl; p++)
2397     {
2398     *p = lookup_r[(*p & 0x7c00)>>10] |
2399     lookup_g[(*p & 0x03e0)>> 5] |
2400     lookup_b[(*p & 0x001f)];
2401     }
2402     p1 = (unsigned short *) ((char *) p1 + srcImage->bytes_per_line);
2403     }
2404     break;
2405     }
2406     case 16:
2407     {
2408     unsigned short *p1, *pf, *p, *pl;
2409     p1 = (unsigned short *) srcImage->data;
2410     pf = (unsigned short *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
2411     while (p1 < pf)
2412     {
2413     p = p1;
2414     pl = p1 + srcImage->width;
2415     for (; p < pl; p++)
2416     {
2417     *p = lookup_r[(*p & 0xf800)>>11] |
2418     lookup_g[(*p & 0x07e0)>> 5] |
2419     lookup_b[(*p & 0x001f)];
2420     }
2421     p1 = (unsigned short *) ((char *) p1 + srcImage->bytes_per_line);
2422     }
2423     break;
2424     }
2425     case 24:
2426     {
2427     unsigned char *p1, *pf, *p, *pl;
2428     p1 = (unsigned char *) srcImage->data;
2429     pf = (unsigned char *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
2430     while (p1 < pf)
2431     {
2432     p = p1;
2433     pl = p1 + srcImage->width * 3;
2434     for (; p < pl; p += 3)
2435     {
2436     p[0] = lookup_r[(p[0] & 0xff0000)>>16];
2437     p[1] = lookup_r[(p[1] & 0x00ff00)>> 8];
2438     p[2] = lookup_r[(p[2] & 0x0000ff)];
2439     }
2440     p1 = (unsigned char *) ((char *) p1 + srcImage->bytes_per_line);
2441     }
2442     break;
2443     }
2444     case 32:
2445     {
2446     RUINT32T *p1, *pf, *p, *pl;
2447     p1 = (RUINT32T *) srcImage->data;
2448     pf = (RUINT32T *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
2449    
2450     while (p1 < pf)
2451     {
2452     p = p1;
2453     pl = p1 + srcImage->width;
2454     for (; p < pl; p++)
2455     {
2456     *p = lookup_r[(*p & 0xff0000)>>16] |
2457     lookup_g[(*p & 0x00ff00)>> 8] |
2458     lookup_b[(*p & 0x0000ff)] |
2459     (*p & ~0xffffff);
2460     }
2461     p1 = (RUINT32T *) ((char *) p1 + srcImage->bytes_per_line);
2462     }
2463     break;
2464 pcg 1.90 }
2465 root 1.116 }
2466    
2467     free (lookup);
2468 pcg 1.90 }
2469     #endif
2470 pcg 1.1
2471     /*
2472     * Check our parents are still who we think they are.
2473     * Do transparency updates if required
2474     */
2475     int
2476 pcg 1.34 rxvt_term::check_our_parents ()
2477 pcg 1.1 {
2478 sasha 1.324 #if TRANSPARENT || ENABLE_PERL
2479     check_our_aprents_ev.stop();
2480     check_our_aprents_ev.start(NOW + 1./3.);
2481     #endif
2482     return 0;
2483     }
2484    
2485     void
2486     rxvt_term::check_our_parents_cb (time_watcher &w)
2487     {
2488 pcg 1.90 int i, pchanged, aformat, have_pixmap, rootdepth;
2489     unsigned long nitems, bytes_after;
2490     Atom atype;
2491     unsigned char *prop = NULL;
2492     Window root, oldp, *list;
2493     Pixmap rootpixmap = None;
2494 pcg 1.36 XWindowAttributes wattr, wrootattr;
2495 sasha 1.324 int sx, sy;
2496     Window cr;
2497 pcg 1.36
2498     pchanged = 0;
2499    
2500 root 1.321 if (!option (Opt_transparent))
2501 sasha 1.324 return /*pchanged*/; /* Don't try any more */
2502 pcg 1.36
2503 root 1.305 XGetWindowAttributes (dpy, display->root, &wrootattr);
2504 pcg 1.36 rootdepth = wrootattr.depth;
2505    
2506 root 1.305 XGetWindowAttributes (dpy, parent[0], &wattr);
2507 pcg 1.90
2508 pcg 1.36 if (rootdepth != wattr.depth)
2509     {
2510     if (am_transparent)
2511     {
2512     pchanged = 1;
2513 root 1.305 XSetWindowBackground (dpy, vt, pix_colors_focused[Color_bg]);
2514 pcg 1.36 am_transparent = am_pixmap_trans = 0;
2515     }
2516 pcg 1.90
2517 sasha 1.324 return /*pchanged*/; /* Don't try any more */
2518 pcg 1.1 }
2519    
2520 pcg 1.36 /* Get all X ops out of the queue so that our information is up-to-date. */
2521 root 1.305 XSync (dpy, False);
2522 pcg 1.1
2523 sasha 1.324 XTranslateCoordinates (dpy, parent[0], display->root,
2524     0, 0, &sx, &sy, &cr);
2525    
2526     /* check if we are outside of the visible part of the virtual screen : */
2527     if( sx + (int)szHint.width <= 0 || sy + (int)szHint.height <= 0
2528     || sx >= wrootattr.width || sy >= wrootattr.height )
2529     return /* 0 */ ;
2530 pcg 1.36 /*
2531     * Make the frame window set by the window manager have
2532     * the root background. Some window managers put multiple nested frame
2533     * windows for each client, so we have to take care about that.
2534     */
2535 root 1.178 i = (xa[XA_XROOTPMAP_ID]
2536 root 1.305 && XGetWindowProperty (dpy, display->root, xa[XA_XROOTPMAP_ID],
2537 pcg 1.36 0L, 1L, False, XA_PIXMAP, &atype, &aformat,
2538 pcg 1.90 &nitems, &bytes_after, &prop) == Success);
2539    
2540     if (!i || prop == NULL)
2541 root 1.178 i = (xa[XA_ESETROOT_PMAP_ID]
2542 root 1.305 && XGetWindowProperty (dpy, display->root, xa[XA_ESETROOT_PMAP_ID],
2543 pcg 1.90 0L, 1L, False, XA_PIXMAP, &atype, &aformat,
2544     &nitems, &bytes_after, &prop) == Success);
2545    
2546 root 1.116 if (!i || prop == NULL
2547     #if TINTING
2548 sasha 1.324 || (!ISSET_PIXCOLOR (Color_tint) && rs[Rs_shade] == NULL
2549     #ifdef HAVE_AFTERIMAGE
2550     && original_asim == NULL && rs[Rs_blurradius] == NULL
2551     #endif
2552     )
2553 root 1.116 #endif
2554     )
2555 pcg 1.36 have_pixmap = 0;
2556     else
2557     {
2558     have_pixmap = 1;
2559 pcg 1.93 rootpixmap = *(Pixmap *)prop;
2560 pcg 1.43 XFree (prop);
2561 pcg 1.1 }
2562 pcg 1.90
2563 pcg 1.36 if (have_pixmap)
2564     {
2565 sasha 1.324 Bool success = False ;
2566     GC gc;
2567     XGCValues gcvalue;
2568     #ifdef HAVE_AFTERIMAGE
2569     {
2570     Pixmap tmp_pmap = None ;
2571     ShadingInfo shade;
2572     ARGB32 tint ;
2573     unsigned int pmap_w = 0, pmap_h = 0;
2574    
2575     if (get_drawable_size( rootpixmap, &pmap_w, &pmap_h ))
2576     {
2577     int root_x = 0, root_y = 0;
2578    
2579     shade.shading = rs[Rs_shade] ? atoi (rs[Rs_shade]) : 100;
2580     if (ISSET_PIXCOLOR (Color_tint))
2581     {
2582     rgba c;
2583     pix_colors_focused [Color_tint].get (c);
2584     shade.tintColor.red = c.r;
2585     shade.tintColor.green = c.g;
2586     shade.tintColor.blue = c.b;
2587     }
2588     else
2589     shade.tintColor.red = shade.tintColor.green = shade.tintColor.blue = 0xFFFF;
2590     tint = shading2tint32( &shade );
2591     gc = XCreateGC (dpy, vt, 0UL, &gcvalue);
2592     if (GetWinPosition (parent[0], &root_x, &root_y) )
2593     {
2594     ASImageLayer *layers = create_image_layers( 2 );
2595     ASImage *merged_im = NULL;
2596     int back_x, back_y, back_w, back_h;
2597     /* merge_layers does good job at tiling background appropriately,
2598     so all we need is to cut out smallest possible piece : */
2599     #define MAKE_ROOTPMAP_GEOM(xy,wh,widthheight) \
2600     do{ while( root_##xy < 0 ) root_##xy += (int)wrootattr.widthheight; \
2601     back_##xy = root_##xy % pmap_##wh; /* that gives us left side of the closest tile : */ \
2602     if( pmap_##wh >= back_##xy + szHint.widthheight ) \
2603     back_##wh = szHint.widthheight;/* background is large - limit it by our size */ \
2604     else \
2605     { /* small background - need the whole of it for successfull tiling :*/ \
2606     back_##xy = 0; \
2607     back_##wh = pmap_##wh; \
2608     }}while(0)
2609    
2610     MAKE_ROOTPMAP_GEOM(x,w,width);
2611     MAKE_ROOTPMAP_GEOM(y,h,height);
2612    
2613     layers[0].im = pixmap2asimage (display->asv, rootpixmap, back_x, back_y, back_w, back_h, AllPlanes, ASA_ASImage, 100);
2614     layers[0].clip_x = (back_w == pmap_w)?root_x:0;
2615     layers[0].clip_y = (back_h == pmap_h)?root_y:0;
2616     layers[0].clip_width = szHint.width;
2617     layers[0].clip_height = szHint.height;
2618     layers[0].tint = tint;
2619     if (rs[Rs_blurradius] && layers[0].im)
2620     {
2621     double r = atof(rs[Rs_blurradius]);
2622     ASImage* tmp = blur_asimage_gauss(display->asv, layers[0].im, r, r, 0xFFFFFFFF, ASA_ASImage, 100, ASIMAGE_QUALITY_DEFAULT );
2623     if( tmp )
2624     {
2625     destroy_asimage( &layers[0].im );
2626     layers[0].im = tmp;
2627     }
2628     }
2629     if (original_asim != NULL)
2630     {
2631     int fore_w, fore_h;
2632     layers[1].im = original_asim;
2633     if( bgPixmap.auto_resize )
2634     {
2635     fore_w = szHint.width;
2636     fore_h = szHint.height;
2637     }
2638     else
2639     {
2640     fore_w = bgPixmap.w;
2641     fore_h = bgPixmap.h;
2642     }
2643     if (fore_w != original_asim->width
2644     || fore_h != original_asim->height)
2645     {
2646     layers[1].im = scale_asimage( display->asv,
2647     original_asim,
2648     fore_w, fore_h,
2649     ASA_ASImage, 100,
2650     ASIMAGE_QUALITY_DEFAULT );
2651     }
2652    
2653     layers[1].clip_width = szHint.width;
2654     layers[1].clip_height = szHint.height;
2655    
2656     if (rs[Rs_blendtype])
2657     {
2658     layers[1].merge_scanlines = blend_scanlines_name2func(rs[Rs_blendtype]);
2659     if( layers[1].merge_scanlines == NULL )
2660     layers[1].merge_scanlines = alphablend_scanlines;
2661     }
2662     }
2663     merged_im = merge_layers( display->asv, layers, layers[1].im?2:1,
2664     szHint.width, szHint.height,
2665     ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT );
2666     if (layers[1].im != original_asim)
2667     destroy_asimage( &(layers[1].im) );
2668     destroy_asimage( &(layers[0].im) );
2669     if (merged_im != NULL)
2670     {
2671     tmp_pmap = asimage2pixmap( display->asv, DefaultRootWindow(dpy), merged_im, gc, True );
2672     destroy_asimage( &merged_im );
2673     }
2674     free( layers );
2675     }
2676     }
2677     if (tmp_pmap != None)
2678     {
2679     success = True;
2680     if (pixmap != None)
2681     XFreePixmap (dpy, pixmap);
2682     pixmap = tmp_pmap;
2683     }
2684     }
2685     #else /* HAVE_AFTERIMAGE */
2686     {
2687 pcg 1.36 /*
2688 pcg 1.38 * Copy display->root pixmap transparency
2689 pcg 1.36 */
2690 sasha 1.324 int nx, ny;
2691     unsigned int nw, nh;
2692     XImage *image;
2693    
2694     nw = (unsigned int)szHint.width;
2695     nh = (unsigned int)szHint.height;
2696     nx = ny = 0;
2697    
2698     if (sx < 0)
2699     {
2700     nw += sx;
2701     nx = -sx;
2702     sx = 0;
2703     }
2704 pcg 1.36
2705 sasha 1.324 if (sy < 0)
2706     {
2707     nh += sy;
2708     ny = -sy;
2709     sy = 0;
2710     }
2711 pcg 1.67
2712 sasha 1.324 min_it (nw, (unsigned int) (wrootattr.width - sx));
2713     min_it (nh, (unsigned int) (wrootattr.height - sy));
2714 pcg 1.67
2715 sasha 1.324 XSync (dpy, False);
2716     allowedxerror = -1;
2717     image = XGetImage (dpy, rootpixmap, sx, sy, nw, nh, AllPlanes, ZPixmap);
2718    
2719     /* XXX: handle BadMatch - usually because we're outside the pixmap */
2720     /* XXX: may need a delay here? */
2721     allowedxerror = 0;
2722     if (image != NULL)
2723     {
2724     if (pixmap != None)
2725     XFreePixmap (dpy, pixmap);
2726 pcg 1.67
2727 sasha 1.324 #if TINTING
2728     if (ISSET_PIXCOLOR (Color_tint))
2729     {
2730     int shade = rs[Rs_shade] ? atoi (rs[Rs_shade]) : 100;
2731 root 1.175
2732 sasha 1.324 rgba c;
2733     pix_colors_focused [Color_tint].get (c);
2734     ShadeXImage (this, image, shade, c.r, c.g, c.b);
2735     }
2736     #endif
2737 pcg 1.90
2738 sasha 1.324 pixmap = XCreatePixmap (dpy, vt, szHint.width, szHint.height, image->depth);
2739     gc = XCreateGC (dpy, vt, 0UL, &gcvalue);
2740     XPutImage (dpy, pixmap, gc, image, 0, 0,
2741     nx, ny, image->width, image->height);
2742     XDestroyImage (image);
2743     success = True ;
2744     }
2745     }
2746     #endif /* HAVE_AFTERIMAGE */
2747     if (gc != NULL)
2748     XFreeGC (dpy, gc);
2749 pcg 1.90
2750 sasha 1.324 if (!success)
2751 pcg 1.36 {
2752     if (am_transparent && am_pixmap_trans)
2753     {
2754     pchanged = 1;
2755 root 1.208 if (pixmap != None)
2756 pcg 1.36 {
2757 root 1.305 XFreePixmap (dpy, pixmap);
2758 root 1.208 pixmap = None;
2759 pcg 1.36 }
2760     }
2761 pcg 1.90
2762 pcg 1.36 am_pixmap_trans = 0;
2763     }
2764     else
2765     {
2766 root 1.305 XSetWindowBackgroundPixmap (dpy, parent[0], pixmap);
2767     XClearWindow (dpy, parent[0]);
2768 pcg 1.90
2769 pcg 1.36 if (!am_transparent || !am_pixmap_trans)
2770     pchanged = 1;
2771 pcg 1.90
2772 pcg 1.36 am_transparent = am_pixmap_trans = 1;
2773     }
2774 pcg 1.1 }
2775 pcg 1.67
2776 root 1.175 if (am_pixmap_trans)
2777 root 1.305 XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
2778 root 1.175 else
2779 pcg 1.36 {
2780 pcg 1.90 unsigned int n;
2781 pcg 1.36 /*
2782     * InheritPixmap transparency
2783     */
2784 root 1.208 for (i = 1; i < (int) (sizeof (parent) / sizeof (Window)); i++)
2785 pcg 1.36 {
2786 root 1.208 oldp = parent[i];
2787 root 1.305 XQueryTree (dpy, parent[i - 1], &root, &parent[i], &list, &n);
2788 pcg 1.43 XFree (list);
2789 pcg 1.90
2790 root 1.208 if (parent[i] == display->root)
2791 pcg 1.36 {
2792     if (oldp != None)
2793     pchanged = 1;
2794 pcg 1.90
2795 pcg 1.36 break;
2796     }
2797 pcg 1.90
2798 root 1.208 if (oldp != parent[i])
2799 pcg 1.36 pchanged = 1;
2800     }
2801 pcg 1.67
2802 pcg 1.36 n = 0;
2803 pcg 1.67
2804 pcg 1.36 if (pchanged)
2805 root 1.298 for (; n < (unsigned int)i; n++)
2806     {
2807 root 1.305 XGetWindowAttributes (dpy, parent[n], &wattr);
2808 root 1.298
2809     if (wattr.depth != rootdepth || wattr.c_class == InputOnly)
2810     {
2811     n = (int) (sizeof (parent) / sizeof (Window)) + 1;
2812     break;
2813     }
2814     }
2815 pcg 1.67
2816 root 1.298 if (n > (sizeof (parent) / sizeof (parent[0])))
2817 pcg 1.36 {
2818 root 1.305 XSetWindowBackground (dpy, parent[0], pix_colors_focused[Color_border]);
2819     XSetWindowBackground (dpy, vt, pix_colors_focused[Color_bg]);
2820 pcg 1.36 am_transparent = 0;
2821     /* XXX: also turn off Opt_transparent? */
2822     }
2823     else
2824     {
2825     for (n = 0; n < (unsigned int)i; n++)
2826 root 1.116 {
2827 root 1.305 XSetWindowBackgroundPixmap (dpy, parent[n], ParentRelative);
2828     XClearWindow (dpy, parent[n]);
2829 root 1.116 }
2830 pcg 1.90
2831 root 1.305 XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
2832 pcg 1.36 am_transparent = 1;
2833     }
2834 pcg 1.67
2835 root 1.208 for (; i < (int) (sizeof (parent) / sizeof (Window)); i++)
2836     parent[i] = None;
2837 pcg 1.1 }
2838 pcg 1.90
2839 root 1.116 if (scrollBar.win)
2840     {
2841 root 1.305 XSetWindowBackgroundPixmap (dpy, scrollBar.win, ParentRelative);
2842 root 1.116 scrollBar.setIdle ();
2843     scrollbar_show (0);
2844     }
2845    
2846 root 1.175 if (am_transparent)
2847     {
2848     want_refresh = want_full_refresh = 1;
2849     if (am_pixmap_trans)
2850     flush ();
2851     }
2852    
2853 sasha 1.324 // return pchanged;
2854 pcg 1.1 }
2855     #endif
2856    
2857     /*}}} */
2858    
2859 pcg 1.81 bool
2860     rxvt_term::cmd_parse ()
2861     {
2862     bool flag = false;
2863 root 1.245 wchar_t ch = NOCHAR;
2864 root 1.234 char *seq_begin; // remember start of esc-sequence here
2865 pcg 1.81
2866     for (;;)
2867     {
2868     if (ch == NOCHAR)
2869     {
2870     seq_begin = cmdbuf_ptr;
2871     ch = next_char ();
2872 root 1.238
2873     if (ch == NOCHAR)
2874     break;
2875 pcg 1.81 }
2876    
2877 pcg 1.93 if (!IS_CONTROL (ch) || ch == C0_LF || ch == C0_CR || ch == C0_HT)
2878 pcg 1.81 {
2879 root 1.145 if (!seen_input)
2880     {
2881     seen_input = 1;
2882     // many badly-written programs (e.g. jed) contain a race condition:
2883     // they first read the screensize and then install a SIGWINCH handler.
2884     // some window managers resize the window early, and these programs
2885     // then sometimes get the size wrong.
2886 root 1.163 // unfortunately other programs are even more buggy and dislike
2887     // being sent SIGWINCH, so only do it when we were in fact being
2888     // resized.
2889 root 1.197 if (seen_resize && cmd_pid)
2890 root 1.163 kill (-cmd_pid, SIGWINCH);
2891 root 1.145 }
2892    
2893 pcg 1.81 /* Read a text string from the input buffer */
2894 root 1.245 wchar_t buf[UBUFSIZ];
2895 pcg 1.81 bool refreshnow = false;
2896     int nlines = 0;
2897 root 1.245 wchar_t *str = buf;
2898     wchar_t *eol = str + min (ncol, UBUFSIZ);
2899 pcg 1.81
2900     for (;;)
2901     {
2902 pcg 1.93 if (ch == NOCHAR || (IS_CONTROL (ch) && ch != C0_LF && ch != C0_CR && ch != C0_HT))
2903 pcg 1.81 break;
2904    
2905     *str++ = ch;
2906    
2907 root 1.204 if (ch == C0_LF || str >= eol)
2908 pcg 1.81 {
2909 root 1.205 if (ch == C0_LF)
2910     nlines++;
2911    
2912 pcg 1.81 refresh_count++;
2913    
2914 root 1.321 if (!option (Opt_jumpScroll)
2915 root 1.208 || (refresh_count >= refresh_limit * (nrow - 1)))
2916 pcg 1.81 {
2917     refreshnow = true;
2918 root 1.226 refresh_count = 0;
2919 pcg 1.81 ch = NOCHAR;
2920     break;
2921     }
2922    
2923 root 1.208 // scr_add_lines only works for nlines <= nrow - 1.
2924     if (nlines >= nrow - 1)
2925 pcg 1.81 {
2926 root 1.266 if (!(SHOULD_INVOKE (HOOK_ADD_LINES)
2927     && HOOK_INVOKE ((this, HOOK_ADD_LINES, DT_WCS_LEN, buf, str - buf, DT_END))))
2928 root 1.245 scr_add_lines (buf, str - buf, nlines);
2929 root 1.236
2930 pcg 1.81 nlines = 0;
2931     str = buf;
2932 root 1.208 eol = str + min (ncol, UBUFSIZ);
2933 root 1.204 }
2934    
2935     if (str >= eol)
2936     {
2937     if (eol >= buf + UBUFSIZ)
2938     {
2939     ch = NOCHAR;
2940     break;
2941     }
2942     else
2943 root 1.208 eol = min (eol + ncol, buf + UBUFSIZ);
2944 pcg 1.81 }
2945    
2946     }
2947 root 1.120
2948     seq_begin = cmdbuf_ptr;
2949     ch = next_char ();
2950 pcg 1.81 }
2951    
2952 root 1.266 if (!(SHOULD_INVOKE (HOOK_ADD_LINES)
2953     && HOOK_INVOKE ((this, HOOK_ADD_LINES, DT_WCS_LEN, buf, str - buf, DT_END))))
2954 root 1.245 scr_add_lines (buf, str - buf, nlines);
2955 pcg 1.81
2956     /*
2957     * If there have been a lot of new lines, then update the screen
2958     * What the heck I'll cheat and only refresh less than every page-full.
2959     * the number of pages between refreshes is refresh_limit, which
2960     * is incremented here because we must be doing flat-out scrolling.
2961     */
2962     if (refreshnow)
2963     {
2964 root 1.321 if (option (Opt_jumpScroll) && refresh_limit < REFRESH_PERIOD)
2965 pcg 1.81 refresh_limit++;
2966 pcg 1.93 else
2967 root 1.116 {
2968     flag = true;
2969 root 1.310 //TODO: due to popular request, implement "skipscroll" option here
2970 root 1.268 scr_refresh ();
2971 root 1.254 want_refresh = 1;
2972 root 1.116 }
2973 pcg 1.81 }
2974    
2975     }
2976     else
2977     {
2978     try
2979     {
2980     process_nonprinting (ch);
2981     }
2982     catch (const class out_of_input &o)
2983     {
2984     // we ran out of input, retry later
2985     cmdbuf_ptr = seq_begin;
2986     break;
2987     }
2988    
2989     ch = NOCHAR;
2990     }
2991     }
2992    
2993     return flag;
2994     }
2995    
2996     // read the next character
2997 root 1.245 wchar_t
2998 root 1.274 rxvt_term::next_char () NOTHROW
2999 pcg 1.81 {
3000     while (cmdbuf_ptr < cmdbuf_endp)
3001     {
3002     // assume 7-bit to be ascii ALWAYS
3003 root 1.234 if ((unsigned char)*cmdbuf_ptr <= 0x7f && *cmdbuf_ptr != 0x1b)
3004 pcg 1.81 return *cmdbuf_ptr++;
3005    
3006     wchar_t wc;
3007 root 1.234 size_t len = mbrtowc (&wc, cmdbuf_ptr, cmdbuf_endp - cmdbuf_ptr, mbstate);
3008 pcg 1.81
3009     if (len == (size_t)-2)
3010     {
3011     // the mbstate stores incomplete sequences. didn't know this :/
3012     cmdbuf_ptr = cmdbuf_endp;
3013     break;
3014     }
3015    
3016     if (len == (size_t)-1)
3017 root 1.245 return (unsigned char)*cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
3018 pcg 1.81
3019     // assume wchar == unicode
3020     cmdbuf_ptr += len;
3021 root 1.183 return wc & UNICODE_MASK;
3022 pcg 1.81 }
3023    
3024     return NOCHAR;
3025     }
3026    
3027 root 1.245 // read the next octet
3028     uint32_t
3029 root 1.274 rxvt_term::next_octet () NOTHROW
3030 root 1.245 {
3031     return cmdbuf_ptr < cmdbuf_endp
3032 root 1.246 ? (unsigned char)*cmdbuf_ptr++
3033 root 1.245 : NOCHAR;
3034     }
3035    
3036 root 1.274 static class out_of_input out_of_input;
3037    
3038 pcg 1.81 /* rxvt_cmd_getc () - Return next input character */
3039     /*
3040     * Return the next input character after first passing any keyboard input
3041     * to the command.
3042     */
3043 root 1.245 wchar_t
3044 root 1.274 rxvt_term::cmd_getc () THROW ((class out_of_input))
3045 pcg 1.81 {
3046 root 1.245 wchar_t c = next_char ();
3047 pcg 1.81
3048     if (c == NOCHAR)
3049     throw out_of_input;
3050    
3051     return c;
3052     }
3053    
3054 root 1.245 uint32_t
3055 root 1.274 rxvt_term::cmd_get8 () THROW ((class out_of_input))
3056 root 1.97 {
3057 root 1.245 uint32_t c = next_octet ();
3058 root 1.97
3059     if (c == NOCHAR)
3060     throw out_of_input;
3061    
3062     return c;
3063     }
3064    
3065 pcg 1.1 /*{{{ print pipe */
3066     /*----------------------------------------------------------------------*/
3067     #ifdef PRINTPIPE
3068 pcg 1.34 FILE *
3069     rxvt_term::popen_printer ()
3070 pcg 1.1 {
3071 pcg 1.67 FILE *stream = popen (rs[Rs_print_pipe], "w");
3072 pcg 1.1
3073 pcg 1.36 if (stream == NULL)
3074 pcg 1.81 rxvt_warn ("can't open printer pipe, not printing.\n");
3075    
3076 pcg 1.36 return stream;
3077 pcg 1.1 }
3078    
3079     int
3080 pcg 1.34 rxvt_term::pclose_printer (FILE *stream)
3081 pcg 1.1 {
3082 pcg 1.11 fflush (stream);
3083     return pclose (stream);
3084 pcg 1.1 }
3085    
3086     /*
3087     * simulate attached vt100 printer
3088     */
3089     void
3090 pcg 1.34 rxvt_term::process_print_pipe ()
3091 pcg 1.1 {
3092 pcg 1.81 int done;
3093     FILE *fd;
3094 pcg 1.36
3095     if ((fd = popen_printer ()) == NULL)
3096     return;
3097    
3098     /*
3099     * Send all input to the printer until either ESC[4i or ESC[?4i
3100     * is received.
3101     */
3102     for (done = 0; !done;)
3103     {
3104 pcg 1.81 unsigned char buf[8];
3105     unicode_t ch;
3106     unsigned int i, len;
3107 pcg 1.1
3108 pcg 1.36 if ((ch = cmd_getc ()) != C0_ESC)
3109     {
3110 pcg 1.43 if (putc (ch, fd) == EOF)
3111 pcg 1.36 break; /* done = 1 */
3112     }
3113     else
3114     {
3115     len = 0;
3116     buf[len++] = ch;
3117 pcg 1.1
3118 pcg 1.36 if ((buf[len++] = cmd_getc ()) == '[')
3119     {
3120     if ((ch = cmd_getc ()) == '?')
3121     {
3122     buf[len++] = '?';
3123     ch = cmd_getc ();
3124     }
3125     if ((buf[len++] = ch) == '4')
3126     {
3127     if ((buf[len++] = cmd_getc ()) == 'i')
3128     break; /* done = 1 */
3129     }
3130     }
3131 pcg 1.81
3132 pcg 1.36 for (i = 0; i < len; i++)
3133 pcg 1.43 if (putc (buf[i], fd) == EOF)
3134 pcg 1.36 {
3135     done = 1;
3136     break;
3137     }
3138     }
3139 pcg 1.1 }
3140 pcg 1.81
3141 pcg 1.36 pclose_printer (fd);
3142 pcg 1.1 }
3143     #endif /* PRINTPIPE */
3144     /*}}} */
3145    
3146     /* *INDENT-OFF* */
3147     enum {
3148 pcg 1.36 C1_40 = 0x40,
3149 pcg 1.90 C1_41 , C1_BPH, C1_NBH, C1_44 , C1_NEL, C1_SSA, C1_ESA,
3150 pcg 1.36 C1_HTS, C1_HTJ, C1_VTS, C1_PLD, C1_PLU, C1_RI , C1_SS2, C1_SS3,
3151     C1_DCS, C1_PU1, C1_PU2, C1_STS, C1_CCH, C1_MW , C1_SPA, C1_EPA,
3152 pcg 1.90 C1_SOS, C1_59 , C1_SCI, C1_CSI, CS_ST , C1_OSC, C1_PM , C1_APC,
3153 pcg 1.1 };
3154     /* *INDENT-ON* */
3155    
3156     /*{{{ process non-printing single characters */
3157     void
3158 pcg 1.81 rxvt_term::process_nonprinting (unicode_t ch)
3159 pcg 1.1 {
3160 pcg 1.36 switch (ch)
3161     {
3162 pcg 1.81 case C0_ESC:
3163     process_escape_seq ();
3164     break;
3165 pcg 1.36 case C0_ENQ: /* terminal Status */
3166     if (rs[Rs_answerbackstring])
3167 root 1.234 tt_write (rs [Rs_answerbackstring], strlen (rs [Rs_answerbackstring]));
3168 pcg 1.36 else
3169 root 1.234 tt_write (VT100_ANS, strlen (VT100_ANS));
3170 pcg 1.36 break;
3171     case C0_BEL: /* bell */
3172     scr_bell ();
3173     break;
3174     case C0_BS: /* backspace */
3175     scr_backspace ();
3176     break;
3177     case C0_HT: /* tab */
3178     scr_tab (1);
3179     break;
3180     case C0_CR: /* carriage return */
3181     scr_gotorc (0, 0, R_RELATIVE);
3182     break;
3183     case C0_VT: /* vertical tab, form feed */
3184     case C0_FF:
3185     case C0_LF: /* line feed */
3186     scr_index (UP);
3187     break;
3188     case C0_SO: /* shift out - acs */
3189     scr_charset_choose (1);
3190     break;
3191     case C0_SI: /* shift in - acs */
3192     scr_charset_choose (0);
3193     break;
3194 pcg 1.81
3195 root 1.97 #ifdef EIGHT_BIT_CONTROLS
3196 pcg 1.81 // 8-bit controls
3197     case 0x90: /* DCS */
3198     process_dcs_seq ();
3199     break;
3200     case 0x9b: /* CSI */
3201     process_csi_seq ();
3202     break;
3203     case 0x9d: /* CSI */
3204     process_osc_seq ();
3205     break;
3206 root 1.97 #endif
3207 pcg 1.1 }
3208     }
3209     /*}}} */
3210    
3211    
3212     /*{{{ process VT52 escape sequences */
3213     void
3214 pcg 1.81 rxvt_term::process_escape_vt52 (unicode_t ch)
3215 pcg 1.1 {
3216 pcg 1.36 int row, col;
3217    
3218     switch (ch)
3219     {
3220     case 'A': /* cursor up */
3221     scr_gotorc (-1, 0, R_RELATIVE | C_RELATIVE);
3222     break;
3223     case 'B': /* cursor down */
3224     scr_gotorc (1, 0, R_RELATIVE | C_RELATIVE);
3225     break;
3226     case 'C': /* cursor right */
3227     scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
3228     break;
3229     case 'D': /* cursor left */
3230     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
3231     break;
3232     case 'H': /* cursor home */
3233     scr_gotorc (0, 0, 0);
3234     break;
3235     case 'I': /* cursor up and scroll down if needed */
3236     scr_index (DN);
3237     break;
3238     case 'J': /* erase to end of screen */
3239     scr_erase_screen (0);
3240     break;
3241     case 'K': /* erase to end of line */
3242     scr_erase_line (0);
3243     break;
3244     case 'Y': /* move to specified row and col */
3245     /* full command is 'ESC Y row col' where row and col
3246     * are encoded by adding 32 and sending the ascii
3247     * character. eg. SPACE = 0, '+' = 13, '0' = 18,
3248     * etc. */
3249     row = cmd_getc () - ' ';
3250     col = cmd_getc () - ' ';
3251     scr_gotorc (row, col, 0);
3252     break;
3253     case 'Z': /* identify the terminal type */
3254 pcg 1.43 tt_printf ("\033/Z"); /* I am a VT100 emulating a VT52 */
3255 pcg 1.1 break;
3256 pcg 1.36 case '<': /* turn off VT52 mode */
3257 pcg 1.43 PrivMode (0, PrivMode_vt52);
3258 pcg 1.36 break;
3259     case 'F': /* use special graphics character set */
3260     case 'G': /* use regular character set */
3261     /* unimplemented */
3262     break;
3263     case '=': /* use alternate keypad mode */
3264     case '>': /* use regular keypad mode */
3265     /* unimplemented */
3266     break;
3267 pcg 1.1 }
3268     }
3269     /*}}} */
3270    
3271    
3272     /*{{{ process escape sequences */
3273     void
3274 pcg 1.34 rxvt_term::process_escape_seq ()
3275 pcg 1.1 {
3276 pcg 1.81 unicode_t ch = cmd_getc ();
3277 pcg 1.36
3278 root 1.145 if (priv_modes & PrivMode_vt52)
3279 pcg 1.36 {
3280     process_escape_vt52 (ch);
3281     return;
3282     }
3283 pcg 1.1
3284 pcg 1.36 switch (ch)
3285     {
3286     /* case 1: do_tek_mode (); break; */
3287     case '#':
3288     if (cmd_getc () == '8')
3289     scr_E ();
3290     break;
3291 pcg 1.44 case '(':
3292 pcg 1.36 scr_charset_set (0, (unsigned int)cmd_getc ());
3293     break;
3294     case ')':
3295     scr_charset_set (1, (unsigned int)cmd_getc ());
3296     break;
3297     case '*':
3298     scr_charset_set (2, (unsigned int)cmd_getc ());
3299     break;
3300     case '+':
3301     scr_charset_set (3, (unsigned int)cmd_getc ());
3302     break;
3303 root 1.294 #if !ENABLE_MINIMAL
3304 pcg 1.36 case '6':
3305     scr_backindex ();
3306     break;
3307     #endif
3308     case '7':
3309     scr_cursor (SAVE);
3310     break;
3311     case '8':
3312     scr_cursor (RESTORE);
3313     break;
3314 root 1.294 #if !ENABLE_MINIMAL
3315 pcg 1.36 case '9':
3316     scr_forwardindex ();
3317     break;
3318     #endif
3319     case '=':
3320     case '>':
3321 pcg 1.43 PrivMode ((ch == '='), PrivMode_aplKP);
3322 pcg 1.36 break;
3323    
3324     case C1_40:
3325     cmd_getc ();
3326     break;
3327     case C1_44:
3328     scr_index (UP);
3329     break;
3330 pcg 1.1
3331 pcg 1.36 /* 8.3.87: NEXT LINE */
3332     case C1_NEL: /* ESC E */
3333 pcg 1.1 {
3334 root 1.245 wchar_t nlcr[] = { C0_LF, C0_CR };
3335     scr_add_lines (nlcr, sizeof (nlcr) / sizeof (nlcr [0]), 1);
3336 pcg 1.1 }
3337 pcg 1.36 break;
3338    
3339     /* kidnapped escape sequence: Should be 8.3.48 */
3340     case C1_ESA: /* ESC G */
3341     process_graphics ();
3342     break;
3343    
3344     /* 8.3.63: CHARACTER TABULATION SET */
3345     case C1_HTS: /* ESC H */
3346     scr_set_tab (1);
3347     break;
3348    
3349     /* 8.3.105: REVERSE LINE FEED */
3350     case C1_RI: /* ESC M */
3351     scr_index (DN);
3352     break;
3353    
3354     /* 8.3.142: SINGLE-SHIFT TWO */
3355 pcg 1.90 /*case C1_SS2: scr_single_shift (2); break; */
3356 pcg 1.36
3357     /* 8.3.143: SINGLE-SHIFT THREE */
3358 pcg 1.90 /*case C1_SS3: scr_single_shift (3); break; */
3359 pcg 1.36
3360     /* 8.3.27: DEVICE CONTROL STRING */
3361     case C1_DCS: /* ESC P */
3362     process_dcs_seq ();
3363     break;
3364    
3365     /* 8.3.110: SINGLE CHARACTER INTRODUCER */
3366     case C1_SCI: /* ESC Z */
3367 root 1.234 tt_write (ESCZ_ANSWER, sizeof (ESCZ_ANSWER) - 1);
3368 pcg 1.36 break; /* steal obsolete ESC [ c */
3369    
3370     /* 8.3.16: CONTROL SEQUENCE INTRODUCER */
3371     case C1_CSI: /* ESC [ */
3372     process_csi_seq ();
3373     break;
3374 pcg 1.1
3375 pcg 1.36 /* 8.3.90: OPERATING SYSTEM COMMAND */
3376     case C1_OSC: /* ESC ] */
3377     process_osc_seq ();
3378     break;
3379    
3380     /* 8.3.106: RESET TO INITIAL STATE */
3381     case 'c':
3382 pcg 1.90 mbstate.reset ();
3383 pcg 1.36 scr_poweron ();
3384     scrollbar_show (1);
3385     break;
3386    
3387     /* 8.3.79: LOCKING-SHIFT TWO (see ISO2022) */
3388     case 'n':
3389     scr_charset_choose (2);
3390     break;
3391    
3392     /* 8.3.81: LOCKING-SHIFT THREE (see ISO2022) */
3393     case 'o':
3394     scr_charset_choose (3);
3395     break;
3396 pcg 1.1 }
3397     }
3398     /*}}} */
3399    
3400     /*{{{ process CONTROL SEQUENCE INTRODUCER (CSI) sequences `ESC[' */
3401     /* *INDENT-OFF* */
3402     enum {
3403 pcg 1.36 CSI_ICH = 0x40,
3404 pcg 1.95 CSI_CUU, CSI_CUD, CSI_CUF, CSI_CUB, CSI_CNL, CSI_CPL, CSI_CHA,
3405 pcg 1.36 CSI_CUP, CSI_CHT, CSI_ED , CSI_EL , CSI_IL , CSI_DL , CSI_EF , CSI_EA ,
3406     CSI_DCH, CSI_SEE, CSI_CPR, CSI_SU , CSI_SD , CSI_NP , CSI_PP , CSI_CTC,
3407     CSI_ECH, CSI_CVT, CSI_CBT, CSI_SRS, CSI_PTX, CSI_SDS, CSI_SIMD, CSI_5F,
3408     CSI_HPA, CSI_HPR, CSI_REP, CSI_DA , CSI_VPA, CSI_VPR, CSI_HVP, CSI_TBC,
3409     CSI_SM , CSI_MC , CSI_HPB, CSI_VPB, CSI_RM , CSI_SGR, CSI_DSR, CSI_DAQ,
3410     CSI_70 , CSI_71 , CSI_72 , CSI_73 , CSI_74 , CSI_75 , CSI_76 , CSI_77 ,
3411     CSI_78 , CSI_79 , CSI_7A , CSI_7B , CSI_7C , CSI_7D , CSI_7E , CSI_7F
3412 pcg 1.1 };
3413    
3414     #define make_byte(b7,b6,b5,b4,b3,b2,b1,b0) \
3415     (((b7) << 7) | ((b6) << 6) | ((b5) << 5) | ((b4) << 4) \
3416     | ((b3) << 3) | ((b2) << 2) | ((b1) << 1) | (b0))
3417     #define get_byte_array_bit(array, bit) \
3418 pcg 1.43 (!! ((array)[ (bit) / 8] & (128 >> ((bit) & 7))))
3419 pcg 1.1
3420 pcg 1.36 const unsigned char csi_defaults[] =
3421     {
3422 pcg 1.43 make_byte (1,1,1,1,1,1,1,1), /* @, A, B, C, D, E, F, G, */
3423     make_byte (1,1,0,0,1,1,0,0), /* H, I, J, K, L, M, N, O, */
3424     make_byte (1,0,1,1,1,1,1,0), /* P, Q, R, S, T, U, V, W, */
3425     make_byte (1,1,1,0,0,0,1,0), /* X, Y, Z, [, \, ], ^, _, */
3426     make_byte (1,1,1,0,1,1,1,0), /* `, a, b, c, d, e, f, g, */
3427     make_byte (0,0,1,1,0,0,0,0), /* h, i, j, k, l, m, n, o, */
3428     make_byte (0,0,0,0,0,0,0,0), /* p, q, r, s, t, u, v, w, */
3429 pcg 1.90 make_byte (0,0,0,0,0,0,0,0), /* x, y, z, {, |, }, ~, */
3430 pcg 1.36 };
3431 pcg 1.1 /* *INDENT-ON* */
3432    
3433     void
3434 pcg 1.34 rxvt_term::process_csi_seq ()
3435 pcg 1.1 {
3436 pcg 1.81 unicode_t ch, priv, i;
3437     unsigned int nargs, p;
3438     int n, ndef;
3439     int arg[ESC_ARGS];
3440 pcg 1.36
3441     for (nargs = ESC_ARGS; nargs > 0;)
3442     arg[--nargs] = 0;
3443    
3444     priv = 0;
3445     ch = cmd_getc ();
3446     if (ch >= '<' && ch <= '?')
3447     { /* '<' '=' '>' '?' */
3448     priv = ch;
3449     ch = cmd_getc ();
3450     }
3451 pcg 1.81
3452 pcg 1.36 /* read any numerical arguments */
3453     for (n = -1; ch < CSI_ICH; )
3454     {
3455 pcg 1.43 if (isdigit (ch))
3456 pcg 1.36 {
3457     if (n < 0)
3458     n = ch - '0';
3459     else
3460     n = n * 10 + ch - '0';
3461     }
3462     else if (ch == ';')
3463     {
3464     if (nargs < ESC_ARGS)
3465     arg[nargs++] = n;
3466     n = -1;
3467     }
3468 pcg 1.81 else if (IS_CONTROL (ch))
3469     process_nonprinting (ch);
3470    
3471 pcg 1.36 ch = cmd_getc ();
3472     }
3473 pcg 1.1
3474 pcg 1.36 if (ch > CSI_7F)
3475     return;
3476 pcg 1.1
3477 pcg 1.36 if (nargs < ESC_ARGS)
3478     arg[nargs++] = n;
3479    
3480     i = ch - CSI_ICH;
3481 pcg 1.43 ndef = get_byte_array_bit (csi_defaults, i);
3482 pcg 1.36 for (p = 0; p < nargs; p++)
3483     if (arg[p] == -1)
3484     arg[p] = ndef;
3485 pcg 1.1
3486 pcg 1.36 /*
3487     * private mode handling
3488     */
3489     if (priv)
3490     {
3491     switch (priv)
3492     {
3493     case '>':
3494     if (ch == CSI_DA) /* secondary device attributes */
3495 root 1.282 {
3496     // first parameter is normally 0 for vt100, 1 for some newer vtxxx, 'R' for rxvt,
3497 root 1.289 // 'U' for rxvt-unicode != 7.[34] (where it was broken).
3498 root 1.282 //
3499     // second parameter is xterm patch level for xterm, MMmmpp (e.g. 20703) for rxvt
3500     // and Mm (e.g. 72 for 7.2) for urxvt <= 7.2, and 94 for later versions, to signify
3501     // that we do not support xterm mouse reporting (should be 95 when we do).
3502     //
3503 root 1.289 tt_printf ("\033[>%d;94;0c", 'U');
3504 root 1.282 }
3505 pcg 1.36 break;
3506     case '?':
3507     if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
3508     process_terminal_mode (ch, priv, nargs, arg);
3509     break;
3510     }
3511     return;
3512 pcg 1.1 }
3513    
3514 pcg 1.36 switch (ch)
3515     {
3516     /*
3517 pcg 1.43 * ISO/IEC 6429:1992 (E) CSI sequences (defaults in parentheses)
3518 pcg 1.36 */
3519 pcg 1.1 #ifdef PRINTPIPE
3520 pcg 1.36 case CSI_MC: /* 8.3.83: (0) MEDIA COPY */
3521     switch (arg[0])
3522     {
3523     case 0: /* initiate transfer to primary aux device */
3524     scr_printscreen (0);
3525     break;
3526     case 5: /* start relay to primary aux device */
3527     process_print_pipe ();
3528     break;
3529     }
3530     break;
3531     #endif
3532 pcg 1.1
3533 pcg 1.36 case CSI_CUU: /* 8.3.22: (1) CURSOR UP */
3534     case CSI_VPR: /* 8.3.161: (1) LINE POSITION FORWARD */
3535     arg[0] = -arg[0];
3536     /* FALLTHROUGH */
3537     case CSI_CUD: /* 8.3.19: (1) CURSOR DOWN */
3538     case CSI_VPB: /* 8.3.160: (1) LINE POSITION BACKWARD */
3539     scr_gotorc (arg[0], 0, RELATIVE);
3540     break;
3541    
3542     case CSI_CUB: /* 8.3.18: (1) CURSOR LEFT */
3543     case CSI_HPB: /* 8.3.59: (1) CHARACTER POSITION BACKWARD */
3544 pcg 1.1 #ifdef ISO6429
3545 pcg 1.36 arg[0] = -arg[0];
3546 pcg 1.1 #else /* emulate common DEC VTs */
3547 pcg 1.36 arg[0] = arg[0] ? -arg[0] : -1;
3548 pcg 1.1 #endif
3549 pcg 1.36 /* FALLTHROUGH */
3550     case CSI_CUF: /* 8.3.20: (1) CURSOR RIGHT */
3551     case CSI_HPR: /* 8.3.60: (1) CHARACTER POSITION FORWARD */
3552 pcg 1.1 #ifdef ISO6429
3553 pcg 1.36 scr_gotorc (0, arg[0], RELATIVE);
3554 pcg 1.1 #else /* emulate common DEC VTs */
3555 pcg 1.36 scr_gotorc (0, arg[0] ? arg[0] : 1, RELATIVE);
3556 pcg 1.1 #endif
3557 pcg 1.36 break;
3558    
3559     case CSI_CPL: /* 8.3.13: (1) CURSOR PRECEDING LINE */
3560     arg[0] = -arg[0];
3561     /* FALLTHROUGH */
3562     case CSI_CNL: /* 8.3.12: (1) CURSOR NEXT LINE */
3563     scr_gotorc (arg[0], 0, R_RELATIVE);
3564     break;
3565    
3566     case CSI_CHA: /* 8.3.9: (1) CURSOR CHARACTER ABSOLUTE */
3567     case CSI_HPA: /* 8.3.58: (1) CURSOR POSITION ABSOLUTE */
3568     scr_gotorc (0, arg[0] - 1, R_RELATIVE);
3569     break;
3570    
3571     case CSI_VPA: /* 8.3.159: (1) LINE POSITION ABSOLUTE */
3572     scr_gotorc (arg[0] - 1, 0, C_RELATIVE);
3573     break;
3574    
3575     case CSI_CUP: /* 8.3.21: (1,1) CURSOR POSITION */
3576     case CSI_HVP: /* 8.3.64: (1,1) CHARACTER AND LINE POSITION */
3577     scr_gotorc (arg[0] - 1, nargs < 2 ? 0 : (arg[1] - 1), 0);
3578     break;
3579 pcg 1.1
3580 pcg 1.36 case CSI_CBT: /* 8.3.7: (1) CURSOR BACKWARD TABULATION */
3581     arg[0] = -arg[0];
3582     /* FALLTHROUGH */
3583     case CSI_CHT: /* 8.3.10: (1) CURSOR FORWARD TABULATION */
3584     scr_tab (arg[0]);
3585     break;
3586    
3587     case CSI_ED: /* 8.3.40: (0) ERASE IN PAGE */
3588     scr_erase_screen (arg[0]);
3589     break;
3590    
3591     case CSI_EL: /* 8.3.42: (0) ERASE IN LINE */
3592     scr_erase_line (arg[0]);
3593     break;
3594    
3595     case CSI_ICH: /* 8.3.65: (1) INSERT CHARACTER */
3596     scr_insdel_chars (arg[0], INSERT);
3597     break;
3598    
3599     case CSI_IL: /* 8.3.68: (1) INSERT LINE */
3600     scr_insdel_lines (arg[0], INSERT);
3601     break;
3602    
3603     case CSI_DL: /* 8.3.33: (1) DELETE LINE */
3604     scr_insdel_lines (arg[0], DELETE);
3605     break;
3606    
3607     case CSI_ECH: /* 8.3.39: (1) ERASE CHARACTER */
3608     scr_insdel_chars (arg[0], ERASE);
3609     break;
3610    
3611     case CSI_DCH: /* 8.3.26: (1) DELETE CHARACTER */
3612     scr_insdel_chars (arg[0], DELETE);
3613     break;
3614    
3615     case CSI_SD: /* 8.3.114: (1) SCROLL DOWN */
3616     arg[0] = -arg[0];
3617     /* FALLTHROUGH */
3618     case CSI_SU: /* 8.3.148: (1) SCROLL UP */
3619 root 1.210 scr_scroll_text (screen.tscroll, screen.bscroll, arg[0]);
3620 pcg 1.36 break;
3621    
3622     case CSI_DA: /* 8.3.24: (0) DEVICE ATTRIBUTES */
3623 root 1.234 tt_write (VT100_ANS, sizeof (VT100_ANS) - 1);
3624 pcg 1.36 break;
3625    
3626     case CSI_SGR: /* 8.3.118: (0) SELECT GRAPHIC RENDITION */
3627     process_sgr_mode (nargs, arg);
3628     break;
3629    
3630     case CSI_DSR: /* 8.3.36: (0) DEVICE STATUS REPORT */
3631     switch (arg[0])
3632     {
3633     case 5: /* DSR requested */
3634 pcg 1.43 tt_printf ("\033[0n");
3635 pcg 1.36 break;
3636     case 6: /* CPR requested */
3637     scr_report_position ();
3638     break;
3639     case 7: /* unofficial extension */
3640 root 1.321 if (option (Opt_insecure))
3641 root 1.145 tt_printf ("%-.250s\012", rs[Rs_display_name]);
3642 pcg 1.36 break;
3643     case 8: /* unofficial extension */
3644 pcg 1.90 process_xterm_seq (XTerm_title, RESNAME "-" VERSION, CHAR_ST);
3645 pcg 1.36 break;
3646     }
3647     break;
3648 pcg 1.1
3649 pcg 1.36 case CSI_TBC: /* 8.3.155: (0) TABULATION CLEAR */
3650     switch (arg[0])
3651     {
3652     case 0: /* char tab stop cleared at active position */
3653     scr_set_tab (0);
3654     break;
3655     /* case 1: */ /* line tab stop cleared in active line */
3656     /* case 2: */ /* char tab stops cleared in active line */
3657     case 3: /* all char tab stops are cleared */
3658     /* case 4: */ /* all line tab stops are cleared */
3659     case 5: /* all tab stops are cleared */
3660     scr_set_tab (-1);
3661     break;
3662     }
3663     break;
3664    
3665     case CSI_CTC: /* 8.3.17: (0) CURSOR TABULATION CONTROL */
3666     switch (arg[0])
3667     {
3668     case 0: /* char tab stop set at active position */
3669     scr_set_tab (1);
3670     break; /* = ESC H */
3671     /* case 1: */ /* line tab stop set at active line */
3672     case 2: /* char tab stop cleared at active position */
3673     scr_set_tab (0);
3674     break; /* = ESC [ 0 g */
3675     /* case 3: */ /* line tab stop cleared at active line */
3676     /* case 4: */ /* char tab stops cleared at active line */
3677     case 5: /* all char tab stops are cleared */
3678     scr_set_tab (-1);
3679     break; /* = ESC [ 3 g */
3680     /* case 6: */ /* all line tab stops are cleared */
3681     }
3682     break;
3683    
3684     case CSI_RM: /* 8.3.107: RESET MODE */
3685     if (arg[0] == 4)
3686     scr_insert_mode (0);
3687 root 1.145 else if (arg[0] == 20)
3688     priv_modes &= ~PrivMode_LFNL;
3689 pcg 1.36 break;
3690    
3691     case CSI_SM: /* 8.3.126: SET MODE */
3692     if (arg[0] == 4)
3693     scr_insert_mode (1);
3694 root 1.145 else if (arg[0] == 20)
3695     priv_modes |= PrivMode_LFNL;
3696 pcg 1.36 break;
3697    
3698     /*
3699     * PRIVATE USE beyond this point. All CSI_7? sequences here
3700     */
3701     case CSI_72: /* DECSTBM: set top and bottom margins */
3702     if (nargs == 1)
3703     scr_scroll_region (arg[0] - 1, MAX_ROWS - 1);
3704     else if (nargs == 0 || arg[0] >= arg[1])
3705     scr_scroll_region (0, MAX_ROWS - 1);
3706     else
3707     scr_scroll_region (arg[0] - 1, arg[1] - 1);
3708     break;
3709    
3710     case CSI_73:
3711     scr_cursor (SAVE);
3712     break;
3713     case CSI_75:
3714     scr_cursor (RESTORE);
3715     break;
3716 pcg 1.1
3717 root 1.294 #if !ENABLE_MINIMAL
3718 pcg 1.36 case CSI_74:
3719     process_window_ops (arg, nargs);
3720     break;
3721 pcg 1.1 #endif
3722    
3723 pcg 1.36 case CSI_78: /* DECREQTPARM */
3724     if (arg[0] == 0 || arg[0] == 1)
3725 pcg 1.43 tt_printf ("\033[%d;1;1;128;128;1;0x", arg[0] + 2);
3726 pcg 1.81 break;
3727 pcg 1.1
3728 pcg 1.36 default:
3729     break;
3730 pcg 1.1 }
3731     }
3732     /*}}} */
3733    
3734 root 1.294 #if !ENABLE_MINIMAL
3735 pcg 1.1 /* ARGSUSED */
3736     void
3737 pcg 1.34 rxvt_term::process_window_ops (const int *args, unsigned int nargs)
3738 pcg 1.1 {
3739 pcg 1.81 int x, y;
3740 pcg 1.36 XWindowAttributes wattr;
3741 pcg 1.81 Window wdummy;
3742 root 1.285
3743 root 1.305 dLocal (Display *, dpy);
3744 pcg 1.1
3745 pcg 1.36 if (nargs == 0)
3746     return;
3747 pcg 1.81
3748 pcg 1.36 switch (args[0])
3749     {
3750 pcg 1.81 /*
3751     * commands
3752     */
3753 pcg 1.36 case 1: /* deiconify window */
3754 root 1.305 XMapWindow (dpy, parent[0]);
3755 pcg 1.36 break;
3756     case 2: /* iconify window */
3757 root 1.305 XIconifyWindow (dpy, parent[0], display->screen);
3758 pcg 1.36 break;
3759     case 3: /* set position (pixels) */
3760 root 1.305 XMoveWindow (dpy, parent[0], args[1], args[2]);
3761 pcg 1.36 break;
3762     case 4: /* set size (pixels) */
3763     set_widthheight ((unsigned int)args[2], (unsigned int)args[1]);
3764     break;
3765     case 5: /* raise window */
3766 root 1.305 XRaiseWindow (dpy, parent[0]);
3767 pcg 1.36 break;
3768     case 6: /* lower window */
3769 root 1.305 XLowerWindow (dpy, parent[0]);
3770 pcg 1.36 break;
3771     case 7: /* refresh window */
3772     scr_touch (true);
3773     break;
3774     case 8: /* set size (chars) */
3775 root 1.208 set_widthheight ((unsigned int) (args[2] * fwidth),
3776     (unsigned int) (args[1] * fheight));
3777 pcg 1.36 break;
3778 pcg 1.81
3779     //case 9: NYI, TODO, restore maximized window or maximize window
3780 pcg 1.36 default:
3781     if (args[0] >= 24) /* set height (chars) */
3782 root 1.208 set_widthheight ((unsigned int)width,
3783     (unsigned int) (args[1] * fheight));
3784 pcg 1.36 break;
3785 pcg 1.81
3786     /*
3787     * reports - some output format copied from XTerm
3788     */
3789 pcg 1.36 case 11: /* report window state */
3790 root 1.305 XGetWindowAttributes (dpy, parent[0], &wattr);
3791 pcg 1.43 tt_printf ("\033[%dt", wattr.map_state == IsViewable ? 1 : 2);
3792 pcg 1.36 break;
3793     case 13: /* report window position */
3794 root 1.305 XGetWindowAttributes (dpy, parent[0], &wattr);
3795     XTranslateCoordinates (dpy, parent[0], wattr.root,
3796 pcg 1.90 -wattr.border_width, -wattr.border_width,
3797     &x, &y, &wdummy);
3798 pcg 1.43 tt_printf ("\033[3;%d;%dt", x, y);
3799 pcg 1.36 break;
3800     case 14: /* report window size (pixels) */
3801 root 1.305 XGetWindowAttributes (dpy, parent[0], &wattr);
3802 pcg 1.43 tt_printf ("\033[4;%d;%dt", wattr.height, wattr.width);
3803 pcg 1.36 break;
3804 pcg 1.81 case 18: /* report text area size (chars) */
3805 root 1.208 tt_printf ("\033[8;%d;%dt", nrow, ncol);
3806 pcg 1.36 break;
3807 pcg 1.81 case 19: /* report window size (chars) */
3808 root 1.208 tt_printf ("\033[9;%d;%dt", nrow, ncol);
3809 pcg 1.81 break;
3810 pcg 1.36 case 20: /* report icon label */
3811 root 1.131 {
3812     char *s;
3813 root 1.305 XGetIconName (dpy, parent[0], &s);
3814 root 1.321 tt_printf ("\033]L%-.250s\234", option (Opt_insecure) && s ? s : ""); /* 8bit ST */
3815 root 1.131 XFree (s);
3816     }
3817 pcg 1.36 break;
3818     case 21: /* report window title */
3819 root 1.131 {
3820     char *s;
3821 root 1.305 XFetchName (dpy, parent[0], &s);
3822 root 1.321 tt_printf ("\033]l%-.250s\234", option (Opt_insecure) && s ? s : ""); /* 8bit ST */
3823 root 1.131 XFree (s);
3824     }
3825 pcg 1.36 break;
3826 pcg 1.1 }
3827     }
3828     #endif
3829    
3830     /*----------------------------------------------------------------------*/
3831     /*
3832     * get input up until STRING TERMINATOR (or BEL)
3833 pcg 1.93 * ends_how is terminator used. returned input must be free()'d
3834 pcg 1.1 */
3835 root 1.234 char *
3836 pcg 1.81 rxvt_term::get_to_st (unicode_t &ends_how)
3837 pcg 1.1 {
3838 root 1.175 unicode_t ch;
3839     bool seen_esc = false;
3840 pcg 1.81 unsigned int n = 0;
3841 root 1.175 wchar_t string[STRING_MAX];
3842 pcg 1.36
3843 root 1.97 while ((ch = cmd_getc ()) != NOCHAR)
3844 pcg 1.36 {
3845 root 1.163 if (seen_esc)
3846 pcg 1.36 {
3847 root 1.97 if (ch == 0x5c) /* 7bit ST */
3848     break;
3849     else
3850     return NULL;
3851 pcg 1.36 }
3852 root 1.163 else if (ch == C0_ESC)
3853     {
3854 root 1.175 seen_esc = true;
3855 root 1.163 continue;
3856     }
3857 root 1.97 else if (ch == C0_BEL || ch == CHAR_ST)
3858     break;
3859 root 1.315 else if (ch == C0_SYN)
3860     ch = cmd_get8 ();
3861 root 1.97 else if (ch < 0x20)
3862 pcg 1.36 return NULL; /* other control character - exit */
3863 pcg 1.81
3864 root 1.175 seen_esc = false;
3865 root 1.163
3866 root 1.202 if (n >= STRING_MAX - 1)
3867 pcg 1.90 // stop at some sane length
3868     return NULL;
3869 pcg 1.81
3870 root 1.315 string[n++] = ch;
3871 pcg 1.36 }
3872 pcg 1.81
3873 pcg 1.36 string[n++] = '\0';
3874 pcg 1.81
3875 root 1.175 ends_how = (ch == 0x5c ? C0_ESC : ch);
3876 pcg 1.81
3877 root 1.234 return rxvt_wcstombs (string);
3878 pcg 1.1 }
3879    
3880     /*----------------------------------------------------------------------*/
3881     /*
3882     * process DEVICE CONTROL STRING `ESC P ... (ST|BEL)' or `0x90 ... (ST|BEL)'
3883     */
3884     void
3885 pcg 1.34 rxvt_term::process_dcs_seq ()
3886 pcg 1.1 {
3887 root 1.234 char *s;
3888 pcg 1.81 unicode_t eh;
3889    
3890 pcg 1.36 /*
3891     * Not handled yet
3892     */
3893 pcg 1.81 s = get_to_st (eh);
3894 pcg 1.36 if (s)
3895 pcg 1.43 free (s);
3896 pcg 1.81
3897 pcg 1.36 return;
3898 pcg 1.1 }
3899    
3900     /*----------------------------------------------------------------------*/
3901     /*
3902     * process OPERATING SYSTEM COMMAND sequence `ESC ] Ps ; Pt (ST|BEL)'
3903     */
3904     void
3905 pcg 1.34 rxvt_term::process_osc_seq ()
3906 pcg 1.1 {
3907 pcg 1.81 unicode_t ch, eh;
3908     int arg;
3909 pcg 1.1
3910 pcg 1.36 ch = cmd_getc ();
3911 pcg 1.43 for (arg = 0; isdigit (ch); ch = cmd_getc ())
3912 pcg 1.36 arg = arg * 10 + (ch - '0');
3913 pcg 1.1
3914 pcg 1.36 if (ch == ';')
3915     {
3916 root 1.234 char *s = get_to_st (eh);
3917 pcg 1.81
3918 pcg 1.36 if (s)
3919     {
3920 root 1.234 process_xterm_seq (arg, s, eh);
3921 pcg 1.90 free (s);
3922     }
3923     }
3924     }
3925 pcg 1.81
3926 pcg 1.90 void
3927 root 1.234 rxvt_term::process_color_seq (int report, int color, const char *str, char resp)
3928 pcg 1.90 {
3929     if (str[0] == '?' && !str[1])
3930     {
3931 root 1.298 rgba c;
3932 root 1.300 pix_colors_focused[color].get (c);
3933 root 1.291
3934     #if XFT
3935 root 1.298 if (c.a != rgba::MAX_CC)
3936 root 1.292 tt_printf ("\033]%d;rgba:%04x/%04x/%04x/%04x%c", report, c.a, c.r, c.g, c.b, resp);
3937 root 1.291 else
3938     #endif
3939     tt_printf ("\033]%d;rgb:%04x/%04x/%04x%c", report, c.r, c.g, c.b, resp);
3940 pcg 1.1 }
3941 pcg 1.90 else
3942     set_window_color (color, str);
3943 pcg 1.1 }
3944 pcg 1.90
3945 pcg 1.1 /*
3946     * XTerm escape sequences: ESC ] Ps;Pt (ST|BEL)
3947     */
3948     void
3949 root 1.234 rxvt_term::process_xterm_seq (int op, const char *str, char resp)
3950 pcg 1.1 {
3951 pcg 1.81 int color;
3952     char *buf, *name;
3953 pcg 1.90 bool query = str[0] == '?' && !str[1];
3954 root 1.163 int saveop = op;
3955 root 1.285
3956 root 1.305 dLocal (Display *, dpy);
3957 pcg 1.36
3958 pcg 1.43 assert (str != NULL);
3959 root 1.311
3960     if (HOOK_INVOKE ((this, HOOK_OSC_SEQ, DT_INT, op, DT_STR, str, DT_END)))
3961 root 1.312 return;
3962 root 1.311
3963 pcg 1.36 switch (op)
3964     {
3965     case XTerm_name:
3966     set_title (str);
3967     /* FALLTHROUGH */
3968     case XTerm_iconName:
3969 pcg 1.81 set_icon_name (str);
3970 pcg 1.36 break;
3971     case XTerm_title:
3972     set_title (str);
3973     break;
3974 pcg 1.90 case XTerm_property:
3975     if (str[0] == '?')
3976     {
3977 root 1.175 Atom prop = display->atom (str + 1);
3978 pcg 1.90 Atom actual_type;
3979     int actual_format;
3980     unsigned long nitems;
3981     unsigned long bytes_after;
3982     unsigned char *value = 0;
3983     const char *str = "";
3984    
3985     if (prop
3986 root 1.305 && XGetWindowProperty (dpy, parent[0],
3987 pcg 1.90 prop, 0, 1<<16, 0, AnyPropertyType,
3988     &actual_type, &actual_format,
3989     &nitems, &bytes_after, &value) == Success
3990     && actual_type != None
3991     && actual_format == 8)
3992     str = (const char *)(value);
3993    
3994 root 1.290 tt_printf ("\033]%d;%s%c", op, str, resp);
3995 pcg 1.90
3996     XFree (value);
3997     }
3998     else
3999     {
4000     char *eq = strchr (str, '='); // constness lost, but verified to be ok
4001    
4002     if (eq)
4003     {
4004     *eq = 0;
4005 root 1.175 set_utf8_property (display->atom (str), eq + 1);
4006 pcg 1.90 }
4007     else
4008 root 1.305 XDeleteProperty (dpy, parent[0],
4009 pcg 1.90 display->atom (str));
4010     }
4011     break;
4012    
4013 pcg 1.36 case XTerm_Color:
4014     for (buf = (char *)str; buf && *buf;)
4015     {
4016 root 1.145 if ((name = strchr (buf, ';')) == NULL)
4017 pcg 1.36 break;
4018 pcg 1.81
4019 pcg 1.36 *name++ = '\0';
4020 root 1.256 color = atoi (buf) + minCOLOR;
4021 pcg 1.81
4022 root 1.257 if (!IN_RANGE_INC (color, minCOLOR, maxTermCOLOR))
4023 pcg 1.36 break;
4024 pcg 1.81
4025 root 1.145 if ((buf = strchr (name, ';')) != NULL)
4026 pcg 1.36 *buf++ = '\0';
4027 pcg 1.81
4028 root 1.291 process_color_seq (op, color, name, resp);
4029 pcg 1.36 }
4030     break;
4031 pcg 1.90 case XTerm_Color00:
4032 root 1.290 process_color_seq (op, Color_fg, str, resp);
4033 pcg 1.90 break;
4034     case XTerm_Color01:
4035 root 1.290 process_color_seq (op, Color_bg, str, resp);
4036 pcg 1.90 break;
4037 pcg 1.1 #ifndef NO_CURSORCOLOR
4038 pcg 1.36 case XTerm_Color_cursor:
4039 root 1.290 process_color_seq (op, Color_cursor, str, resp);
4040 pcg 1.36 break;
4041     #endif
4042 pcg 1.90 case XTerm_Color_pointer_fg:
4043 root 1.290 process_color_seq (op, Color_pointer_fg, str, resp);
4044 pcg 1.90 break;
4045     case XTerm_Color_pointer_bg:
4046 root 1.290 process_color_seq (op, Color_pointer_bg, str, resp);
4047 pcg 1.36 break;
4048 pcg 1.1 #ifndef NO_BOLD_UNDERLINE_REVERSE
4049 pcg 1.36 case XTerm_Color_RV:
4050 root 1.290 process_color_seq (op, Color_RV, str, resp);
4051 pcg 1.36 break;
4052 root 1.257 case Rxvt_Color_BD:
4053     case URxvt_Color_BD:
4054     process_color_seq (op, Color_BD, str, resp);
4055     break;
4056     case Rxvt_Color_UL:
4057     case URxvt_Color_UL:
4058     process_color_seq (op, Color_UL, str, resp);
4059     break;
4060 root 1.201 case URxvt_Color_IT:
4061 root 1.290 process_color_seq (op, Color_IT, str, resp);
4062 root 1.201 break;
4063 pcg 1.1 #endif
4064 root 1.170 #if TRANSPARENT && TINTING
4065 root 1.201 case URxvt_Color_tint:
4066 root 1.290 process_color_seq (op, Color_tint, str, resp);
4067 root 1.297
4068 root 1.163 check_our_parents ();
4069 root 1.297
4070 root 1.163 if (am_transparent)
4071     want_full_refresh = want_refresh = 1;
4072 root 1.297
4073 root 1.163 break;
4074     #endif
4075 pcg 1.1
4076 root 1.257 case Rxvt_Pixmap:
4077 root 1.271 {
4078     if (*str != ';')
4079     {
4080 pcg 1.1 #if XPM_BACKGROUND
4081 root 1.271 scale_pixmap (""); /* reset to default scaling */
4082     set_bgPixmap (str); /* change pixmap */
4083     scr_touch (true);
4084 pcg 1.1 #endif
4085 root 1.271 }
4086    
4087     int changed = 0;
4088 root 1.256
4089 root 1.271 while ((str = strchr (str, ';')) != NULL)
4090     {
4091     str++;
4092 pcg 1.1 #if XPM_BACKGROUND
4093 root 1.271 changed += scale_pixmap (str);
4094 pcg 1.1 #endif
4095 root 1.271 }
4096 pcg 1.36
4097 root 1.271 if (changed)
4098     {
4099 pcg 1.1 #ifdef XPM_BACKGROUND
4100 root 1.271 resize_pixmap ();
4101     scr_touch (true);
4102 pcg 1.1 #endif
4103 root 1.271 }
4104 sasha 1.324 #if TRANSPARENT && defined(HAVE_AFTERIMAGE)
4105     if (option(Opt_transparent))
4106     check_our_parents ();
4107     #endif
4108    
4109 root 1.271 }
4110 pcg 1.36 break;
4111    
4112 root 1.257 case Rxvt_restoreFG:
4113 pcg 1.36 set_window_color (Color_fg, str);
4114     break;
4115 root 1.257 case Rxvt_restoreBG:
4116 pcg 1.36 set_window_color (Color_bg, str);
4117     break;
4118 pcg 1.90
4119 pcg 1.36 case XTerm_logfile:
4120 pcg 1.81 // TODO, when secure mode?
4121 pcg 1.36 break;
4122 pcg 1.90
4123 root 1.201 #if 0
4124 root 1.257 case Rxvt_dumpscreen: /* no error notices */
4125 root 1.201 {
4126     int fd;
4127     if ((fd = open (str, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0)
4128     {
4129     scr_dump (fd);
4130     close (fd);
4131     }
4132     }
4133     break;
4134     #endif
4135 pcg 1.36 case XTerm_font:
4136 root 1.163 op = URxvt_font;
4137     case URxvt_font:
4138     #if ENABLE_STYLES
4139     case URxvt_boldFont:
4140     case URxvt_italicFont:
4141     case URxvt_boldItalicFont:
4142     #endif
4143 pcg 1.90 if (query)
4144 root 1.163 tt_printf ("\33]%d;%-.250s%c", saveop,
4145 root 1.321 option (Opt_insecure) && fontset[op - URxvt_font]->fontdesc
4146 root 1.208 ? fontset[op - URxvt_font]->fontdesc : "",
4147 root 1.131 resp);
4148 pcg 1.90 else
4149 root 1.163 {
4150     const char *&res = rs[Rs_font + (op - URxvt_font)];
4151    
4152     res = strdup (str);
4153     allocated.push_back ((void *)res);
4154     set_fonts ();
4155     }
4156 pcg 1.51 break;
4157 pcg 1.90
4158 root 1.288 case URxvt_version:
4159     if (query)
4160     tt_printf ("\33]%d;rxvt-unicode;%-.20s;%c;%c%c",
4161 root 1.290 op,
4162     rs[Rs_name], VERSION[0], VERSION[2],
4163 root 1.288 resp);
4164     break;
4165    
4166 root 1.294 #if !ENABLE_MINIMAL
4167 root 1.201 case URxvt_locale:
4168 pcg 1.90 if (query)
4169 root 1.321 tt_printf ("\33]%d;%-.250s%c", op, option (Opt_insecure) ? locale : "", resp);
4170 pcg 1.54 else
4171     {
4172     set_locale (str);
4173 root 1.269 pty->set_utf8_mode (enc_utf8);
4174 root 1.199 init_xlocale ();
4175 pcg 1.54 }
4176 pcg 1.36 break;
4177 pcg 1.90
4178 root 1.201 case URxvt_view_up:
4179     case URxvt_view_down:
4180 root 1.231 {
4181     int lines = atoi (str);
4182 root 1.201
4183 root 1.231 if (lines)
4184     scr_page (op == URxvt_view_up ? UP : DN, lines);
4185     else
4186     scr_erase_savelines ();
4187     }
4188 root 1.230
4189     break;
4190     #endif
4191 root 1.201
4192 root 1.230 #if ENABLE_PERL
4193     case URxvt_perl:
4194 root 1.311 if (HOOK_INVOKE ((this, HOOK_OSC_SEQ_PERL, DT_STR, str, DT_END)))
4195 root 1.230 ; // no responses yet
4196 pcg 1.36 break;
4197 pcg 1.1 #endif
4198     }
4199     }
4200     /*----------------------------------------------------------------------*/
4201    
4202     /*{{{ process DEC private mode sequences `ESC [ ? Ps mode' */
4203     /*
4204     * mode can only have the following values:
4205     * 'l' = low
4206     * 'h' = high
4207     * 's' = save
4208     * 'r' = restore
4209     * 't' = toggle
4210     * so no need for fancy checking
4211     */
4212     int
4213 pcg 1.34 rxvt_term::privcases (int mode, unsigned long bit)
4214 pcg 1.1 {
4215 pcg 1.81 int state;
4216 pcg 1.1
4217 pcg 1.36 if (mode == 's')
4218     {
4219 root 1.145 SavedModes |= (priv_modes & bit);
4220 pcg 1.36 return -1;
4221 pcg 1.1 }
4222 pcg 1.36 else
4223     {
4224     if (mode == 'r')
4225     state = (SavedModes & bit) ? 1 : 0; /* no overlapping */
4226     else
4227 root 1.145 state = (mode == 't') ? ! (priv_modes & bit) : mode;
4228 pcg 1.43 PrivMode (state, bit);
4229 pcg 1.36 }
4230 pcg 1.81
4231 pcg 1.36 return state;
4232 pcg 1.1 }
4233    
4234     /* we're not using priv _yet_ */
4235     void
4236 root 1.274 rxvt_term::process_terminal_mode (int mode, int priv UNUSED, unsigned int nargs, const int *arg)
4237 pcg 1.1 {
4238 pcg 1.81 unsigned int i, j;
4239     int state;
4240    
4241 pcg 1.36 static const struct
4242     {
4243     const int argval;
4244     const unsigned long bit;
4245     }
4246 pcg 1.81
4247 pcg 1.36 argtopriv[] = {
4248     { 1, PrivMode_aplCUR },
4249     { 2, PrivMode_vt52 },
4250     { 3, PrivMode_132 },
4251     { 4, PrivMode_smoothScroll },
4252     { 5, PrivMode_rVideo },
4253     { 6, PrivMode_relOrigin },
4254     { 7, PrivMode_Autowrap },
4255 root 1.145 // 8, bi-directional support mode
4256 pcg 1.36 { 9, PrivMode_MouseX10 },
4257 root 1.145 // 18, 19 printing-related
4258     { 25, PrivMode_VisibleCursor },
4259 pcg 1.1 #ifdef scrollBar_esc
4260 pcg 1.36 { scrollBar_esc, PrivMode_scrollBar },
4261 pcg 1.1 #endif
4262 pcg 1.73 { 35, PrivMode_ShiftKeys }, // rxvt extension
4263 pcg 1.36 { 40, PrivMode_132OK },
4264 pcg 1.73 // 41 xterm more fixes NYI
4265     // 45 margin bell NYI
4266     // 46 start logging
4267 pcg 1.36 { 47, PrivMode_Screen },
4268     { 66, PrivMode_aplKP },
4269 pcg 1.1 #ifndef NO_BACKSPACE_KEY
4270 pcg 1.36 { 67, PrivMode_BackSpace },
4271 pcg 1.1 #endif
4272 pcg 1.36 { 1000, PrivMode_MouseX11 },
4273 pcg 1.73 // 1001 Use Hilite Mouse Tracking. NYI, TODO
4274     // 1002 Use Cell Motion Mouse Tracking. NYI, TODO
4275     // 1003 Use All Motion Mouse Tracking. NYI, TODO
4276     { 1010, PrivMode_TtyOutputInh }, // rxvt extension
4277     { 1011, PrivMode_Keypress }, // rxvt extension
4278     // 1035 enable modifiers for alt, numlock NYI
4279     // 1036 send ESC for meta keys NYI
4280     // 1037 send DEL for keypad delete NYI
4281 pcg 1.36 { 1047, PrivMode_Screen },
4282 pcg 1.73 // 1048 save and restore cursor
4283 pcg 1.90 { 1049, PrivMode_Screen }, /* xterm extension, clear screen on ti rather than te */
4284 pcg 1.73 // 1051, 1052, 1060, 1061 keyboard emulation NYI
4285 pcg 1.36 };
4286    
4287     if (nargs == 0)
4288     return;
4289    
4290     /* make lo/hi boolean */
4291     if (mode == 'l')
4292     mode = 0; /* reset */
4293     else if (mode == 'h')
4294     mode = 1; /* set */
4295    
4296     for (i = 0; i < nargs; i++)
4297     {
4298     state = -1;
4299    
4300     /* basic handling */
4301 pcg 1.43 for (j = 0; j < (sizeof (argtopriv)/sizeof (argtopriv[0])); j++)
4302 pcg 1.36 if (argtopriv[j].argval == arg[i])
4303     {
4304     state = privcases (mode, argtopriv[j].bit);
4305     break;
4306     }
4307 pcg 1.1
4308 pcg 1.36 /* extra handling for values with state unkept */
4309 pcg 1.73 switch (arg[i])
4310     {
4311 root 1.220 #if ENABLE_STYLES
4312     case 1021:
4313 root 1.249 set_option (Opt_intensityStyles, mode);
4314 root 1.222
4315 root 1.225 scr_touch (true);
4316 root 1.222 break;
4317 root 1.220 #endif
4318 pcg 1.73 case 1048: /* alternative cursor save */
4319 root 1.163 case 1049:
4320 root 1.321 if (option (Opt_secondaryScreen))
4321 pcg 1.90 if (mode == 0)
4322     scr_cursor (RESTORE);
4323     else if (mode == 1)
4324     scr_cursor (SAVE);
4325     break;
4326 pcg 1.73 }
4327    
4328     if (state >= 0)
4329     /* extra handling for values with valid 0 or 1 state */
4330 pcg 1.36 switch (arg[i])
4331     {
4332 pcg 1.73 /* case 1: - application cursor keys */
4333     case 2: /* VT52 mode */
4334     /* oddball mode. should be set regardless of set/reset
4335     * parameter. Return from VT52 mode with an ESC < from
4336     * within VT52 mode
4337     */
4338     PrivMode (1, PrivMode_vt52);
4339     break;
4340     case 3: /* 80/132 */
4341 root 1.145 if (priv_modes & PrivMode_132OK)
4342 root 1.208 set_widthheight (((state ? 132 : 80) * fwidth), height);
4343 pcg 1.73 break;
4344     case 4: /* smooth scrolling */
4345 root 1.249 set_option (Opt_jumpScroll, !state);
4346 pcg 1.73 break;
4347     case 5: /* reverse video */
4348     scr_rvideo_mode (state);
4349     break;
4350     case 6: /* relative/absolute origins */
4351     scr_relative_origin (state);
4352     break;
4353     case 7: /* autowrap */
4354     scr_autowrap (state);
4355     break;
4356 pcg 1.90 /* case 8: - auto repeat, can't do on a per window basis */
4357 pcg 1.73 case 9: /* X10 mouse reporting */
4358     if (state) /* orthogonal */
4359 root 1.145 priv_modes &= ~PrivMode_MouseX11;
4360 pcg 1.73 break;
4361 pcg 1.1 #ifdef scrollBar_esc
4362 pcg 1.73 case scrollBar_esc:
4363     if (scrollbar_mapping (state))
4364     {
4365     resize_all_windows (0, 0, 0);
4366     scr_touch (true);
4367     }
4368     break;
4369 pcg 1.1 #endif
4370 pcg 1.73 case 25: /* visible/invisible cursor */
4371     scr_cursor_visible (state);
4372     break;
4373 pcg 1.90 /* case 35: - shift keys */
4374     /* case 40: - 80 <--> 132 mode */
4375 pcg 1.73 case 47: /* secondary screen */
4376     scr_change_screen (state);
4377     break;
4378 pcg 1.90 /* case 66: - application key pad */
4379     /* case 67: - backspace key */
4380 pcg 1.73 case 1000: /* X11 mouse reporting */
4381     if (state) /* orthogonal */
4382 root 1.145 priv_modes &= ~PrivMode_MouseX10;
4383 pcg 1.73 break;
4384 pcg 1.1 #if 0
4385 pcg 1.73 case 1001:
4386     break; /* X11 mouse highlighting */
4387 pcg 1.1 #endif
4388 pcg 1.73 case 1010: /* scroll to bottom on TTY output inhibit */
4389 root 1.249 set_option (Opt_scrollTtyOutput, !state);
4390 pcg 1.73 break;
4391     case 1011: /* scroll to bottom on key press */
4392 root 1.249 set_option (Opt_scrollTtyKeypress, state);
4393 pcg 1.73 break;
4394 pcg 1.90 case 1047: /* secondary screen w/ clearing last */
4395 root 1.321 if (option (Opt_secondaryScreen))
4396 pcg 1.90 if (current_screen != PRIMARY)
4397     scr_erase_screen (2);
4398     scr_change_screen (state);
4399     break;
4400     case 1049: /* secondary screen w/ clearing first */
4401 pcg 1.73 scr_change_screen (state);
4402 root 1.321 if (option (Opt_secondaryScreen))
4403 pcg 1.90 if (current_screen != PRIMARY)
4404     scr_erase_screen (2);
4405     break;
4406 pcg 1.73 default:
4407     break;
4408     }
4409 pcg 1.1 }
4410     }
4411     /*}}} */
4412    
4413     /*{{{ process sgr sequences */
4414     void
4415 pcg 1.34 rxvt_term::process_sgr_mode (unsigned int nargs, const int *arg)
4416 pcg 1.1 {
4417 pcg 1.81 unsigned int i;
4418     short rendset;
4419     int rendstyle;
4420 pcg 1.36
4421     if (nargs == 0)
4422     {
4423     scr_rendition (0, ~RS_None);
4424     return;
4425     }
4426 pcg 1.81
4427 pcg 1.36 for (i = 0; i < nargs; i++)
4428     {
4429     rendset = -1;
4430     switch (arg[i])
4431     {
4432     case 0:
4433     rendset = 0, rendstyle = ~RS_None;
4434     break;
4435     case 1:
4436     rendset = 1, rendstyle = RS_Bold;
4437     break;
4438 root 1.163 //case 2: // low intensity
4439     case 3:
4440     rendset = 1, rendstyle = RS_Italic;
4441     break;
4442 pcg 1.36 case 4:
4443     rendset = 1, rendstyle = RS_Uline;
4444     break;
4445 root 1.107 case 5: // slowly blinking
4446     case 6: // rapidly blinking
4447 pcg 1.36 rendset = 1, rendstyle = RS_Blink;
4448     break;
4449 pcg 1.93 //case 6: // scoansi light background
4450 pcg 1.36 case 7:
4451     rendset = 1, rendstyle = RS_RVid;
4452     break;
4453 pcg 1.73 case 8:
4454     // invisible. NYI
4455     break;
4456 root 1.107 //case 9: // crossed out
4457     //case 10: // scoansi acs off, primary font
4458     //case 11: // scoansi acs on, first alt font
4459     //case 12: // scoansi acs on, |0x80, second alt font
4460     //...
4461     //case 19: // ninth alt font
4462     //case 20: // gothic
4463 root 1.163 case 21: // disable bold, faint, sometimes doubly underlined (iso 8613)
4464 root 1.107 rendset = 0, rendstyle = RS_Bold;
4465 pcg 1.93 break;
4466 root 1.163 case 22: // normal intensity
4467 pcg 1.36 rendset = 0, rendstyle = RS_Bold;
4468     break;
4469 root 1.163 case 23: // disable italic
4470     rendset = 0, rendstyle = RS_Italic;
4471     break;
4472 pcg 1.36 case 24:
4473     rendset = 0, rendstyle = RS_Uline;
4474     break;
4475     case 25:
4476     rendset = 0, rendstyle = RS_Blink;
4477     break;
4478 root 1.163 case 26: // variable spacing (iso 8613)
4479 root 1.145 rendset = 0, rendstyle = RS_Blink;
4480     break;
4481 pcg 1.36 case 27:
4482     rendset = 0, rendstyle = RS_RVid;
4483     break;
4484 root 1.107 //case 28: // visible. NYI
4485     //case 29: // not crossed-out
4486 pcg 1.36 }
4487 pcg 1.73
4488 pcg 1.36 if (rendset != -1)
4489     {
4490     scr_rendition (rendset, rendstyle);
4491 pcg 1.43 continue; /* for (;i;) */
4492 pcg 1.36 }
4493    
4494     switch (arg[i])
4495     {
4496     case 30:
4497     case 31: /* set fg color */
4498     case 32:
4499     case 33:
4500     case 34:
4501     case 35:
4502     case 36:
4503     case 37:
4504 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 30)), Color_fg);
4505 pcg 1.36 break;
4506 root 1.163 case 38: // set fg color, ISO 8613-6
4507 pcg 1.36 if (nargs > i + 2 && arg[i + 1] == 5)
4508     {
4509 pcg 1.73 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_fg);
4510 pcg 1.36 i += 2;
4511     }
4512     break;
4513     case 39: /* default fg */
4514     scr_color (Color_fg, Color_fg);
4515     break;
4516    
4517     case 40:
4518     case 41: /* set bg color */
4519     case 42:
4520     case 43:
4521     case 44:
4522     case 45:
4523     case 46:
4524     case 47:
4525 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 40)), Color_bg);
4526 pcg 1.36 break;
4527 root 1.163 case 48: // set bg color, ISO 8613-6
4528 pcg 1.36 if (nargs > i + 2 && arg[i + 1] == 5)
4529     {
4530 pcg 1.73 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_bg);
4531 pcg 1.36 i += 2;
4532     }
4533     break;
4534     case 49: /* default bg */
4535     scr_color (Color_bg, Color_bg);
4536     break;
4537 pcg 1.1
4538 root 1.163 //case 50: // not variable spacing
4539    
4540 root 1.294 #if !ENABLE_MINIMAL
4541 pcg 1.36 case 90:
4542     case 91: /* set bright fg color */
4543     case 92:
4544     case 93:
4545     case 94:
4546     case 95:
4547     case 96:
4548     case 97:
4549 root 1.163 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 90)), Color_fg);
4550 pcg 1.36 break;
4551     case 100:
4552     case 101: /* set bright bg color */
4553     case 102:
4554     case 103:
4555     case 104:
4556     case 105:
4557     case 106:
4558     case 107:
4559 root 1.163 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 100)), Color_bg);
4560 pcg 1.36 break;
4561 pcg 1.1 #endif
4562 pcg 1.36 }
4563 pcg 1.1 }
4564     }
4565     /*}}} */
4566    
4567 pcg 1.93 /*{{{ (do not) process Rob Nation's own graphics mode sequences */
4568 pcg 1.1 void
4569 pcg 1.34 rxvt_term::process_graphics ()
4570 pcg 1.1 {
4571 pcg 1.81 unicode_t ch, cmd = cmd_getc ();
4572 pcg 1.1
4573 pcg 1.36 if (cmd == 'Q')
4574     { /* query graphics */
4575 root 1.145 tt_printf ("\033G0\012"); /* no graphics */
4576 pcg 1.36 return;
4577     }
4578     /* swallow other graphics sequences until terminating ':' */
4579     do
4580     ch = cmd_getc ();
4581     while (ch != ':');
4582 pcg 1.1 }
4583     /*}}} */
4584    
4585     /* ------------------------------------------------------------------------- */
4586    
4587     /*
4588 pcg 1.43 * Send printf () formatted output to the command.
4589 pcg 1.1 * Only use for small amounts of data.
4590     */
4591     void
4592 pcg 1.10 rxvt_term::tt_printf (const char *fmt,...)
4593 pcg 1.1 {
4594 pcg 1.10 va_list arg_ptr;
4595 root 1.234 char buf[256];
4596 pcg 1.1
4597 pcg 1.10 va_start (arg_ptr, fmt);
4598     vsnprintf ((char *)buf, 256, fmt, arg_ptr);
4599     va_end (arg_ptr);
4600 root 1.145 tt_write (buf, strlen (buf));
4601 pcg 1.1 }
4602    
4603     /* ---------------------------------------------------------------------- */
4604 pcg 1.10 /* Write data to the pty as typed by the user, pasted with the mouse,
4605 pcg 1.1 * or generated by us in response to a query ESC sequence.
4606     */
4607 root 1.177 const unsigned int MAX_PTY_WRITE = 255; // minimum MAX_INPUT
4608    
4609 pcg 1.1 void
4610 root 1.234 rxvt_term::tt_write (const char *data, unsigned int len)
4611 pcg 1.1 {
4612 root 1.253 if (HOOK_INVOKE ((this, HOOK_TT_WRITE, DT_STR_LEN, data, len, DT_END)))
4613     return;
4614    
4615 root 1.269 if (pty->pty < 0)
4616 root 1.239 return;
4617    
4618 root 1.177 if (v_buflen == 0)
4619     {
4620 root 1.269 ssize_t written = write (pty->pty, data, min (len, MAX_PTY_WRITE));
4621 pcg 1.10
4622 root 1.177 if ((unsigned int)written == len)
4623     return;
4624 pcg 1.34
4625 root 1.177 data += written;
4626     len -= written;
4627     }
4628 pcg 1.10
4629 root 1.234 v_buffer = (char *)realloc (v_buffer, v_buflen + len);
4630 pcg 1.10
4631 root 1.177 memcpy (v_buffer + v_buflen, data, len);
4632     v_buflen += len;
4633 pcg 1.10
4634 root 1.177 pty_ev.set (EVENT_READ | EVENT_WRITE);
4635     }
4636 pcg 1.10
4637 root 1.177 void rxvt_term::pty_write ()
4638     {
4639 root 1.269 int written = write (pty->pty, v_buffer, min (v_buflen, MAX_PTY_WRITE));
4640 pcg 1.1
4641 root 1.177 if (written > 0)
4642 pcg 1.10 {
4643 root 1.177 v_buflen -= written;
4644 pcg 1.10
4645 root 1.177 if (v_buflen == 0)
4646 pcg 1.10 {
4647 root 1.177 free (v_buffer);
4648     v_buffer = 0;
4649     v_buflen = 0;
4650 pcg 1.10
4651 root 1.177 pty_ev.set (EVENT_READ);
4652 pcg 1.10 return;
4653     }
4654 root 1.177
4655     memmove (v_buffer, v_buffer + written, v_buflen);
4656 pcg 1.1 }
4657 root 1.177 else if (written != -1 || (errno != EAGAIN && errno != EINTR))
4658 root 1.213 pty_ev.set (EVENT_READ);
4659 pcg 1.1 }
4660 pcg 1.10
4661 pcg 1.1 /*----------------------- end-of-file (C source) -----------------------*/
4662