ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.570
Committed: Tue Jun 21 12:03:56 2016 UTC (7 years, 10 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.569: +43 -0 lines
Log Message:
24-bit direct color support (patch by Fengguang Wu)

Support directly setting RGB fg/bg colors via ISO-8613-3 24-bit
ANSI color escapes:

  ESC[38;2;<r>;<g>;<b>m Select RGB foreground color
  ESC[48;2;<r>;<g>;<b>m Select RGB background color

The killer applications for me are vim in tmux. It'll not only modernize
their look and feeling, but also bring more eye friendly color schemes.
Very helpful for long time programmers.

To avoid memory overheads and keep the patch non-intrusive, it takes the
approach to adapt the nearest color in an hidden 6x6x4 (88-color mode)
or 7x7x5 (256-color mode) color cube to the new 24-bit RGB color.

The pros/cons are:

+) least memory footprint (close to 0)
   comparing to konsole, gnome-terminal etc. real 24-bit arrays

+) exact colors and excellent user feelings
   comparing to xterm, mlterm, etc. approximating to 256 palette

+) usable in both the existing 88/256-color modes

   Most vim GUI color schemes show up the same as gvim in rxvt-unicode's
   88-color mode, not to mention the 256-color mode. Typical applications
   only use one or two dozens of colors at the same time.

-) may not be able to show 2+ close 24-bit colors

   RGB colors close to each other will likely fall into the same slot in
   the 6x6x4 or 7x7x5 color cube. If necessary, it could be improved
   effectively by implementing some collision avoidance logic, trying to
   find empty/eldest slot in the +1/-1 r/g/b indices (ie. 3-8 neighbors).

The CPU overheads of map_rgb24_color() look ignorable: I feel no
perceptible slow down when doing vim operations in 24-bit color mode.

A micro benchmark running a test script from [1]:

% time (for i in {1..100}; do 24-bit-color.sh; done)

vanilla rxvt-unicode
====================
  2.42s user 1.88s system 31% cpu 13.555 total
  2.59s user 1.74s system 31% cpu 13.615 total
  2.46s user 1.85s system 31% cpu 13.631 total

THIS PATCH (adapt hidden color cube to 24-bit)
==============================================
  2.33s user 1.97s system 31% cpu 13.598 total
  2.46s user 1.89s system 31% cpu 13.613 total
  2.51s user 1.82s system 31% cpu 13.556 total

https://github.com/spudowiar/rxvt-unicode (real 24-bit array)
=============================================================
  2.61s user 1.75s system 31% cpu 13.721 total
  2.48s user 1.82s system 31% cpu 13.566 total
  2.60s user 1.76s system 31% cpu 13.631 total

USE_256_COLORS is defined in all the above rxvt-unicode builds.

References:

[1] True Colour (16 million colours) support in various terminal
    applications and terminals
    https://gist.github.com/XVilka/8346728

[2] https://en.wikipedia.org/wiki/ANSI_escape_code#Colors

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 root 1.526 * - extensive modifications
10 pcg 1.1 * 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 root 1.526 * - extensive modifications
26 pcg 1.1 * 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.542 * Copyright (c) 2003-2014 Marc Lehmann <schmorp@schmorp.de>
31 sf-exg 1.568 * Copyright (c) 2007,2015 Emanuele Giaquinta <e.giaquinta@glauco.it>
32 pcg 1.1 *
33     * This program is free software; you can redistribute it and/or modify
34     * it under the terms of the GNU General Public License as published by
35 root 1.550 * the Free Software Foundation; either version 3 of the License, or
36 pcg 1.1 * (at your option) any later version.
37     *
38     * This program is distributed in the hope that it will be useful,
39     * but WITHOUT ANY WARRANTY; without even the implied warranty of
40     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41     * GNU General Public License for more details.
42     *
43     * You should have received a copy of the GNU General Public License
44     * along with this program; if not, write to the Free Software
45     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
46     *----------------------------------------------------------------------*/
47    
48     /*{{{ includes: */
49 root 1.227 #include "../config.h"
50     #include "rxvt.h"
51     #include "rxvtperl.h"
52 pcg 1.1 #include "version.h"
53     #include "command.h"
54    
55 root 1.190 #ifdef KEYSYM_RESOURCE
56     # include "keyboard.h"
57     #endif
58    
59 sf-exg 1.505 #include <signal.h>
60 pcg 1.20
61 root 1.303 #if LINUX_YIELD_HACK
62 sf-exg 1.505 # include <time.h>
63 root 1.303 #endif
64    
65 pcg 1.1 /*----------------------------------------------------------------------*/
66    
67 pcg 1.81 #define IS_CONTROL(ch) !((ch) & 0xffffff60UL)
68    
69 root 1.145 #if ENABLE_FRILLS || ISO_14755
70 root 1.131
71 root 1.145 #define ISO_14755_STARTED 0x80000000UL
72     #define ISO_14755_51 0x40000000UL // basic (section 5.1)
73     #define ISO_14755_52 0x20000000UL // keycap (section 5.2)
74     #define ISO_14755_54 0x10000000UL // code feedback (section 5.4)
75     #define ISO_14755_MASK 0x0fffffffUL
76 root 1.131
77 root 1.145 #if ISO_14755
78 root 1.131 static unsigned short iso14755_symtab[] = {
79     // keysym, unicode
80     XK_Left, 0x2190,
81     XK_KP_Left, 0x2190,
82     XK_Up, 0x2191,
83     XK_KP_Up, 0x2191,
84     XK_Right, 0x2192,
85     XK_KP_Right, 0x2192,
86     XK_Down, 0x2193,
87     XK_KP_Down, 0x2193,
88     XK_Linefeed, 0x21b4,
89     XK_Return, 0x21b5,
90     XK_KP_Enter, 0x21b5,
91    
92     XK_Prior, 0x21de,
93     XK_Next, 0x21df,
94     XK_Tab, 0x21e5,
95     XK_ISO_Left_Tab, 0x21e6,
96     XK_Shift_L, 0x21e7,
97     XK_Shift_R, 0x21e7,
98    
99     XK_Shift_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 root 1.512 void ecb_cold
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.517 iso14755_51 (l.t[x], l.r[x], x, y, view_start);
155 root 1.145 iso14755buf = ISO_14755_54;
156     break;
157     }
158    
159     x--;
160     }
161     }
162    
163 root 1.512 void ecb_cold
164 root 1.517 rxvt_term::iso14755_51 (unicode_t ch, rend_t r, int x, int y, int y2)
165 root 1.145 {
166 root 1.163 rxvt_fontset *fs = FONTSET (r);
167 sf-exg 1.439 wchar_t *chr, *alloc, ch2, **fname;
168 root 1.145 int len;
169    
170 root 1.217 # if ENABLE_COMBINING
171 root 1.145 if (IS_COMPOSE (ch))
172     {
173     len = rxvt_composite.expand (ch, 0);
174     alloc = chr = new wchar_t[len];
175     rxvt_composite.expand (ch, chr);
176     }
177     else
178 root 1.217 # endif
179 root 1.145 {
180 root 1.163 ch2 = ch;
181    
182 root 1.145 alloc = 0;
183 root 1.163 chr = &ch2;
184 root 1.145 len = 1;
185     }
186    
187 root 1.517 char rowcol[40];
188     snprintf (rowcol, sizeof rowcol, "col %d row %d @%d", x, y, y2);
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 sf-exg 1.439 int width = 0;
203     fname = rxvt_temp_buf<wchar_t *> (len);
204     for (int i = 0; i < len; i++)
205     {
206 sf-exg 1.444 rxvt_font *f = (*fs)[fs->find_font_idx (chr[i])];
207 sf-exg 1.439 fname[i] = rxvt_utf8towcs (f->name);
208     max_it (width, wcswidth (fname[i], wcslen (fname[i])));
209     }
210 root 1.163
211 root 1.216 max_it (width, strlen (attr));
212    
213 root 1.217 if (y >= 0)
214     {
215 root 1.558 y = (y >= nrow - len - 5 && x < width + 2) ? 0 : -1;
216 root 1.217 x = 0;
217     }
218    
219 root 1.517 scr_overlay_new (x, y, width, len * 2 + 2);
220    
221     scr_overlay_set (0, 0, rowcol);
222 root 1.163
223     r = SET_STYLE (OVERLAY_RSTYLE, GET_STYLE (r));
224 root 1.145
225     for (int y = 0; y < len; y++)
226     {
227     char buf[9];
228    
229     ch = *chr++;
230    
231     sprintf (buf, "%8x", ch);
232 root 1.517 scr_overlay_set (0, y + 1, buf);
233     scr_overlay_set (9, y + 1, '=');
234 ayin 1.386 # if !UNICODE_3
235 root 1.145 if (ch >= 0x10000)
236     ch = 0xfffd;
237 root 1.217 # endif
238 root 1.517 scr_overlay_set (11, y + 1, ch, r);
239 root 1.293
240     if (WCWIDTH (ch) >= 2)
241 root 1.517 scr_overlay_set (12, y + 1, NOCHAR, r);
242 root 1.145 }
243    
244 root 1.293 // {
245     // char buf[4+4+3+1];
246     // snprintf (buf, sizeof (buf), "(%.4d|%.4d)", x, y);
247     // scr_overlay_set (0, 0, buf);
248     // }
249 root 1.517 scr_overlay_set (0, len + 1, attr);
250 sf-exg 1.439 for (int i = 0; i < len; i++)
251     {
252 root 1.517 scr_overlay_set (0, len + 2 + i, fname[i]);
253 sf-exg 1.439 free (fname[i]);
254     }
255 root 1.163
256 root 1.217 # if ENABLE_COMBINING
257 root 1.145 if (alloc)
258     delete [] alloc;
259 root 1.217 # endif
260 root 1.220 }
261 root 1.145 #endif
262    
263 root 1.512 void ecb_cold
264 root 1.131 rxvt_term::commit_iso14755 ()
265     {
266 sf-exg 1.486 wchar_t ch = iso14755buf & ISO_14755_MASK;
267 root 1.131
268 root 1.145 if (iso14755buf & ISO_14755_51)
269 root 1.131 {
270 sf-exg 1.486 char mb[MB_LEN_MAX];
271 root 1.131 int len;
272    
273     // allow verbatim 0-bytes and control-bytes to be entered
274 sf-exg 1.486 if (ch >= 0x20)
275     len = wctomb (mb, ch);
276 root 1.131 else
277     {
278 sf-exg 1.486 mb[0] = ch;
279 root 1.131 len = 1;
280     }
281    
282     if (len > 0)
283 root 1.234 tt_write (mb, len);
284 root 1.131 else
285     scr_bell ();
286     }
287    
288     iso14755buf = 0;
289     }
290    
291 root 1.512 static int ecb_cold
292 ayin 1.407 hex_keyval (XKeyEvent &ev)
293 root 1.131 {
294 sf-exg 1.442 // check whether this event corresponds to a hex digit
295 root 1.131 // if the modifiers had not been pressed.
296     for (int index = 0; index < 8; index++)
297     {
298     KeySym k = XLookupKeysym (&ev, index);
299    
300     if (k >= XK_KP_0 && k <= XK_KP_9) return k - XK_KP_0;
301     else if (k >= XK_0 && k <= XK_9) return k - XK_0;
302     else if (k >= XK_a && k <= XK_f) return k - XK_a + 10;
303     else if (k >= XK_A && k <= XK_F) return k - XK_A + 10;
304     }
305    
306     return -1;
307     }
308     #endif
309    
310 root 1.512 static inline KeySym ecb_cold
311 ayin 1.408 translate_keypad (KeySym keysym, bool kp)
312     {
313     #ifdef XK_KP_Home
314     static const KeySym keypadtrans[] = {
315     XK_KP_7, // XK_KP_Home
316     XK_KP_4, // XK_KP_Left
317     XK_KP_8, // XK_KP_Up
318     XK_KP_6, // XK_KP_Right
319     XK_KP_2, // XK_KP_Down
320     XK_KP_9, // XK_KP_Prior
321     XK_KP_3, // XK_KP_Next
322     XK_KP_1, // XK_KP_End
323     XK_KP_5, // XK_KP_Begin
324     };
325    
326     if (IN_RANGE_INC (keysym, XK_KP_Home, XK_KP_Begin))
327     {
328     unsigned int index = keysym - XK_KP_Home;
329     keysym = kp ? keypadtrans[index] : XK_Home + index;
330     }
331     else if (keysym == XK_KP_Insert)
332     keysym = kp ? XK_KP_0 : XK_Insert;
333     # ifndef NO_DELETE_KEY
334     else if (keysym == XK_KP_Delete)
335     keysym = kp ? XK_KP_Decimal : XK_Delete;
336     # endif
337     #endif
338     return keysym;
339     }
340    
341 root 1.512 static inline int ecb_cold
342 ayin 1.409 map_function_key (KeySym keysym)
343     {
344     int param = 0;
345    
346     if (IN_RANGE_INC (keysym, XK_F1, XK_F35))
347     {
348     param = 11 + keysym - XK_F1;
349     if (keysym >= XK_F17)
350     param += 4;
351     else if (keysym >= XK_F15)
352     param += 3;
353     else if (keysym >= XK_F11)
354     param += 2;
355     else if (keysym >= XK_F6)
356     param += 1;
357     }
358     else
359     switch (keysym)
360     {
361     case XK_Find:
362     param = 1;
363     break;
364     case XK_Insert:
365     param = 2;
366     break;
367     #ifdef DXK_Remove
368     case DXK_Remove:
369     #endif
370     case XK_Execute:
371     param = 3;
372     break;
373     case XK_Select:
374     param = 4;
375     break;
376     case XK_Prior:
377     param = 5;
378     break;
379     case XK_Next:
380     param = 6;
381     break;
382 ayin 1.410 case XK_Home:
383     param = 7;
384     break;
385     case XK_End:
386     param = 8;
387     break;
388 ayin 1.409 case XK_Help:
389     param = 28;
390     break;
391     case XK_Menu:
392     param = 29;
393     break;
394     }
395     return param;
396     }
397    
398 sf-exg 1.543 static inline wchar_t *
399     rxvt_wcsdup (const wchar_t *str, int len)
400     {
401     wchar_t *r = (wchar_t *)rxvt_malloc ((len + 1) * sizeof (wchar_t));
402     memcpy (r, str, len * sizeof (wchar_t));
403     r[len] = 0;
404     return r;
405     }
406    
407 root 1.512 void ecb_cold
408 root 1.306 rxvt_term::key_press (XKeyEvent &ev)
409 pcg 1.1 {
410 pcg 1.49 int ctrl, meta, shft, len;
411 sf-exg 1.552 KeySym keysym = NoSymbol;
412 sf-exg 1.546 char rkbuf[KBUFSZ + 1];
413 sf-exg 1.544 char *kbuf = rkbuf + 1;
414 pcg 1.1
415 root 1.306 #if ISO_14755
416     if (iso14755buf & ISO_14755_52)
417     return;
418     #endif
419    
420 pcg 1.36 /*
421     * use Num_Lock to toggle Keypad on/off. If Num_Lock is off, allow an
422     * escape sequence to toggle the Keypad.
423     *
424     * Always permit `shift' to override the current setting
425     */
426 root 1.195 shft = ev.state & ShiftMask;
427     ctrl = ev.state & ControlMask;
428     meta = ev.state & ModMetaMask;
429 pcg 1.14
430 pcg 1.36 kbuf[0] = 0;
431 pcg 1.14
432 root 1.514 #if USE_XIM
433 pcg 1.36 if (Input_Context)
434     {
435     Status status_return;
436 pcg 1.1
437 pcg 1.81 #if 0
438 pcg 1.1 #ifdef X_HAVE_UTF8_STRING
439 pcg 1.48 if (enc_utf8 && 0) // currently disabled, doesn't seem to work, nor is useful
440 root 1.234 len = Xutf8LookupString (Input_Context, &ev, kbuf,
441 pcg 1.36 KBUFSZ, &keysym, &status_return);
442     else
443 pcg 1.20 #endif
444 pcg 1.81 #endif
445 pcg 1.36 {
446     wchar_t wkbuf[KBUFSZ + 1];
447    
448     // the XOpenIM manpage lies about hardcoding the locale
449     // at the point of XOpenIM, so temporarily switch locales
450     if (rs[Rs_imLocale])
451     SET_LOCALE (rs[Rs_imLocale]);
452 root 1.202
453 pcg 1.36 // assume wchar_t == unicode or better
454 pcg 1.38 len = XwcLookupString (Input_Context, &ev, wkbuf,
455 pcg 1.36 KBUFSZ, &keysym, &status_return);
456 root 1.202
457 pcg 1.36 if (rs[Rs_imLocale])
458     SET_LOCALE (locale);
459 pcg 1.17
460 pcg 1.36 if (status_return == XLookupChars
461 pcg 1.49 || status_return == XLookupBoth)
462 pcg 1.36 {
463 pcg 1.55 /* make sure the user can type ctrl-@, i.e. NUL */
464     if (len == 1 && *wkbuf == 0)
465     {
466     kbuf[0] = 0;
467     len = 1;
468     }
469     else
470     {
471     wkbuf[len] = 0;
472     len = wcstombs ((char *)kbuf, wkbuf, KBUFSZ);
473     if (len < 0)
474     len = 0;
475     }
476 pcg 1.36 }
477     else
478     len = 0;
479     }
480     }
481     else
482 pcg 1.14 #endif
483 pcg 1.36 {
484 root 1.234 len = XLookupString (&ev, kbuf, KBUFSZ, &keysym, &compose);
485 pcg 1.36 }
486    
487 sf-exg 1.552 if (keysym != NoSymbol)
488 pcg 1.36 {
489 sf-exg 1.551 KeySym orig_keysym = keysym;
490    
491     /* Shift + F1 - F10 generates F11 - F20 */
492     if (shft && keysym >= XK_F1 && keysym <= XK_F10)
493     {
494     keysym += (XK_F11 - XK_F1);
495     shft = 0; /* turn off Shift */
496     }
497    
498 pcg 1.36 if (keysym >= 0xFF00 && keysym <= 0xFFFF)
499     {
500 ayin 1.411 bool kp = priv_modes & PrivMode_aplKP ? !shft : shft;
501     unsigned int newlen = 1;
502 ayin 1.364
503 sf-exg 1.445 if (ev.state & ModNumLockMask)
504     kp = false;
505 root 1.446
506     keysym = translate_keypad (keysym, kp);
507    
508     switch (keysym)
509 ayin 1.411 {
510 pcg 1.1 #ifndef NO_BACKSPACE_KEY
511 ayin 1.411 case XK_BackSpace:
512     if (priv_modes & PrivMode_HaveBackSpace)
513     {
514     kbuf[0] = (!! (priv_modes & PrivMode_BackSpace)
515     ^ !!ctrl) ? '\b' : '\177';
516     kbuf[1] = '\0';
517     }
518     else
519     strcpy (kbuf, rs[Rs_backspace_key]);
520     break;
521 pcg 1.1 #endif
522     #ifndef NO_DELETE_KEY
523 ayin 1.411 case XK_Delete:
524     strcpy (kbuf, rs[Rs_delete_key]);
525     break;
526 pcg 1.1 #endif
527 ayin 1.411 case XK_Tab:
528     if (shft)
529     strcpy (kbuf, "\033[Z");
530     else
531     {
532 pcg 1.1 #ifdef CTRL_TAB_MAKES_META
533 ayin 1.411 if (ctrl)
534     meta = 1;
535 pcg 1.1 #endif
536     #ifdef MOD4_TAB_MAKES_META
537 ayin 1.411 if (ev.state & Mod4Mask)
538     meta = 1;
539 pcg 1.1 #endif
540 ayin 1.411 newlen = 0;
541     }
542     break;
543    
544     case XK_Up: /* "\033[A" */
545     case XK_Down: /* "\033[B" */
546     case XK_Right: /* "\033[C" */
547     case XK_Left: /* "\033[D" */
548     strcpy (kbuf, "\033[Z");
549     kbuf[2] = "DACB"[keysym - XK_Left];
550     /* do Shift first */
551     if (shft)
552     kbuf[2] = "dacb"[keysym - XK_Left];
553     else if (ctrl)
554     {
555     kbuf[1] = 'O';
556     kbuf[2] = "dacb"[keysym - XK_Left];
557     }
558     else if (priv_modes & PrivMode_aplCUR)
559     kbuf[1] = 'O';
560     break;
561 pcg 1.1
562 ayin 1.411 case XK_KP_Enter:
563     /* allow shift to override */
564     if (kp)
565     {
566     strcpy (kbuf, "\033OM");
567 pcg 1.36 break;
568 ayin 1.411 }
569 pcg 1.1
570 ayin 1.411 /* FALLTHROUGH */
571 root 1.145
572 ayin 1.411 case XK_Return:
573     if (priv_modes & PrivMode_LFNL)
574     {
575     kbuf[0] = '\015';
576     kbuf[1] = '\012';
577     kbuf[2] = '\0';
578     }
579     else
580     {
581     kbuf[0] = '\015';
582     kbuf[1] = '\0';
583     }
584     break;
585 root 1.145
586 ayin 1.411 case XK_KP_F1: /* "\033OP" */
587     case XK_KP_F2: /* "\033OQ" */
588     case XK_KP_F3: /* "\033OR" */
589     case XK_KP_F4: /* "\033OS" */
590     strcpy (kbuf, "\033OP");
591     kbuf[2] += (keysym - XK_KP_F1);
592     break;
593 pcg 1.1
594 ayin 1.411 case XK_KP_Multiply: /* "\033Oj" : "*" */
595     case XK_KP_Add: /* "\033Ok" : "+" */
596     case XK_KP_Separator: /* "\033Ol" : "," */
597     case XK_KP_Subtract: /* "\033Om" : "-" */
598     case XK_KP_Decimal: /* "\033On" : "." */
599     case XK_KP_Divide: /* "\033Oo" : "/" */
600     case XK_KP_0: /* "\033Op" : "0" */
601     case XK_KP_1: /* "\033Oq" : "1" */
602     case XK_KP_2: /* "\033Or" : "2" */
603     case XK_KP_3: /* "\033Os" : "3" */
604     case XK_KP_4: /* "\033Ot" : "4" */
605     case XK_KP_5: /* "\033Ou" : "5" */
606     case XK_KP_6: /* "\033Ov" : "6" */
607     case XK_KP_7: /* "\033Ow" : "7" */
608     case XK_KP_8: /* "\033Ox" : "8" */
609     case XK_KP_9: /* "\033Oy" : "9" */
610     /* allow shift to override */
611     if (kp)
612     {
613     strcpy (kbuf, "\033Oj");
614     kbuf[2] += (keysym - XK_KP_Multiply);
615     }
616     else
617     {
618     kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
619     kbuf[1] = '\0';
620     }
621     break;
622 pcg 1.36
623 ayin 1.411 default:
624     {
625     int param = map_function_key (keysym);
626     if (param > 0)
627 sf-exg 1.455 sprintf (kbuf,"\033[%d~", param);
628 ayin 1.411 else
629     newlen = 0;
630 pcg 1.36 }
631 ayin 1.411 break;
632     }
633 root 1.183
634 ayin 1.411 if (newlen)
635     len = strlen (kbuf);
636 pcg 1.68
637 sf-exg 1.500 if (len > 0)
638     {
639     /*
640     * pass Shift/Control indicators for function keys ending with `~'
641     *
642     * eg,
643     * Prior = "ESC[5~"
644     * Shift+Prior = "ESC[5$"
645     * Ctrl+Prior = "ESC[5^"
646     * Ctrl+Shift+Prior = "ESC[5@"
647     */
648     if (kbuf[0] == C0_ESC && kbuf[1] == '[' && kbuf[len - 1] == '~')
649     kbuf[len - 1] = (shft ? (ctrl ? '@' : '$') : (ctrl ? '^' : '~'));
650 sf-exg 1.501
651     /*
652     * Pass meta for all function keys, if 'meta' option set
653     */
654     #ifdef META8_OPTION
655     if (meta && (meta_char == 0x80))
656     kbuf[len - 1] |= 0x80;
657     #endif
658 sf-exg 1.500 }
659    
660 pcg 1.36 }
661     else if (ctrl && keysym == XK_minus)
662     {
663     len = 1;
664     kbuf[0] = '\037'; /* Ctrl-Minus generates ^_ (31) */
665     }
666 root 1.183 else if (keysym == XK_ISO_Left_Tab)
667     {
668     strcpy (kbuf, "\033[Z");
669     len = 3;
670     }
671 pcg 1.36 else
672     {
673 pcg 1.1 #ifdef META8_OPTION
674 pcg 1.36 /* set 8-bit on */
675     if (meta && (meta_char == 0x80))
676     {
677 root 1.234 char *ch;
678 pcg 1.36
679     for (ch = kbuf; ch < kbuf + len; ch++)
680     *ch |= 0x80;
681     }
682 pcg 1.1 #endif
683 pcg 1.36 /* nil */ ;
684     }
685 sf-exg 1.551
686     keysym = orig_keysym;
687 pcg 1.36 }
688 pcg 1.1
689 sf-exg 1.544 /* escape prefix */
690     if (len && meta
691     #ifdef META8_OPTION
692     && meta_char == C0_ESC
693     #endif
694     )
695     {
696     *--kbuf = C0_ESC;
697     len++;
698     }
699    
700 sf-exg 1.547 if (HOOK_INVOKE ((this, HOOK_KEY_PRESS, DT_XEVENT, &ev, DT_INT, keysym, DT_STR_LEN, kbuf, len, DT_END)))
701     return;
702    
703 sf-exg 1.552 if (keysym != NoSymbol)
704 sf-exg 1.545 {
705     #ifdef KEYSYM_RESOURCE
706     if (keyboard->dispatch (this, keysym, ev.state, kbuf, len))
707     return;
708     #endif
709    
710     if (saveLines)
711     {
712     #ifdef UNSHIFTED_SCROLLKEYS
713     if (!ctrl && !meta)
714     #else
715     if (IS_SCROLL_MOD)
716     #endif
717     {
718     int lnsppg;
719    
720     #ifdef PAGING_CONTEXT_LINES
721     lnsppg = nrow - PAGING_CONTEXT_LINES;
722     #else
723     lnsppg = nrow * 4 / 5;
724     #endif
725     max_it (lnsppg, 1);
726    
727     if (keysym == XK_Prior)
728     {
729     scr_page (lnsppg);
730     return;
731     }
732     else if (keysym == XK_Next)
733     {
734     scr_page (-lnsppg);
735     return;
736     }
737     }
738     #ifdef SCROLL_ON_UPDOWN_KEYS
739     if (IS_SCROLL_MOD)
740     {
741     if (keysym == XK_Up)
742     {
743     scr_page (1);
744     return;
745     }
746     else if (keysym == XK_Down)
747     {
748     scr_page (-1);
749     return;
750     }
751     }
752     #endif
753     #ifdef SCROLL_ON_HOMEEND_KEYS
754     if (IS_SCROLL_MOD)
755     {
756     if (keysym == XK_Home)
757     {
758     scr_changeview (top_row);
759     return;
760     }
761     else if (keysym == XK_End)
762     {
763     scr_changeview (0);
764     return;
765     }
766     }
767     #endif
768     }
769    
770     if (shft)
771     {
772 sf-exg 1.551 if (!ctrl && !meta && (priv_modes & PrivMode_ShiftKeys))
773 sf-exg 1.545 {
774     switch (keysym)
775     {
776     /* normal XTerm key bindings */
777     case XK_Insert: /* Shift+Insert = paste mouse selection */
778     selection_request (ev.time);
779     return;
780     #if TODO
781     /* rxvt extras */
782     case XK_KP_Add: /* Shift+KP_Add = bigger font */
783     return;
784     case XK_KP_Subtract: /* Shift+KP_Subtract = smaller font */
785     return;
786     #endif
787     }
788     }
789     }
790    
791     if (ctrl && meta && (keysym == XK_c || keysym == XK_v))
792     {
793     if (keysym == XK_v)
794     selection_request (ev.time, Sel_Clipboard);
795     else if (selection.len > 0)
796     {
797     free (selection.clip_text);
798     selection.clip_text = rxvt_wcsdup (selection.text, selection.len);
799     selection.clip_len = selection.len;
800     selection_grab (CurrentTime, true);
801     }
802    
803     return;
804     }
805    
806     #if ENABLE_FRILLS || ISO_14755
807     // ISO 14755 support
808     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_51))
809     {
810     int hv;
811    
812     if (iso14755buf & ISO_14755_51
813     && (keysym == XK_space || keysym == XK_KP_Space
814     || keysym == XK_Return || keysym == XK_KP_Enter))
815     {
816     commit_iso14755 ();
817     iso14755buf = ISO_14755_51;
818     # if ISO_14755
819     iso14755_51 (0);
820     # endif
821     return;
822     }
823     else if (keysym == XK_BackSpace)
824     {
825     iso14755buf = ((iso14755buf & ISO_14755_MASK) >> 4) | ISO_14755_51;
826     # if ISO_14755
827     iso14755_51 (iso14755buf & ISO_14755_MASK);
828     # endif
829     return;
830     }
831     else if ((hv = hex_keyval (ev)) >= 0)
832     {
833     iso14755buf = ((iso14755buf << 4) & ISO_14755_MASK)
834     | hv | ISO_14755_51;
835     # if ISO_14755
836     iso14755_51 (iso14755buf & ISO_14755_MASK);
837     # endif
838     return;
839     }
840     else
841     {
842     # if ISO_14755
843     scr_overlay_off ();
844     # endif
845     iso14755buf = 0;
846     }
847     }
848     else if (option (Opt_iso14755) &&
849     ((ctrl && (keysym == XK_Shift_L || keysym == XK_Shift_R))
850     || (shft && (keysym == XK_Control_L || keysym == XK_Control_R))))
851     if (!(iso14755buf & ISO_14755_STARTED))
852     {
853     iso14755buf |= ISO_14755_STARTED;
854     # if ISO_14755
855     scr_overlay_new (0, -1, sizeof ("ISO 14755 mode") - 1, 1);
856     scr_overlay_set (0, 0, "ISO 14755 mode");
857     # endif
858     }
859     #endif
860    
861     #ifdef PRINTPIPE
862     if (keysym == XK_Print)
863     {
864     scr_printscreen (ctrl | shft);
865     return;
866     }
867     #endif
868     }
869    
870 pcg 1.36 if (len <= 0)
871     return; /* not mapped */
872 pcg 1.1
873 sf-exg 1.548 tt_write_user_input (kbuf, (unsigned int)len);
874 pcg 1.1 }
875 root 1.306
876 root 1.512 void ecb_cold
877 root 1.306 rxvt_term::key_release (XKeyEvent &ev)
878     {
879     #if (MOUSE_WHEEL && MOUSE_SLIP_WHEELING) || ISO_14755 || ENABLE_PERL
880     KeySym keysym;
881    
882     keysym = XLookupKeysym (&ev, ev.state & ShiftMask ? 1 : 0); // sorry, only shift supported :/
883     #endif
884    
885     #if ENABLE_FRILLS || ISO_14755
886     // ISO 14755 support
887     if (iso14755buf)
888     if (iso14755buf & ISO_14755_52)
889     {
890 ayin 1.337 # if ISO_14755
891 root 1.306 scr_overlay_off ();
892     # endif
893     # if ISO_14755
894     // iso14755 part 5.2 handling: release time
895     // first: controls
896     if ((ev.state & ControlMask)
897     && ((keysym >= 0x40 && keysym <= 0x5f)
898     || (keysym >= 0x61 && keysym <= 0x7f)))
899     {
900     iso14755buf = ISO_14755_51 | 0x2400 | (keysym & 0x1f);
901     commit_iso14755 ();
902    
903     return;
904     }
905    
906 sf-exg 1.463 for (unsigned short *i = iso14755_symtab; i[0]; i += 2)
907 root 1.306 if (i[0] == keysym)
908     {
909     iso14755buf = ISO_14755_51 | i[1];
910     commit_iso14755 ();
911    
912     return;
913     }
914    
915     scr_bell ();
916     # endif
917     iso14755buf = 0;
918    
919     return;
920     }
921     else if ((ev.state & (ShiftMask | ControlMask)) != (ShiftMask | ControlMask))
922     {
923 ayin 1.337 # if ISO_14755
924 root 1.306 scr_overlay_off ();
925     # endif
926     if (iso14755buf & ISO_14755_51)
927     commit_iso14755 ();
928     #if ISO_14755
929 ayin 1.325 else if (option (Opt_iso14755_52) && iso14755buf & ISO_14755_STARTED)
930 root 1.306 {
931     iso14755buf = ISO_14755_52; // iso14755 part 5.2: remember empty begin/end pair
932    
933     scr_overlay_new (0, -1, sizeof ("KEYCAP PICTURE INSERT MODE") - 1, 1);
934     scr_overlay_set (0, 0, "KEYCAP PICTURE INSERT MODE");
935     }
936     # endif
937     else
938     iso14755buf = 0;
939     }
940     #endif
941    
942     if (HOOK_INVOKE ((this, HOOK_KEY_RELEASE, DT_XEVENT, &ev, DT_INT, keysym, DT_END)))
943     return;
944    
945     #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
946     if (!(ev.state & ControlMask))
947     slip_wheel_ev.stop ();
948     else if (keysym == XK_Control_L || keysym == XK_Control_R)
949     mouse_slip_wheel_speed = 0;
950     #endif
951     }
952 pcg 1.1
953 pcg 1.3 void
954 pcg 1.11 rxvt_term::flush ()
955     {
956 root 1.168 flush_ev.stop ();
957 ayin 1.361
958 sf-exg 1.528 #ifdef HAVE_IMG
959 sf-exg 1.474 if (bg_flags & BG_NEEDS_REFRESH)
960 sasha 1.357 {
961 sf-exg 1.474 bg_flags &= ~BG_NEEDS_REFRESH;
962 sasha 1.357 scr_touch (false);
963     }
964     #endif
965 root 1.168
966 pcg 1.11 if (want_refresh)
967     {
968 root 1.237 if (SHOULD_INVOKE (HOOK_LINE_UPDATE))
969     {
970 root 1.262 int row = view_start;
971 root 1.250 int end_row = row + nrow;
972 root 1.237
973 root 1.262 while (row > top_row && ROW (row - 1).is_longer ())
974 root 1.237 --row;
975    
976 root 1.250 do
977 root 1.237 {
978     int start_row = row;
979     line_t *l;
980    
981     do
982     {
983 root 1.255 l = &ROW (row++);
984 root 1.237
985 root 1.255 if (!(l->f & LINE_FILTERED))
986 root 1.237 {
987     // line not filtered, mark it as filtered
988     l->f |= LINE_FILTERED;
989     while (l->is_longer ())
990     {
991 root 1.255 l = &ROW (row++);
992 root 1.237 l->f |= LINE_FILTERED;
993     }
994    
995     // and filter it
996     HOOK_INVOKE ((this, HOOK_LINE_UPDATE, DT_INT, start_row, DT_END));
997    
998     break;
999     }
1000     }
1001 root 1.250 while (l->is_longer () && row < end_row);
1002 root 1.237 }
1003 root 1.255 while (row < end_row);
1004 root 1.237 }
1005    
1006 root 1.268 scr_refresh ();
1007 ayin 1.414 scrollBar.show (1);
1008 root 1.514 #if USE_XIM
1009 sf-exg 1.489 im_send_spot ();
1010 pcg 1.11 #endif
1011     }
1012    
1013 pcg 1.42 display->flush ();
1014 pcg 1.11 }
1015    
1016 sf-exg 1.443 /* checks whether a refresh is requested and starts the refresh timer */
1017 pcg 1.11 void
1018 root 1.381 rxvt_term::refresh_check ()
1019 pcg 1.11 {
1020 root 1.376 if (want_refresh && !flush_ev.is_active ())
1021 root 1.374 flush_ev.start (1. / 60.); // refresh at max. 60 Hz normally
1022 root 1.382
1023     display->flush ();
1024 root 1.116 }
1025    
1026     void
1027 root 1.363 rxvt_term::flush_cb (ev::timer &w, int revents)
1028 root 1.116 {
1029 root 1.264 make_current ();
1030 root 1.116
1031     refresh_count = 0;
1032 pcg 1.11 flush ();
1033     }
1034    
1035 pcg 1.27 #ifdef CURSOR_BLINK
1036 pcg 1.3 void
1037 sf-exg 1.506 rxvt_term::cursor_blink_reset ()
1038     {
1039 sf-exg 1.564 if (!focus)
1040     return;
1041    
1042 sf-exg 1.507 if (hidden_cursor)
1043     {
1044     hidden_cursor = 0;
1045     want_refresh = 1;
1046     }
1047 sf-exg 1.506
1048 sf-exg 1.561 if (option (Opt_cursorBlink) || (priv_modes & PrivMode_BlinkingCursor))
1049 sf-exg 1.507 cursor_blink_ev.again ();
1050     else
1051     cursor_blink_ev.stop ();
1052 sf-exg 1.506 }
1053    
1054     void
1055 root 1.363 rxvt_term::cursor_blink_cb (ev::timer &w, int revents)
1056 pcg 1.5 {
1057     hidden_cursor = !hidden_cursor;
1058     want_refresh = 1;
1059 root 1.381 refresh_check ();
1060 pcg 1.5 }
1061 pcg 1.27 #endif
1062 pcg 1.5
1063 pcg 1.31 #ifdef TEXT_BLINK
1064     void
1065 root 1.363 rxvt_term::text_blink_cb (ev::timer &w, int revents)
1066 pcg 1.31 {
1067     if (scr_refresh_rend (RS_Blink, RS_Blink))
1068     {
1069     hidden_text = !hidden_text;
1070     want_refresh = 1;
1071 root 1.392 refresh_check ();
1072 pcg 1.31 }
1073 root 1.375 else
1074     w.stop ();
1075 pcg 1.31 }
1076     #endif
1077    
1078 root 1.97 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
1079     void
1080 root 1.363 rxvt_term::cont_scroll_cb (ev::timer &w, int revents)
1081 root 1.97 {
1082 sf-exg 1.497 if ((scrollBar.state == SB_STATE_UP || scrollBar.state == SB_STATE_DOWN)
1083     && scr_page (scrollBar.state == SB_STATE_UP ? UP : DN, 1))
1084 root 1.381 {
1085     want_refresh = 1;
1086     refresh_check ();
1087     }
1088 root 1.363 else
1089     w.stop ();
1090 root 1.97 }
1091     #endif
1092    
1093     #ifdef SELECTION_SCROLLING
1094     void
1095 root 1.363 rxvt_term::sel_scroll_cb (ev::timer &w, int revents)
1096 root 1.97 {
1097 sf-exg 1.540 if (scr_page (scroll_selection_lines))
1098 root 1.97 {
1099     selection_extend (selection_save_x, selection_save_y, selection_save_state);
1100     want_refresh = 1;
1101 root 1.381 refresh_check ();
1102 root 1.97 }
1103 root 1.363 else
1104     w.stop ();
1105 root 1.97 }
1106     #endif
1107    
1108     #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
1109     void
1110 root 1.363 rxvt_term::slip_wheel_cb (ev::timer &w, int revents)
1111 root 1.97 {
1112 sf-exg 1.539 if (scr_page (mouse_slip_wheel_speed))
1113 root 1.381 {
1114     want_refresh = 1;
1115     refresh_check ();
1116     }
1117 root 1.378
1118     if (view_start == top_row || view_start == 0 || mouse_slip_wheel_speed == 0)
1119 root 1.97 {
1120 root 1.378 mouse_slip_wheel_speed = 0;
1121     w.stop ();
1122 root 1.97 }
1123     }
1124     #endif
1125    
1126 root 1.302 #if LINUX_YIELD_HACK
1127     static struct event_handler
1128     {
1129 root 1.363 ev::prepare yield_ev;
1130 ayin 1.329
1131 root 1.363 void yield_cb (ev::prepare &w, int revents)
1132 root 1.302 {
1133 root 1.303 // this should really be sched_yield(), but the linux guys thought
1134     // that giving a process calling sched_yield () less cpu time than
1135 root 1.304 // ones with high nice levels is a useful thing to do. It surely is is
1136     // allowed by the sus... as is returning ENOSYS.
1137 root 1.421 // since the linux guys additionally thought that breaking the only
1138 sf-exg 1.442 // known workaround against their unusable sched_yield hack is cool,
1139 root 1.421 // we just nanosleep a bit and hope for the best.
1140 root 1.303
1141 root 1.421 struct timespec ts = { 0, 1000 };
1142 root 1.303 nanosleep (&ts, 0);
1143    
1144 root 1.302 w.stop ();
1145     }
1146    
1147     event_handler ()
1148     : yield_ev (this, &event_handler::yield_cb)
1149     {
1150     }
1151     } event_handler;
1152     #endif
1153    
1154 root 1.481 /* make sure all the cmd data is at beginning of cmdbuf */
1155     void
1156     rxvt_term::cmdbuf_reify ()
1157     {
1158     if (cmdbuf_ptr == cmdbuf_base)
1159     return;
1160    
1161     ssize_t used = cmdbuf_endp - cmdbuf_ptr;
1162    
1163     memmove (cmdbuf_base, cmdbuf_ptr, used);
1164     cmdbuf_ptr = cmdbuf_base;
1165     cmdbuf_endp = cmdbuf_ptr + used;
1166    
1167     }
1168    
1169     #if defined (KEYSYM_RESOURCE)
1170     void
1171     rxvt_term::cmdbuf_append (const char *str, size_t count)
1172     {
1173     cmdbuf_reify ();
1174    
1175     size_t avail = cmdbuf_base + CBUFSIZ - cmdbuf_endp;
1176    
1177     if (count > avail)
1178     return;
1179    
1180     memcpy (cmdbuf_endp, str, count);
1181     cmdbuf_endp += count;
1182    
1183     cmd_parse ();
1184     }
1185     #endif
1186    
1187 pcg 1.4 bool
1188 pcg 1.8 rxvt_term::pty_fill ()
1189 pcg 1.4 {
1190 root 1.481 cmdbuf_reify ();
1191 pcg 1.4
1192 root 1.481 size_t avail = cmdbuf_base + CBUFSIZ - cmdbuf_endp;
1193 pcg 1.93
1194 root 1.481 if (!avail)
1195     {
1196     // normally this indicates a "too long" command sequence - just drop the data we have
1197     cmdbuf_ptr = cmdbuf_base;
1198     cmdbuf_endp = cmdbuf_ptr;
1199     avail = CBUFSIZ;
1200     }
1201 pcg 1.36
1202 root 1.481 ssize_t r = read (pty->pty, cmdbuf_endp, avail);
1203 pcg 1.4
1204 root 1.223 if (r > 0)
1205 pcg 1.4 {
1206 root 1.223 cmdbuf_endp += r;
1207 pcg 1.4 return true;
1208     }
1209 root 1.223 else if (r < 0 && (errno == EAGAIN || errno == EINTR))
1210     {
1211 root 1.302 #if LINUX_YIELD_HACK
1212 root 1.228 if (display->is_local)
1213 root 1.302 event_handler.yield_ev.start ();
1214 root 1.223 #endif
1215     }
1216     else
1217 root 1.215 {
1218     pty_ev.stop ();
1219    
1220 root 1.321 if (!option (Opt_hold))
1221 root 1.215 destroy ();
1222     }
1223 ayin 1.329
1224 pcg 1.13 return false;
1225 pcg 1.4 }
1226    
1227 pcg 1.3 void
1228 root 1.363 rxvt_term::pty_cb (ev::io &w, int revents)
1229 pcg 1.3 {
1230 root 1.264 make_current ();
1231 pcg 1.9
1232 root 1.363 if (revents & ev::READ)
1233 pcg 1.93 // loop, but don't allow a single term to monopolize us
1234 root 1.422 for (int i = CBUFCNT; i-- && pty_fill (); )
1235     cmd_parse ();
1236 root 1.177
1237 root 1.363 if (revents & ev::WRITE)
1238 root 1.177 pty_write ();
1239 root 1.383
1240     refresh_check ();
1241 pcg 1.57 }
1242    
1243 root 1.512 void ecb_cold
1244 pcg 1.6 rxvt_term::pointer_unblank ()
1245     {
1246 root 1.305 XDefineCursor (dpy, vt, TermWin_cursor);
1247 root 1.563 recolor_cursor ();
1248 pcg 1.7
1249 root 1.107 #ifdef POINTER_BLANK
1250 pcg 1.6 hidden_pointer = 0;
1251 pcg 1.1
1252 root 1.321 if (option (Opt_pointerBlank))
1253 root 1.363 pointer_ev.start (pointerBlankDelay);
1254 root 1.107 #endif
1255 pcg 1.1 }
1256    
1257 root 1.107 #ifdef POINTER_BLANK
1258 root 1.512 void ecb_cold
1259 pcg 1.6 rxvt_term::pointer_blank ()
1260 pcg 1.1 {
1261 root 1.321 if (!option (Opt_pointerBlank))
1262 pcg 1.6 return;
1263    
1264 root 1.305 XDefineCursor (dpy, vt, display->blank_cursor);
1265     XFlush (dpy);
1266 pcg 1.1
1267 pcg 1.6 hidden_pointer = 1;
1268 pcg 1.1 }
1269    
1270 root 1.512 void ecb_cold
1271 root 1.363 rxvt_term::pointer_cb (ev::timer &w, int revents)
1272 pcg 1.1 {
1273 root 1.264 make_current ();
1274 pcg 1.9
1275 pcg 1.6 pointer_blank ();
1276 pcg 1.1 }
1277     #endif
1278    
1279     void
1280 pcg 1.56 rxvt_term::mouse_report (XButtonEvent &ev)
1281 pcg 1.1 {
1282 pcg 1.56 int button_number, key_state = 0;
1283     int x, y;
1284 ayin 1.360 int code = 32;
1285 pcg 1.36
1286 root 1.461 x = Pixel2Col (ev.x) + 1;
1287     y = Pixel2Row (ev.y) + 1;
1288    
1289 ayin 1.365 if (ev.type == MotionNotify)
1290     {
1291     if (x == mouse_row && y == mouse_col)
1292     return;
1293 root 1.461
1294 ayin 1.365 mouse_row = x;
1295     mouse_col = y;
1296     code += 32;
1297     }
1298 pcg 1.36
1299     if (MEvent.button == AnyButton)
1300 root 1.145 button_number = 3;
1301 pcg 1.36 else
1302     {
1303     button_number = MEvent.button - Button1;
1304     /* add 0x3D for wheel events, like xterm does */
1305     if (button_number >= 3)
1306 root 1.461 button_number += 64 - 3;
1307 pcg 1.36 }
1308 pcg 1.1
1309 root 1.145 if (priv_modes & PrivMode_MouseX10)
1310 pcg 1.36 {
1311     /*
1312     * do not report ButtonRelease
1313     * no state info allowed
1314     */
1315     key_state = 0;
1316     if (button_number == 3)
1317     return;
1318     }
1319     else
1320     {
1321     /* XTerm mouse reporting needs these values:
1322     * 4 = Shift
1323     * 8 = Meta
1324     * 16 = Control
1325     * plus will add in our own Double-Click reporting
1326     * 32 = Double Click
1327     */
1328     key_state = ((MEvent.state & ShiftMask) ? 4 : 0)
1329     + ((MEvent.state & ModMetaMask) ? 8 : 0)
1330     + ((MEvent.state & ControlMask) ? 16 : 0);
1331 pcg 1.1 #ifdef MOUSE_REPORT_DOUBLECLICK
1332 pcg 1.36 key_state += ((MEvent.clicks > 1) ? 32 : 0);
1333 pcg 1.1 #endif
1334     }
1335    
1336 root 1.163 #if DEBUG_MOUSEREPORT
1337 pcg 1.43 fprintf (stderr, "Mouse [");
1338 pcg 1.36 if (key_state & 16)
1339 pcg 1.43 fputc ('C', stderr);
1340 pcg 1.36 if (key_state & 4)
1341 pcg 1.43 fputc ('S', stderr);
1342 pcg 1.36 if (key_state & 8)
1343 pcg 1.43 fputc ('A', stderr);
1344 pcg 1.36 if (key_state & 32)
1345 pcg 1.43 fputc ('2', stderr);
1346     fprintf (stderr, "]: <%d>, %d/%d\n",
1347 pcg 1.36 button_number,
1348 root 1.461 x,
1349     y);
1350 root 1.163 #endif
1351    
1352 root 1.461 #if ENABLE_FRILLS
1353     if (priv_modes & PrivMode_ExtMouseRight)
1354     tt_printf ("\033[%d;%d;%dM",
1355     code + button_number + key_state,
1356     x,
1357     y);
1358     else if (priv_modes & PrivMode_ExtModeMouse)
1359     tt_printf ("\033[M%c%lc%lc",
1360     code + button_number + key_state,
1361     wint_t (32 + x),
1362     wint_t (32 + y));
1363     else
1364     #endif
1365     tt_printf ("\033[M%c%c%c",
1366     code + button_number + key_state,
1367     32 + x,
1368     32 + y);
1369 pcg 1.1 }
1370    
1371     /*{{{ process an X event */
1372 root 1.512 void ecb_hot
1373 pcg 1.38 rxvt_term::x_cb (XEvent &ev)
1374 pcg 1.1 {
1375 root 1.264 make_current ();
1376    
1377 root 1.305 dLocal (Display *, dpy);
1378 root 1.192
1379 root 1.259 if (ev.xany.window == vt
1380 root 1.265 && SHOULD_INVOKE (HOOK_X_EVENT)
1381 root 1.259 && HOOK_INVOKE ((this, HOOK_X_EVENT, DT_XEVENT, &ev, DT_END)))
1382     return;
1383    
1384 root 1.260 // for XQueryPointer
1385 root 1.175 Window unused_root, unused_child;
1386     int unused_root_x, unused_root_y;
1387     unsigned int unused_mask;
1388 pcg 1.3
1389 pcg 1.38 switch (ev.type)
1390 pcg 1.36 {
1391     case KeyPress:
1392 root 1.306 key_press (ev.xkey);
1393 pcg 1.36 break;
1394 pcg 1.1
1395 pcg 1.36 case KeyRelease:
1396 root 1.306 key_release (ev.xkey);
1397     break;
1398 pcg 1.36
1399     case ButtonPress:
1400 pcg 1.38 button_press (ev.xbutton);
1401 pcg 1.36 break;
1402    
1403     case ButtonRelease:
1404 pcg 1.38 button_release (ev.xbutton);
1405 pcg 1.36 break;
1406    
1407     case ClientMessage:
1408 root 1.277 if (ev.xclient.format == 32
1409     && !HOOK_INVOKE ((this, HOOK_CLIENT_MESSAGE, DT_XEVENT, &ev, DT_END)))
1410 root 1.200 {
1411 root 1.276 if (ev.xclient.message_type == xa[XA_WM_PROTOCOLS])
1412     {
1413 root 1.277 if (!HOOK_INVOKE ((this, HOOK_WM_PROTOCOLS, DT_XEVENT, &ev, DT_END)))
1414 root 1.276 {
1415 root 1.277 if (ev.xclient.data.l[0] == xa[XA_WM_DELETE_WINDOW])
1416     {
1417     if (!HOOK_INVOKE ((this, HOOK_WM_DELETE_WINDOW, DT_XEVENT, &ev, DT_END)))
1418     destroy ();
1419     }
1420 root 1.200 #if ENABLE_EWMH
1421 root 1.277 else if (ev.xclient.data.l[0] == xa[XA_NET_WM_PING])
1422 root 1.305 XSendEvent (dpy, ev.xclient.window = display->root,
1423 root 1.277 False, SubstructureRedirectMask | SubstructureNotifyMask,
1424     &ev);
1425 root 1.200 #endif
1426 root 1.277 }
1427 root 1.276 }
1428 root 1.198 #if ENABLE_XEMBED
1429 root 1.276 else if (ev.xclient.format == 32 && ev.xclient.message_type == xa[XA_XEMBED])
1430     {
1431     if (ev.xclient.data.l[1] == XEMBED_FOCUS_IN)
1432     focus_in ();
1433     else if (ev.xclient.data.l[1] == XEMBED_FOCUS_OUT)
1434     focus_out ();
1435     }
1436 root 1.198 #endif
1437 pcg 1.36 }
1438     break;
1439 pcg 1.1
1440 pcg 1.36 /*
1441     * XXX: this is not the _current_ arrangement
1442     * Here's my conclusion:
1443     * If the window is completely unobscured, use bitblt's
1444     * to scroll. Even then, they're only used when doing partial
1445     * screen scrolling. When partially obscured, we have to fill
1446     * in the GraphicsExpose parts, which means that after each refresh,
1447     * we need to wait for the graphics expose or Noexpose events,
1448     * which ought to make things real slow!
1449     */
1450     case VisibilityNotify:
1451 pcg 1.38 switch (ev.xvisibility.state)
1452 pcg 1.8 {
1453     case VisibilityUnobscured:
1454 pcg 1.34 refresh_type = FAST_REFRESH;
1455 pcg 1.8 break;
1456     case VisibilityPartiallyObscured:
1457 pcg 1.34 refresh_type = SLOW_REFRESH;
1458 pcg 1.8 break;
1459     default:
1460 pcg 1.34 refresh_type = NO_REFRESH;
1461 pcg 1.8 break;
1462     }
1463 pcg 1.36 break;
1464 pcg 1.1
1465 pcg 1.36 case FocusIn:
1466 root 1.320 if (ev.xfocus.detail != NotifyInferior
1467     && ev.xfocus.detail != NotifyPointer
1468     && ev.xfocus.mode != NotifyGrab)
1469 root 1.316 focus_in ();
1470 pcg 1.36 break;
1471    
1472     case FocusOut:
1473 root 1.320 if (ev.xfocus.detail != NotifyInferior
1474     && ev.xfocus.detail != NotifyPointer
1475     && ev.xfocus.mode != NotifyGrab)
1476 root 1.316 focus_out ();
1477 pcg 1.36 break;
1478    
1479     case ConfigureNotify:
1480 sf-exg 1.482 if (ev.xconfigure.window == parent)
1481 pcg 1.36 {
1482 root 1.398 while (XCheckTypedWindowEvent (dpy, ev.xconfigure.window, ConfigureNotify, &ev))
1483 root 1.208 ;
1484 pcg 1.38
1485 root 1.515 bool want_position_change = SHOULD_INVOKE (HOOK_POSITION_CHANGE);
1486    
1487 sf-exg 1.523 bool moved = false;
1488 sf-exg 1.460 #ifdef HAVE_BG_PIXMAP
1489 root 1.515 if (bg_window_position_sensitive ())
1490 sf-exg 1.523 {
1491     want_position_change = true;
1492 sf-exg 1.530 if (bg_img == 0)
1493 sf-exg 1.523 moved = true;
1494     }
1495 root 1.515 #endif
1496    
1497     if (want_position_change)
1498 sf-exg 1.460 {
1499     int x, y;
1500 root 1.515
1501 sf-exg 1.460 if (ev.xconfigure.send_event)
1502     {
1503     x = ev.xconfigure.x;
1504     y = ev.xconfigure.y;
1505     }
1506     else
1507     get_window_origin (x, y);
1508    
1509 root 1.515 if (x != parent_x || y != parent_y)
1510     {
1511     parent_x = x;
1512     parent_y = y;
1513 root 1.519 HOOK_INVOKE ((this, HOOK_POSITION_CHANGE, DT_INT, x, DT_INT, y, DT_END));
1514 sf-exg 1.521 moved = true;
1515 root 1.515 }
1516 sf-exg 1.460 }
1517    
1518 root 1.208 if (szHint.width != ev.xconfigure.width || szHint.height != ev.xconfigure.height)
1519 root 1.163 {
1520     seen_resize = 1;
1521 root 1.208 resize_all_windows (ev.xconfigure.width, ev.xconfigure.height, 1);
1522 sasha 1.347 }
1523     else
1524     {
1525 sasha 1.353 #ifdef HAVE_BG_PIXMAP
1526 sf-exg 1.460 if (moved)
1527 sf-exg 1.492 update_background ();
1528 sasha 1.324 #endif
1529 root 1.163 }
1530 root 1.385
1531 root 1.270 HOOK_INVOKE ((this, HOOK_CONFIGURE_NOTIFY, DT_XEVENT, &ev, DT_END));
1532 pcg 1.36 }
1533     break;
1534    
1535 root 1.131 case PropertyNotify:
1536 sf-exg 1.476 HOOK_INVOKE ((this, HOOK_PROPERTY_NOTIFY, DT_XEVENT, &ev, DT_END));
1537 root 1.131 break;
1538    
1539 pcg 1.36 case SelectionClear:
1540 sf-exg 1.436 selection_clear (ev.xselectionclear.selection == xa[XA_CLIPBOARD]);
1541 pcg 1.36 break;
1542    
1543     case SelectionRequest:
1544 pcg 1.38 selection_send (ev.xselectionrequest);
1545 pcg 1.36 break;
1546 pcg 1.1
1547 root 1.247 case MapNotify:
1548 sasha 1.393 #ifdef HAVE_BG_PIXMAP
1549 sf-exg 1.529 // This is needed at startup for the case of no window manager
1550     // or a non-reparenting window manager and also because we
1551     // defer bg image updates if the window is not mapped. The
1552     // short delay is to optimize for multiple ConfigureNotify
1553     // events at startup when the window manager reparents the
1554     // window, so as to perform the computation after we have
1555     // received all of them.
1556 sf-exg 1.530 if (bg_img == 0)
1557 sasha 1.393 update_background_ev.start (0.025);
1558     #endif
1559 root 1.247 mapped = 1;
1560 pcg 1.31 #ifdef TEXT_BLINK
1561 root 1.374 text_blink_ev.start ();
1562 pcg 1.31 #endif
1563 root 1.247 HOOK_INVOKE ((this, HOOK_MAP_NOTIFY, DT_XEVENT, &ev, DT_END));
1564 pcg 1.36 break;
1565 pcg 1.1
1566 root 1.247 case UnmapNotify:
1567     mapped = 0;
1568 pcg 1.31 #ifdef TEXT_BLINK
1569 root 1.247 text_blink_ev.stop ();
1570 pcg 1.31 #endif
1571 root 1.247 HOOK_INVOKE ((this, HOOK_UNMAP_NOTIFY, DT_XEVENT, &ev, DT_END));
1572 pcg 1.36 break;
1573 pcg 1.1
1574 pcg 1.36 case GraphicsExpose:
1575     case Expose:
1576 root 1.208 if (ev.xany.window == vt)
1577 pcg 1.36 {
1578 root 1.116 do
1579 sasha 1.357 {
1580     scr_expose (ev.xexpose.x, ev.xexpose.y,
1581 sf-exg 1.475 ev.xexpose.width, ev.xexpose.height, false);
1582 sasha 1.357 }
1583 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, ev.xany.type, &ev));
1584 root 1.116
1585     ev.xany.type = ev.xany.type == Expose ? GraphicsExpose : Expose;
1586    
1587 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, ev.xany.type, &ev))
1588 sasha 1.357 {
1589     scr_expose (ev.xexpose.x, ev.xexpose.y,
1590 sf-exg 1.475 ev.xexpose.width, ev.xexpose.height, false);
1591 sasha 1.357 }
1592 root 1.381
1593 root 1.254 want_refresh = 1;
1594 pcg 1.36 }
1595     else
1596     {
1597 pcg 1.38 XEvent unused_event;
1598 pcg 1.36
1599 root 1.305 while (XCheckTypedWindowEvent (dpy, ev.xany.window, Expose, &unused_event))
1600 pcg 1.95 ;
1601 root 1.305 while (XCheckTypedWindowEvent (dpy, ev.xany.window, GraphicsExpose, &unused_event))
1602 pcg 1.95 ;
1603    
1604 ayin 1.389 if (scrollBar.state && ev.xany.window == scrollBar.win)
1605 pcg 1.36 {
1606 sf-exg 1.497 scrollBar.state = SB_STATE_IDLE;
1607 ayin 1.414 scrollBar.show (0);
1608 pcg 1.36 }
1609     }
1610     break;
1611    
1612     case MotionNotify:
1613 pcg 1.1 #ifdef POINTER_BLANK
1614 pcg 1.36 if (hidden_pointer)
1615     pointer_unblank ();
1616 pcg 1.1 #endif
1617 sf-exg 1.566 if (!bypass_keystate
1618     && ((priv_modes & PrivMode_MouseBtnEvent && ev.xbutton.state & (Button1Mask|Button2Mask|Button3Mask))
1619     || priv_modes & PrivMode_MouseAnyEvent))
1620 ayin 1.360 mouse_report (ev.xbutton);
1621 root 1.168 if ((priv_modes & PrivMode_mouse_report) && !bypass_keystate)
1622 pcg 1.36 break;
1623    
1624 root 1.208 if (ev.xany.window == vt)
1625 pcg 1.36 {
1626 root 1.265 if (SHOULD_INVOKE (HOOK_MOTION_NOTIFY)
1627     && HOOK_INVOKE ((this, HOOK_MOTION_NOTIFY, DT_XEVENT, &ev, DT_END)))
1628 root 1.240 ; // nop
1629     else if (ev.xbutton.state & (Button1Mask | Button3Mask))
1630 pcg 1.36 {
1631 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, MotionNotify, &ev))
1632 pcg 1.38 ;
1633    
1634 root 1.305 XQueryPointer (dpy, vt,
1635 root 1.145 &unused_root, &unused_child,
1636     &unused_root_x, &unused_root_y,
1637 root 1.168 &ev.xbutton.x, &ev.xbutton.y,
1638     &ev.xbutton.state);
1639 pcg 1.1 #ifdef MOUSE_THRESHOLD
1640 pcg 1.36 /* deal with a `jumpy' mouse */
1641 root 1.565 if (ev.xmotion.time - MEvent.time > MOUSE_THRESHOLD)
1642     #endif
1643 pcg 1.36 {
1644 root 1.145 #if ISO_14755
1645     // 5.4
1646     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
1647     {
1648     iso14755_54 (ev.xbutton.x, ev.xbutton.y);
1649     break;
1650     }
1651     #endif
1652     selection_extend (ev.xbutton.x, ev.xbutton.y,
1653 root 1.168 ev.xbutton.state & Button3Mask ? 2 : 0);
1654    
1655 pcg 1.1 #ifdef SELECTION_SCROLLING
1656 root 1.208 if (ev.xbutton.y < int_bwidth
1657     || Pixel2Row (ev.xbutton.y) > (nrow-1))
1658 pcg 1.36 {
1659 sf-exg 1.540 page_dirn scroll_selection_dir;
1660 pcg 1.36 int dist;
1661    
1662     /* don't clobber the current delay if we are
1663     * already in the middle of scrolling.
1664     */
1665 root 1.376 if (!sel_scroll_ev.is_active ())
1666 root 1.363 sel_scroll_ev.start (SCROLLBAR_INITIAL_DELAY, SCROLLBAR_CONTINUOUS_DELAY);
1667 pcg 1.36
1668     /* save the event params so we can highlight
1669     * the selection in the pending-scroll loop
1670     */
1671 root 1.145 selection_save_x = ev.xbutton.x;
1672     selection_save_y = ev.xbutton.y;
1673     selection_save_state = (ev.xbutton.state & Button3Mask) ? 2 : 0;
1674 pcg 1.36
1675     /* calc number of lines to scroll */
1676 root 1.208 if (ev.xbutton.y < int_bwidth)
1677 pcg 1.36 {
1678     scroll_selection_dir = UP;
1679 root 1.208 dist = int_bwidth - ev.xbutton.y;
1680 pcg 1.36 }
1681     else
1682     {
1683     scroll_selection_dir = DN;
1684 sf-exg 1.504 dist = ev.xbutton.y - (int_bwidth + vt_height);
1685 pcg 1.36 }
1686 root 1.145
1687     scroll_selection_lines = Pixel2Height (dist)
1688     / SELECTION_SCROLL_LINE_SPEEDUP
1689     + 1;
1690 root 1.212 min_it (scroll_selection_lines,
1691 root 1.145 SELECTION_SCROLL_MAX_LINES);
1692 sf-exg 1.540 scroll_selection_lines *= scroll_selection_dir;
1693 pcg 1.36 }
1694     else
1695     {
1696     /* we are within the text window, so we
1697     * shouldn't be scrolling
1698     */
1699 root 1.376 sel_scroll_ev.stop();
1700 pcg 1.36 }
1701 pcg 1.1 #endif
1702 pcg 1.36 }
1703     }
1704     }
1705 sf-exg 1.497 else if (scrollBar.state == SB_STATE_MOTION && ev.xany.window == scrollBar.win)
1706 pcg 1.36 {
1707 root 1.305 while (XCheckTypedWindowEvent (dpy, scrollBar.win,
1708 root 1.168 MotionNotify, &ev))
1709     ;
1710    
1711 root 1.305 XQueryPointer (dpy, scrollBar.win,
1712 pcg 1.36 &unused_root, &unused_child,
1713     &unused_root_x, &unused_root_y,
1714 root 1.168 &ev.xbutton.x, &ev.xbutton.y,
1715 pcg 1.36 &unused_mask);
1716 sf-exg 1.494 scr_move_to (scrollBar.position (ev.xbutton.y) - csrO,
1717 ayin 1.413 scrollBar.size ());
1718 root 1.254 want_refresh = 1;
1719 ayin 1.414 scrollBar.show (1);
1720 pcg 1.36 }
1721     break;
1722     }
1723 root 1.248
1724     #if defined(CURSOR_BLINK)
1725 sf-exg 1.506 if (ev.type == KeyPress)
1726     cursor_blink_reset ();
1727 root 1.248 #endif
1728    
1729     #if defined(POINTER_BLANK)
1730 root 1.321 if (option (Opt_pointerBlank) && pointerBlankDelay > 0)
1731 root 1.248 {
1732     if (ev.type == MotionNotify
1733     || ev.type == ButtonPress
1734     || ev.type == ButtonRelease)
1735     if (hidden_pointer)
1736     pointer_unblank ();
1737    
1738     if (ev.type == KeyPress && hidden_pointer == 0)
1739     pointer_blank ();
1740     }
1741     #endif
1742 root 1.381
1743     refresh_check ();
1744 pcg 1.36 }
1745 pcg 1.1
1746 root 1.430 #if ENABLE_FRILLS
1747 root 1.512 void ecb_cold
1748 root 1.420 rxvt_term::set_urgency (bool enable)
1749     {
1750 sf-exg 1.503 if (enable == urgency_hint)
1751 root 1.420 return;
1752    
1753 sf-exg 1.482 if (XWMHints *h = XGetWMHints (dpy, parent))
1754 root 1.420 {
1755     h->flags = h->flags & ~XUrgencyHint | (enable ? XUrgencyHint : 0);
1756 sf-exg 1.482 XSetWMHints (dpy, parent, h);
1757 root 1.420 urgency_hint = enable;
1758 sf-exg 1.498 XFree (h);
1759 root 1.420 }
1760     }
1761 root 1.430 #endif
1762 root 1.420
1763 root 1.512 void ecb_cold
1764 root 1.198 rxvt_term::focus_in ()
1765     {
1766 root 1.208 if (!focus)
1767 root 1.198 {
1768 root 1.208 focus = 1;
1769 root 1.296 want_refresh = 1;
1770 root 1.227
1771 root 1.206 #if USE_XIM
1772 root 1.198 if (Input_Context != NULL)
1773     {
1774 sf-exg 1.489 im_set_position ();
1775 root 1.198 XSetICFocus (Input_Context);
1776     }
1777     #endif
1778 root 1.206 #if CURSOR_BLINK
1779 root 1.321 if (option (Opt_cursorBlink))
1780 root 1.375 cursor_blink_ev.again ();
1781 root 1.198 #endif
1782 root 1.206 #if OFF_FOCUS_FADING
1783 root 1.198 if (rs[Rs_fade])
1784     {
1785     pix_colors = pix_colors_focused;
1786 root 1.563 scr_recolor ();
1787 root 1.198 }
1788     #endif
1789 ayin 1.322 #if ENABLE_FRILLS
1790     if (option (Opt_urgentOnBell))
1791 root 1.420 set_urgency (0);
1792 sf-exg 1.569
1793     if (priv_modes & PrivMode_FocusEvent)
1794     tt_printf ("\x1b[I");
1795 ayin 1.322 #endif
1796 root 1.420
1797     HOOK_INVOKE ((this, HOOK_FOCUS_IN, DT_END));
1798 root 1.198 }
1799     }
1800    
1801 root 1.512 void ecb_cold
1802 root 1.198 rxvt_term::focus_out ()
1803     {
1804 root 1.208 if (focus)
1805 root 1.198 {
1806 root 1.208 focus = 0;
1807 root 1.296 want_refresh = 1;
1808 root 1.198
1809 root 1.420 #if ENABLE_FRILLS
1810     if (option (Opt_urgentOnBell))
1811     set_urgency (0);
1812 sf-exg 1.569
1813     if (priv_modes & PrivMode_FocusEvent)
1814     tt_printf ("\x1b[O");
1815 root 1.420 #endif
1816 root 1.198 #if ENABLE_FRILLS || ISO_14755
1817 root 1.227 if (iso14755buf)
1818     {
1819     iso14755buf = 0;
1820 ayin 1.337 # if ISO_14755
1821 root 1.227 scr_overlay_off ();
1822     # endif
1823     }
1824 root 1.198 #endif
1825 root 1.206 #if USE_XIM
1826 root 1.198 if (Input_Context != NULL)
1827     XUnsetICFocus (Input_Context);
1828     #endif
1829 root 1.206 #if CURSOR_BLINK
1830 root 1.321 if (option (Opt_cursorBlink))
1831 root 1.198 cursor_blink_ev.stop ();
1832 root 1.363
1833 root 1.198 hidden_cursor = 0;
1834     #endif
1835 root 1.206 #if OFF_FOCUS_FADING
1836 root 1.198 if (rs[Rs_fade])
1837     {
1838     pix_colors = pix_colors_unfocused;
1839 root 1.563 scr_recolor ();
1840 root 1.198 }
1841     #endif
1842 root 1.420
1843     HOOK_INVOKE ((this, HOOK_FOCUS_OUT, DT_END));
1844 root 1.198 }
1845     }
1846    
1847 root 1.512 void ecb_cold
1848 root 1.563 rxvt_term::update_fade_color (unsigned int idx, bool first_time)
1849 root 1.313 {
1850     #if OFF_FOCUS_FADING
1851     if (rs[Rs_fade])
1852     {
1853 root 1.563 if (!first_time)
1854     pix_colors_focused [idx].free (this);
1855    
1856 root 1.313 rgba c;
1857     pix_colors [Color_fade].get (c);
1858     pix_colors_focused [idx].fade (this, atoi (rs[Rs_fade]), pix_colors_unfocused [idx], c);
1859     }
1860     #endif
1861     }
1862    
1863 sf-exg 1.527 #if BG_IMAGE_FROM_ROOT || ENABLE_PERL
1864 root 1.512 void ecb_hot
1865 pcg 1.38 rxvt_term::rootwin_cb (XEvent &ev)
1866     {
1867 root 1.264 make_current ();
1868 pcg 1.38
1869 root 1.314 if (SHOULD_INVOKE (HOOK_ROOT_EVENT)
1870     && HOOK_INVOKE ((this, HOOK_ROOT_EVENT, DT_XEVENT, &ev, DT_END)))
1871     return;
1872    
1873 pcg 1.40 switch (ev.type)
1874 pcg 1.38 {
1875 pcg 1.40 case PropertyNotify:
1876 root 1.131 /*
1877     * if user used some Esetroot compatible prog to set the root bg,
1878     * use the property to determine the pixmap. We use it later on.
1879     */
1880 sasha 1.343 if (ev.xproperty.atom == xa[XA_XROOTPMAP_ID]
1881     || ev.xproperty.atom == xa[XA_ESETROOT_PMAP_ID])
1882     {
1883 sf-exg 1.527 #if BG_IMAGE_FROM_ROOT
1884 sf-exg 1.531 if (option (Opt_transparent))
1885     {
1886 sf-exg 1.532 rxvt_img::new_from_root (this)->replace (root_img);
1887 sf-exg 1.531 update_background ();
1888     }
1889 root 1.516 #endif
1890     HOOK_INVOKE ((this, HOOK_ROOTPMAP_CHANGE, DT_END));
1891 sasha 1.343 }
1892 root 1.385
1893 pcg 1.40 break;
1894 pcg 1.38 }
1895 root 1.381
1896     refresh_check ();
1897 pcg 1.38 }
1898 root 1.131 #endif
1899 pcg 1.38
1900     void
1901 pcg 1.56 rxvt_term::button_press (XButtonEvent &ev)
1902 pcg 1.1 {
1903 pcg 1.36 int reportmode = 0, clickintime;
1904 pcg 1.1
1905 pcg 1.38 bypass_keystate = ev.state & (ModMetaMask | ShiftMask);
1906 root 1.229
1907 pcg 1.36 if (!bypass_keystate)
1908 root 1.145 reportmode = !! (priv_modes & PrivMode_mouse_report);
1909    
1910 pcg 1.36 /*
1911     * VT window processing of button press
1912     */
1913 root 1.208 if (ev.window == vt)
1914 pcg 1.36 {
1915 root 1.280 if (HOOK_INVOKE ((this, HOOK_BUTTON_PRESS, DT_XEVENT, &ev, DT_END)))
1916     return;
1917    
1918 root 1.145 #if ISO_14755
1919     // 5.4
1920     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
1921     {
1922     iso14755_54 (ev.x, ev.y);
1923     return;
1924     }
1925     #endif
1926    
1927 sf-exg 1.555 clickintime = ev.time - MEvent.time < multiClickTime;
1928 root 1.168
1929 pcg 1.50 if (reportmode)
1930 pcg 1.36 {
1931 pcg 1.50 /* mouse report from vt window */
1932     /* save the xbutton state (for ButtonRelease) */
1933     MEvent.state = ev.state;
1934     #ifdef MOUSE_REPORT_DOUBLECLICK
1935     if (ev.button == MEvent.button && clickintime)
1936 pcg 1.36 {
1937 sf-exg 1.452 /* same button, within allowed time */
1938 pcg 1.50 MEvent.clicks++;
1939 root 1.243
1940 pcg 1.50 if (MEvent.clicks > 1)
1941 pcg 1.36 {
1942 pcg 1.50 /* only report double clicks */
1943     MEvent.clicks = 2;
1944 pcg 1.36 mouse_report (ev);
1945 pcg 1.50
1946     /* don't report the release */
1947     MEvent.clicks = 0;
1948     MEvent.button = AnyButton;
1949 pcg 1.36 }
1950 pcg 1.50 }
1951     else
1952     {
1953     /* different button, or time expired */
1954     MEvent.clicks = 1;
1955 pcg 1.38 MEvent.button = ev.button;
1956 pcg 1.36 mouse_report (ev);
1957 pcg 1.50 }
1958     #else
1959     MEvent.button = ev.button;
1960     mouse_report (ev);
1961 ayin 1.366 #endif /* MOUSE_REPORT_DOUBLECLICK */
1962 pcg 1.36
1963 pcg 1.50 }
1964     else
1965     {
1966     if (ev.button != MEvent.button)
1967     MEvent.clicks = 0;
1968 root 1.168
1969 root 1.280 switch (ev.button)
1970     {
1971     case Button1:
1972     /* allow meta + click to select rectangular areas */
1973     /* should be done in screen.C */
1974 root 1.168 #if ENABLE_FRILLS
1975 root 1.280 selection.rect = !!(ev.state & ModMetaMask);
1976 root 1.168 #else
1977 root 1.280 selection.rect = false;
1978 root 1.168 #endif
1979    
1980 root 1.280 /* allow shift+left click to extend selection */
1981     if (ev.state & ShiftMask && !(priv_modes & PrivMode_mouse_report))
1982     {
1983     if (MEvent.button == Button1 && clickintime)
1984     selection_rotate (ev.x, ev.y);
1985     else
1986     selection_extend (ev.x, ev.y, 1);
1987     }
1988     else
1989     {
1990     if (MEvent.button == Button1 && clickintime)
1991     MEvent.clicks++;
1992     else
1993     MEvent.clicks = 1;
1994 pcg 1.21
1995 root 1.280 selection_click (MEvent.clicks, ev.x, ev.y);
1996     }
1997 pcg 1.21
1998 root 1.280 MEvent.button = Button1;
1999     break;
2000 pcg 1.1
2001 root 1.280 case Button3:
2002     if (MEvent.button == Button3 && clickintime)
2003     selection_rotate (ev.x, ev.y);
2004     else
2005     selection_extend (ev.x, ev.y, 1);
2006 root 1.145
2007 root 1.280 MEvent.button = Button3;
2008     break;
2009     }
2010     }
2011 root 1.145
2012 pcg 1.50 MEvent.time = ev.time;
2013     return;
2014 pcg 1.36 }
2015 pcg 1.1
2016 pcg 1.36 /*
2017     * Scrollbar window processing of button press
2018     */
2019 ayin 1.389 if (scrollBar.state && ev.window == scrollBar.win)
2020 pcg 1.36 {
2021 ayin 1.403 page_dirn direction = NO_DIR;
2022 ayin 1.400
2023     if (scrollBar.upButton (ev.y))
2024 ayin 1.403 direction = UP; /* up */
2025 ayin 1.400 else if (scrollBar.dnButton (ev.y))
2026 ayin 1.403 direction = DN; /* down */
2027 ayin 1.400
2028 sf-exg 1.497 scrollBar.state = SB_STATE_IDLE;
2029 pcg 1.36 /*
2030     * Rxvt-style scrollbar:
2031     * move up if mouse is above slider
2032     * move dn if mouse is below slider
2033     *
2034     * XTerm-style scrollbar:
2035     * Move display proportional to pointer location
2036     * pointer near top -> scroll one line
2037     * pointer near bot -> scroll full page
2038     */
2039 pcg 1.1 #ifndef NO_SCROLLBAR_REPORT
2040 pcg 1.36 if (reportmode)
2041     {
2042     /*
2043     * Mouse report disabled scrollbar:
2044     * arrow buttons - send up/down
2045     * click on scrollbar - send pageup/down
2046     */
2047 ayin 1.403 if (direction == UP)
2048 pcg 1.43 tt_printf ("\033[A");
2049 ayin 1.403 else if (direction == DN)
2050 pcg 1.43 tt_printf ("\033[B");
2051 pcg 1.36 else
2052 pcg 1.38 switch (ev.button)
2053 pcg 1.36 {
2054     case Button2:
2055 pcg 1.43 tt_printf ("\014");
2056 pcg 1.36 break;
2057     case Button1:
2058 pcg 1.43 tt_printf ("\033[6~");
2059 pcg 1.36 break;
2060     case Button3:
2061 pcg 1.43 tt_printf ("\033[5~");
2062 pcg 1.36 break;
2063     }
2064     }
2065     else
2066 ayin 1.366 #endif /* NO_SCROLLBAR_REPORT */
2067 pcg 1.36 {
2068 ayin 1.403 if (direction != NO_DIR)
2069 pcg 1.36 {
2070 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2071 root 1.376 if (!cont_scroll_ev.is_active ())
2072     cont_scroll_ev.start (SCROLLBAR_INITIAL_DELAY, SCROLLBAR_CONTINUOUS_DELAY);
2073 pcg 1.1 #endif
2074 ayin 1.403 if (scr_page (direction, 1))
2075 pcg 1.36 {
2076 ayin 1.403 if (direction == UP)
2077 sf-exg 1.497 scrollBar.state = SB_STATE_UP;
2078 pcg 1.36 else
2079 sf-exg 1.497 scrollBar.state = SB_STATE_DOWN;
2080 pcg 1.36 }
2081     }
2082     else
2083 pcg 1.38 switch (ev.button)
2084 pcg 1.36 {
2085     case Button2:
2086 ayin 1.387 switch (scrollBar.align)
2087 pcg 1.36 {
2088 sf-exg 1.497 case SB_ALIGN_TOP:
2089 pcg 1.36 csrO = 0;
2090     break;
2091 sf-exg 1.497 case SB_ALIGN_CENTRE:
2092 pcg 1.36 csrO = (scrollBar.bot - scrollBar.top) / 2;
2093     break;
2094 sf-exg 1.497 case SB_ALIGN_BOTTOM:
2095 pcg 1.36 csrO = scrollBar.bot - scrollBar.top;
2096     break;
2097     }
2098 root 1.120
2099 sf-exg 1.497 if (scrollBar.style == SB_STYLE_XTERM
2100 sf-exg 1.494 || scrollBar.above_slider (ev.y)
2101     || scrollBar.below_slider (ev.y))
2102     scr_move_to (scrollBar.position (ev.y) - csrO, scrollBar.size ());
2103 root 1.120
2104 sf-exg 1.497 scrollBar.state = SB_STATE_MOTION;
2105 pcg 1.36 break;
2106    
2107     case Button1:
2108 sf-exg 1.497 if (scrollBar.align == SB_ALIGN_CENTRE)
2109 pcg 1.38 csrO = ev.y - scrollBar.top;
2110 pcg 1.36 /* FALLTHROUGH */
2111    
2112     case Button3:
2113 sf-exg 1.497 if (scrollBar.style != SB_STYLE_XTERM)
2114 pcg 1.36 {
2115 sf-exg 1.494 if (scrollBar.above_slider (ev.y))
2116 pcg 1.1 # ifdef RXVT_SCROLL_FULL
2117 root 1.208 scr_page (UP, nrow - 1);
2118 pcg 1.1 # else
2119 root 1.208 scr_page (UP, nrow / 4);
2120 pcg 1.1 # endif
2121 sf-exg 1.494 else if (scrollBar.below_slider (ev.y))
2122 pcg 1.1 # ifdef RXVT_SCROLL_FULL
2123 root 1.208 scr_page (DN, nrow - 1);
2124 pcg 1.1 # else
2125 root 1.208 scr_page (DN, nrow / 4);
2126 pcg 1.1 # endif
2127 pcg 1.36 else
2128 sf-exg 1.497 scrollBar.state = SB_STATE_MOTION;
2129 pcg 1.36 }
2130     else
2131     {
2132 pcg 1.38 scr_page ((ev.button == Button1 ? DN : UP),
2133 root 1.208 (nrow
2134 sf-exg 1.494 * scrollBar.position (ev.y)
2135 ayin 1.413 / scrollBar.size ()));
2136 pcg 1.36 }
2137 root 1.120
2138 pcg 1.36 break;
2139     }
2140     }
2141 root 1.243
2142 pcg 1.36 return;
2143 pcg 1.1 }
2144     }
2145    
2146     void
2147 pcg 1.56 rxvt_term::button_release (XButtonEvent &ev)
2148 pcg 1.1 {
2149 pcg 1.38 int reportmode = 0;
2150 pcg 1.1
2151 pcg 1.36 csrO = 0; /* reset csr Offset */
2152     if (!bypass_keystate)
2153 root 1.145 reportmode = !! (priv_modes & PrivMode_mouse_report);
2154 pcg 1.36
2155 sf-exg 1.497 if (scrollBar.state == SB_STATE_UP || scrollBar.state == SB_STATE_DOWN)
2156 pcg 1.36 {
2157 sf-exg 1.497 scrollBar.state = SB_STATE_IDLE;
2158 ayin 1.414 scrollBar.show (0);
2159 root 1.145 }
2160 pcg 1.36
2161 pcg 1.1 #ifdef SELECTION_SCROLLING
2162 root 1.376 sel_scroll_ev.stop();
2163 pcg 1.1 #endif
2164 root 1.145
2165 root 1.208 if (ev.window == vt)
2166 pcg 1.36 {
2167 root 1.280 if (HOOK_INVOKE ((this, HOOK_BUTTON_RELEASE, DT_XEVENT, &ev, DT_END)))
2168     return;
2169    
2170 root 1.145 #if ISO_14755
2171     // 5.4
2172     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
2173     return;
2174     #endif
2175 root 1.280
2176 pcg 1.50 if (reportmode)
2177 pcg 1.36 {
2178 pcg 1.50 /* mouse report from vt window */
2179     /* don't report release of wheel "buttons" */
2180     if (ev.button >= 4)
2181     return;
2182     #ifdef MOUSE_REPORT_DOUBLECLICK
2183     /* only report the release of 'slow' single clicks */
2184     if (MEvent.button != AnyButton
2185     && (ev.button != MEvent.button
2186     || (ev.time - MEvent.time
2187 sf-exg 1.555 > multiClickTime / 2)))
2188 pcg 1.36 {
2189 pcg 1.50 MEvent.clicks = 0;
2190 pcg 1.36 MEvent.button = AnyButton;
2191     mouse_report (ev);
2192 pcg 1.50 }
2193     #else /* MOUSE_REPORT_DOUBLECLICK */
2194     MEvent.button = AnyButton;
2195     mouse_report (ev);
2196 ayin 1.366 #endif /* MOUSE_REPORT_DOUBLECLICK */
2197 pcg 1.50 return;
2198     }
2199 root 1.145
2200 pcg 1.50 /*
2201     * dumb hack to compensate for the failure of click-and-drag
2202     * when overriding mouse reporting
2203     */
2204 root 1.145 if (priv_modes & PrivMode_mouse_report
2205 pcg 1.50 && bypass_keystate
2206     && ev.button == Button1 && MEvent.clicks <= 1)
2207     selection_extend (ev.x, ev.y, 0);
2208    
2209     switch (ev.button)
2210     {
2211     case Button1:
2212     case Button3:
2213     selection_make (ev.time);
2214     break;
2215 root 1.272
2216 pcg 1.50 case Button2:
2217 sf-exg 1.504 if (IN_RANGE_EXC (ev.x, 0, vt_width) && IN_RANGE_EXC (ev.y, 0, vt_height)) // inside window?
2218 sf-exg 1.447 selection_request (ev.time, ev.state & ModMetaMask ? Sel_Clipboard : Sel_Primary);
2219 pcg 1.50 break;
2220 root 1.272
2221 pcg 1.50 #ifdef MOUSE_WHEEL
2222     case Button4:
2223     case Button5:
2224 pcg 1.36 {
2225 sf-exg 1.537 int lines;
2226     page_dirn dirn;
2227 pcg 1.36
2228 sf-exg 1.537 dirn = ev.button == Button4 ? UP : DN;
2229 root 1.97
2230 pcg 1.50 if (ev.state & ShiftMask)
2231 sf-exg 1.537 lines = 1;
2232 root 1.321 else if (option (Opt_mouseWheelScrollPage))
2233 sf-exg 1.537 lines = nrow - 1;
2234 pcg 1.50 else
2235 sf-exg 1.537 lines = 5;
2236 root 1.97
2237 pcg 1.1 # ifdef MOUSE_SLIP_WHEELING
2238 pcg 1.50 if (ev.state & ControlMask)
2239     {
2240 sf-exg 1.537 mouse_slip_wheel_speed += dirn;
2241 sf-exg 1.539 clamp_it (mouse_slip_wheel_speed, -nrow, nrow);
2242 root 1.107
2243 root 1.376 if (!slip_wheel_ev.is_active ())
2244     slip_wheel_ev.start (SCROLLBAR_CONTINUOUS_DELAY, SCROLLBAR_CONTINUOUS_DELAY);
2245 pcg 1.50 }
2246 root 1.107 else
2247 ayin 1.390 # endif
2248 root 1.107 {
2249 sf-exg 1.537 scr_page (dirn, lines);
2250 ayin 1.414 scrollBar.show (1);
2251 pcg 1.50 }
2252     }
2253     break;
2254 pcg 1.1 #endif
2255 pcg 1.36 }
2256     }
2257 pcg 1.1 }
2258    
2259     /*}}} */
2260    
2261 root 1.512 void ecb_hot
2262 pcg 1.81 rxvt_term::cmd_parse ()
2263     {
2264 root 1.245 wchar_t ch = NOCHAR;
2265 root 1.234 char *seq_begin; // remember start of esc-sequence here
2266 pcg 1.81
2267     for (;;)
2268     {
2269 sf-exg 1.488 if (ecb_unlikely (ch == NOCHAR))
2270 pcg 1.81 {
2271     seq_begin = cmdbuf_ptr;
2272     ch = next_char ();
2273 root 1.238
2274     if (ch == NOCHAR)
2275     break;
2276 pcg 1.81 }
2277    
2278 sf-exg 1.488 if (ecb_likely (!IS_CONTROL (ch) || ch == C0_LF || ch == C0_CR || ch == C0_HT))
2279 pcg 1.81 {
2280 sf-exg 1.488 if (ecb_unlikely (!seen_input))
2281 root 1.145 {
2282     seen_input = 1;
2283     // many badly-written programs (e.g. jed) contain a race condition:
2284     // they first read the screensize and then install a SIGWINCH handler.
2285     // some window managers resize the window early, and these programs
2286     // then sometimes get the size wrong.
2287 root 1.163 // unfortunately other programs are even more buggy and dislike
2288     // being sent SIGWINCH, so only do it when we were in fact being
2289     // resized.
2290 root 1.197 if (seen_resize && cmd_pid)
2291 root 1.163 kill (-cmd_pid, SIGWINCH);
2292 root 1.145 }
2293    
2294 pcg 1.81 /* Read a text string from the input buffer */
2295 root 1.245 wchar_t buf[UBUFSIZ];
2296 pcg 1.81 bool refreshnow = false;
2297     int nlines = 0;
2298 root 1.245 wchar_t *str = buf;
2299     wchar_t *eol = str + min (ncol, UBUFSIZ);
2300 pcg 1.81
2301     for (;;)
2302     {
2303 sf-exg 1.488 if (ecb_unlikely (ch == NOCHAR || (IS_CONTROL (ch) && ch != C0_LF && ch != C0_CR && ch != C0_HT)))
2304 pcg 1.81 break;
2305    
2306     *str++ = ch;
2307    
2308 sf-exg 1.488 if (ecb_unlikely (ch == C0_LF || str >= eol))
2309 pcg 1.81 {
2310 root 1.205 if (ch == C0_LF)
2311     nlines++;
2312    
2313 pcg 1.81 refresh_count++;
2314    
2315 root 1.330 if (!option (Opt_jumpScroll) || refresh_count >= nrow - 1)
2316 pcg 1.81 {
2317 root 1.226 refresh_count = 0;
2318 root 1.330
2319 root 1.367 if (!option (Opt_skipScroll) || ev_time () > ev::now () + 1. / 60.)
2320 root 1.330 {
2321     refreshnow = true;
2322     ch = NOCHAR;
2323     break;
2324     }
2325 pcg 1.81 }
2326    
2327 root 1.208 // scr_add_lines only works for nlines <= nrow - 1.
2328     if (nlines >= nrow - 1)
2329 pcg 1.81 {
2330 root 1.266 if (!(SHOULD_INVOKE (HOOK_ADD_LINES)
2331     && HOOK_INVOKE ((this, HOOK_ADD_LINES, DT_WCS_LEN, buf, str - buf, DT_END))))
2332 root 1.245 scr_add_lines (buf, str - buf, nlines);
2333 root 1.236
2334 pcg 1.81 nlines = 0;
2335     str = buf;
2336 root 1.208 eol = str + min (ncol, UBUFSIZ);
2337 root 1.204 }
2338    
2339     if (str >= eol)
2340     {
2341     if (eol >= buf + UBUFSIZ)
2342     {
2343     ch = NOCHAR;
2344     break;
2345     }
2346     else
2347 root 1.208 eol = min (eol + ncol, buf + UBUFSIZ);
2348 pcg 1.81 }
2349    
2350     }
2351 root 1.120
2352     seq_begin = cmdbuf_ptr;
2353     ch = next_char ();
2354 pcg 1.81 }
2355    
2356 root 1.266 if (!(SHOULD_INVOKE (HOOK_ADD_LINES)
2357     && HOOK_INVOKE ((this, HOOK_ADD_LINES, DT_WCS_LEN, buf, str - buf, DT_END))))
2358 root 1.245 scr_add_lines (buf, str - buf, nlines);
2359 pcg 1.81
2360     /*
2361     * If there have been a lot of new lines, then update the screen
2362 root 1.330 * What the heck we'll cheat and only refresh less than every page-full.
2363     * if skipScroll is enabled.
2364 pcg 1.81 */
2365     if (refreshnow)
2366     {
2367 root 1.330 scr_refresh ();
2368     want_refresh = 1;
2369 pcg 1.81 }
2370     }
2371     else
2372     {
2373     try
2374     {
2375     process_nonprinting (ch);
2376     }
2377     catch (const class out_of_input &o)
2378     {
2379     // we ran out of input, retry later
2380     cmdbuf_ptr = seq_begin;
2381     break;
2382     }
2383    
2384     ch = NOCHAR;
2385     }
2386     }
2387     }
2388    
2389     // read the next character
2390 root 1.512 wchar_t ecb_hot
2391 root 1.274 rxvt_term::next_char () NOTHROW
2392 pcg 1.81 {
2393     while (cmdbuf_ptr < cmdbuf_endp)
2394     {
2395     // assume 7-bit to be ascii ALWAYS
2396 sf-exg 1.488 if (ecb_likely ((unsigned char)*cmdbuf_ptr <= 0x7f && *cmdbuf_ptr != 0x1b))
2397 pcg 1.81 return *cmdbuf_ptr++;
2398    
2399     wchar_t wc;
2400 root 1.234 size_t len = mbrtowc (&wc, cmdbuf_ptr, cmdbuf_endp - cmdbuf_ptr, mbstate);
2401 pcg 1.81
2402     if (len == (size_t)-2)
2403     {
2404     // the mbstate stores incomplete sequences. didn't know this :/
2405     cmdbuf_ptr = cmdbuf_endp;
2406     break;
2407     }
2408    
2409     if (len == (size_t)-1)
2410 root 1.415 {
2411 root 1.431 mbstate.reset (); // reset now undefined conversion state
2412 sf-exg 1.525 // a -1 might indicate that a previous incomplete char is invalid (previous return -2)
2413     // in which case we "erroneously" return the next byte which might be valid.
2414 root 1.415 return (unsigned char)*cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
2415     }
2416 pcg 1.81
2417     // assume wchar == unicode
2418     cmdbuf_ptr += len;
2419 root 1.183 return wc & UNICODE_MASK;
2420 pcg 1.81 }
2421    
2422     return NOCHAR;
2423     }
2424    
2425 root 1.245 // read the next octet
2426 root 1.512 uint32_t ecb_hot
2427 root 1.274 rxvt_term::next_octet () NOTHROW
2428 root 1.245 {
2429     return cmdbuf_ptr < cmdbuf_endp
2430 root 1.246 ? (unsigned char)*cmdbuf_ptr++
2431 root 1.245 : NOCHAR;
2432     }
2433    
2434 root 1.274 static class out_of_input out_of_input;
2435    
2436 root 1.512 wchar_t ecb_hot
2437 root 1.274 rxvt_term::cmd_getc () THROW ((class out_of_input))
2438 pcg 1.81 {
2439 root 1.245 wchar_t c = next_char ();
2440 pcg 1.81
2441     if (c == NOCHAR)
2442     throw out_of_input;
2443    
2444     return c;
2445     }
2446    
2447 root 1.512 uint32_t ecb_hot
2448 root 1.274 rxvt_term::cmd_get8 () THROW ((class out_of_input))
2449 root 1.97 {
2450 root 1.245 uint32_t c = next_octet ();
2451 root 1.97
2452     if (c == NOCHAR)
2453     throw out_of_input;
2454    
2455     return c;
2456     }
2457    
2458 pcg 1.1 /*{{{ print pipe */
2459     /*----------------------------------------------------------------------*/
2460     #ifdef PRINTPIPE
2461 root 1.512 FILE * ecb_cold
2462 pcg 1.34 rxvt_term::popen_printer ()
2463 pcg 1.1 {
2464 root 1.416 FILE *stream = popen (rs[Rs_print_pipe] ? rs[Rs_print_pipe] : PRINTPIPE, "w");
2465 pcg 1.1
2466 pcg 1.36 if (stream == NULL)
2467 pcg 1.81 rxvt_warn ("can't open printer pipe, not printing.\n");
2468    
2469 pcg 1.36 return stream;
2470 pcg 1.1 }
2471    
2472 root 1.512 int ecb_cold
2473 pcg 1.34 rxvt_term::pclose_printer (FILE *stream)
2474 pcg 1.1 {
2475 pcg 1.11 fflush (stream);
2476     return pclose (stream);
2477 pcg 1.1 }
2478    
2479     /*
2480     * simulate attached vt100 printer
2481     */
2482 root 1.512 void ecb_cold
2483 pcg 1.34 rxvt_term::process_print_pipe ()
2484 pcg 1.1 {
2485 root 1.416 FILE *fd = popen_printer ();
2486 pcg 1.36
2487 root 1.416 if (!fd)
2488 pcg 1.36 return;
2489    
2490     /*
2491     * Send all input to the printer until either ESC[4i or ESC[?4i
2492     * is received.
2493     */
2494 root 1.416 for (int done = 0; !done; )
2495 pcg 1.36 {
2496 pcg 1.81 unsigned char buf[8];
2497     unicode_t ch;
2498     unsigned int i, len;
2499 pcg 1.1
2500 pcg 1.36 if ((ch = cmd_getc ()) != C0_ESC)
2501     {
2502 pcg 1.43 if (putc (ch, fd) == EOF)
2503 pcg 1.36 break; /* done = 1 */
2504     }
2505     else
2506     {
2507     len = 0;
2508     buf[len++] = ch;
2509 pcg 1.1
2510 pcg 1.36 if ((buf[len++] = cmd_getc ()) == '[')
2511     {
2512     if ((ch = cmd_getc ()) == '?')
2513     {
2514     buf[len++] = '?';
2515     ch = cmd_getc ();
2516     }
2517     if ((buf[len++] = ch) == '4')
2518     {
2519     if ((buf[len++] = cmd_getc ()) == 'i')
2520     break; /* done = 1 */
2521     }
2522     }
2523 ayin 1.329
2524 pcg 1.36 for (i = 0; i < len; i++)
2525 pcg 1.43 if (putc (buf[i], fd) == EOF)
2526 pcg 1.36 {
2527     done = 1;
2528     break;
2529     }
2530     }
2531 pcg 1.1 }
2532 pcg 1.81
2533 pcg 1.36 pclose_printer (fd);
2534 pcg 1.1 }
2535 ayin 1.366 #endif /* PRINTPIPE */
2536 pcg 1.1 /*}}} */
2537    
2538     enum {
2539 pcg 1.36 C1_40 = 0x40,
2540 pcg 1.90 C1_41 , C1_BPH, C1_NBH, C1_44 , C1_NEL, C1_SSA, C1_ESA,
2541 pcg 1.36 C1_HTS, C1_HTJ, C1_VTS, C1_PLD, C1_PLU, C1_RI , C1_SS2, C1_SS3,
2542     C1_DCS, C1_PU1, C1_PU2, C1_STS, C1_CCH, C1_MW , C1_SPA, C1_EPA,
2543 pcg 1.90 C1_SOS, C1_59 , C1_SCI, C1_CSI, CS_ST , C1_OSC, C1_PM , C1_APC,
2544 pcg 1.1 };
2545    
2546     /*{{{ process non-printing single characters */
2547 root 1.512 void ecb_hot
2548 pcg 1.81 rxvt_term::process_nonprinting (unicode_t ch)
2549 pcg 1.1 {
2550 pcg 1.36 switch (ch)
2551     {
2552 pcg 1.81 case C0_ESC:
2553     process_escape_seq ();
2554     break;
2555 pcg 1.36 case C0_ENQ: /* terminal Status */
2556     if (rs[Rs_answerbackstring])
2557 root 1.234 tt_write (rs [Rs_answerbackstring], strlen (rs [Rs_answerbackstring]));
2558 pcg 1.36 else
2559 root 1.234 tt_write (VT100_ANS, strlen (VT100_ANS));
2560 pcg 1.36 break;
2561     case C0_BEL: /* bell */
2562     scr_bell ();
2563     break;
2564     case C0_BS: /* backspace */
2565     scr_backspace ();
2566     break;
2567     case C0_HT: /* tab */
2568     scr_tab (1);
2569     break;
2570     case C0_CR: /* carriage return */
2571     scr_gotorc (0, 0, R_RELATIVE);
2572     break;
2573     case C0_VT: /* vertical tab, form feed */
2574     case C0_FF:
2575     case C0_LF: /* line feed */
2576     scr_index (UP);
2577     break;
2578     case C0_SO: /* shift out - acs */
2579     scr_charset_choose (1);
2580     break;
2581     case C0_SI: /* shift in - acs */
2582     scr_charset_choose (0);
2583     break;
2584 pcg 1.81
2585 root 1.97 #ifdef EIGHT_BIT_CONTROLS
2586 pcg 1.81 // 8-bit controls
2587 root 1.559 case 0x90: /* DCS */
2588 pcg 1.81 process_dcs_seq ();
2589     break;
2590 root 1.559 case 0x9b: /* CSI */
2591 pcg 1.81 process_csi_seq ();
2592     break;
2593 root 1.559 case 0x9d: /* OSC */
2594 pcg 1.81 process_osc_seq ();
2595     break;
2596 root 1.97 #endif
2597 pcg 1.1 }
2598     }
2599     /*}}} */
2600    
2601    
2602     /*{{{ process VT52 escape sequences */
2603 root 1.512 void ecb_cold
2604 pcg 1.81 rxvt_term::process_escape_vt52 (unicode_t ch)
2605 pcg 1.1 {
2606 pcg 1.36 int row, col;
2607    
2608     switch (ch)
2609     {
2610     case 'A': /* cursor up */
2611     scr_gotorc (-1, 0, R_RELATIVE | C_RELATIVE);
2612     break;
2613     case 'B': /* cursor down */
2614     scr_gotorc (1, 0, R_RELATIVE | C_RELATIVE);
2615     break;
2616     case 'C': /* cursor right */
2617     scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
2618     break;
2619     case 'D': /* cursor left */
2620     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
2621     break;
2622     case 'H': /* cursor home */
2623     scr_gotorc (0, 0, 0);
2624     break;
2625     case 'I': /* cursor up and scroll down if needed */
2626     scr_index (DN);
2627     break;
2628     case 'J': /* erase to end of screen */
2629     scr_erase_screen (0);
2630     break;
2631     case 'K': /* erase to end of line */
2632     scr_erase_line (0);
2633     break;
2634     case 'Y': /* move to specified row and col */
2635     /* full command is 'ESC Y row col' where row and col
2636     * are encoded by adding 32 and sending the ascii
2637     * character. eg. SPACE = 0, '+' = 13, '0' = 18,
2638     * etc. */
2639     row = cmd_getc () - ' ';
2640     col = cmd_getc () - ' ';
2641     scr_gotorc (row, col, 0);
2642     break;
2643     case 'Z': /* identify the terminal type */
2644 pcg 1.43 tt_printf ("\033/Z"); /* I am a VT100 emulating a VT52 */
2645 pcg 1.1 break;
2646 pcg 1.36 case '<': /* turn off VT52 mode */
2647 sf-exg 1.496 priv_modes &= ~PrivMode_vt52;
2648 pcg 1.36 break;
2649     case 'F': /* use special graphics character set */
2650     case 'G': /* use regular character set */
2651     /* unimplemented */
2652     break;
2653     case '=': /* use alternate keypad mode */
2654     case '>': /* use regular keypad mode */
2655     /* unimplemented */
2656     break;
2657 pcg 1.1 }
2658     }
2659     /*}}} */
2660    
2661    
2662     /*{{{ process escape sequences */
2663 root 1.512 void ecb_hot
2664 pcg 1.34 rxvt_term::process_escape_seq ()
2665 pcg 1.1 {
2666 pcg 1.81 unicode_t ch = cmd_getc ();
2667 pcg 1.36
2668 root 1.145 if (priv_modes & PrivMode_vt52)
2669 pcg 1.36 {
2670     process_escape_vt52 (ch);
2671     return;
2672     }
2673 pcg 1.1
2674 pcg 1.36 switch (ch)
2675     {
2676     case '#':
2677     if (cmd_getc () == '8')
2678     scr_E ();
2679     break;
2680 pcg 1.44 case '(':
2681 pcg 1.36 scr_charset_set (0, (unsigned int)cmd_getc ());
2682     break;
2683     case ')':
2684     scr_charset_set (1, (unsigned int)cmd_getc ());
2685     break;
2686     case '*':
2687     scr_charset_set (2, (unsigned int)cmd_getc ());
2688     break;
2689     case '+':
2690     scr_charset_set (3, (unsigned int)cmd_getc ());
2691     break;
2692 root 1.294 #if !ENABLE_MINIMAL
2693 pcg 1.36 case '6':
2694     scr_backindex ();
2695     break;
2696     #endif
2697     case '7':
2698     scr_cursor (SAVE);
2699     break;
2700     case '8':
2701     scr_cursor (RESTORE);
2702     break;
2703 root 1.294 #if !ENABLE_MINIMAL
2704 pcg 1.36 case '9':
2705     scr_forwardindex ();
2706     break;
2707     #endif
2708 sf-exg 1.490 // DECPAM/DECPNM
2709 pcg 1.36 case '=':
2710 sf-exg 1.496 priv_modes |= PrivMode_aplKP;
2711     break;
2712 pcg 1.36 case '>':
2713 sf-exg 1.496 priv_modes &= ~PrivMode_aplKP;
2714 pcg 1.36 break;
2715    
2716     case C1_40:
2717     cmd_getc ();
2718     break;
2719     case C1_44:
2720     scr_index (UP);
2721     break;
2722 pcg 1.1
2723 pcg 1.36 /* 8.3.87: NEXT LINE */
2724     case C1_NEL: /* ESC E */
2725 pcg 1.1 {
2726 root 1.245 wchar_t nlcr[] = { C0_LF, C0_CR };
2727 sf-exg 1.488 scr_add_lines (nlcr, ecb_array_length (nlcr), 1);
2728 pcg 1.1 }
2729 pcg 1.36 break;
2730    
2731     /* kidnapped escape sequence: Should be 8.3.48 */
2732     case C1_ESA: /* ESC G */
2733 root 1.479 // used by original rxvt for rob nations own graphics mode
2734     if (cmd_getc () == 'Q')
2735     tt_printf ("\033G0\012"); /* query graphics - no graphics */
2736 pcg 1.36 break;
2737    
2738     /* 8.3.63: CHARACTER TABULATION SET */
2739     case C1_HTS: /* ESC H */
2740     scr_set_tab (1);
2741     break;
2742    
2743     /* 8.3.105: REVERSE LINE FEED */
2744     case C1_RI: /* ESC M */
2745     scr_index (DN);
2746     break;
2747    
2748     /* 8.3.142: SINGLE-SHIFT TWO */
2749 sf-exg 1.487 /* case C1_SS2: break; */
2750 pcg 1.36
2751     /* 8.3.143: SINGLE-SHIFT THREE */
2752 sf-exg 1.487 /* case C1_SS3: break; */
2753 pcg 1.36
2754     /* 8.3.27: DEVICE CONTROL STRING */
2755     case C1_DCS: /* ESC P */
2756     process_dcs_seq ();
2757     break;
2758    
2759     /* 8.3.110: SINGLE CHARACTER INTRODUCER */
2760     case C1_SCI: /* ESC Z */
2761 root 1.234 tt_write (ESCZ_ANSWER, sizeof (ESCZ_ANSWER) - 1);
2762 pcg 1.36 break; /* steal obsolete ESC [ c */
2763    
2764 root 1.423 /* 8.3.16: CONTROL SEQUENCE INTRODUCER (CSI) */
2765 pcg 1.36 case C1_CSI: /* ESC [ */
2766     process_csi_seq ();
2767     break;
2768 pcg 1.1
2769 root 1.423 /* 8.3.90: OPERATING SYSTEM COMMAND (OSC) */
2770 pcg 1.36 case C1_OSC: /* ESC ] */
2771     process_osc_seq ();
2772     break;
2773    
2774 root 1.423 /* 8.3.106: RESET TO INITIAL STATE (RIS) */
2775 pcg 1.36 case 'c':
2776 pcg 1.90 mbstate.reset ();
2777 pcg 1.36 scr_poweron ();
2778 ayin 1.414 scrollBar.show (1);
2779 pcg 1.36 break;
2780    
2781     /* 8.3.79: LOCKING-SHIFT TWO (see ISO2022) */
2782     case 'n':
2783     scr_charset_choose (2);
2784     break;
2785    
2786     /* 8.3.81: LOCKING-SHIFT THREE (see ISO2022) */
2787     case 'o':
2788     scr_charset_choose (3);
2789     break;
2790 pcg 1.1 }
2791     }
2792     /*}}} */
2793    
2794     /*{{{ process CONTROL SEQUENCE INTRODUCER (CSI) sequences `ESC[' */
2795     enum {
2796 pcg 1.36 CSI_ICH = 0x40,
2797 pcg 1.95 CSI_CUU, CSI_CUD, CSI_CUF, CSI_CUB, CSI_CNL, CSI_CPL, CSI_CHA,
2798 pcg 1.36 CSI_CUP, CSI_CHT, CSI_ED , CSI_EL , CSI_IL , CSI_DL , CSI_EF , CSI_EA ,
2799     CSI_DCH, CSI_SEE, CSI_CPR, CSI_SU , CSI_SD , CSI_NP , CSI_PP , CSI_CTC,
2800     CSI_ECH, CSI_CVT, CSI_CBT, CSI_SRS, CSI_PTX, CSI_SDS, CSI_SIMD, CSI_5F,
2801     CSI_HPA, CSI_HPR, CSI_REP, CSI_DA , CSI_VPA, CSI_VPR, CSI_HVP, CSI_TBC,
2802     CSI_SM , CSI_MC , CSI_HPB, CSI_VPB, CSI_RM , CSI_SGR, CSI_DSR, CSI_DAQ,
2803     CSI_70 , CSI_71 , CSI_72 , CSI_73 , CSI_74 , CSI_75 , CSI_76 , CSI_77 ,
2804     CSI_78 , CSI_79 , CSI_7A , CSI_7B , CSI_7C , CSI_7D , CSI_7E , CSI_7F
2805 pcg 1.1 };
2806    
2807 sf-exg 1.465 #define make_byte(b0,b1,b2,b3,b4,b5,b6,b7) \
2808 pcg 1.1 (((b7) << 7) | ((b6) << 6) | ((b5) << 5) | ((b4) << 4) \
2809     | ((b3) << 3) | ((b2) << 2) | ((b1) << 1) | (b0))
2810     #define get_byte_array_bit(array, bit) \
2811 sf-exg 1.465 (!! ((array)[(bit) >> 3] & (1 << ((bit) & 7))))
2812 pcg 1.1
2813 sf-exg 1.464 static const unsigned char csi_defaults[] =
2814 pcg 1.36 {
2815 pcg 1.43 make_byte (1,1,1,1,1,1,1,1), /* @, A, B, C, D, E, F, G, */
2816     make_byte (1,1,0,0,1,1,0,0), /* H, I, J, K, L, M, N, O, */
2817     make_byte (1,0,1,1,1,1,1,0), /* P, Q, R, S, T, U, V, W, */
2818     make_byte (1,1,1,0,0,0,1,0), /* X, Y, Z, [, \, ], ^, _, */
2819     make_byte (1,1,1,0,1,1,1,0), /* `, a, b, c, d, e, f, g, */
2820     make_byte (0,0,1,1,0,0,0,0), /* h, i, j, k, l, m, n, o, */
2821     make_byte (0,0,0,0,0,0,0,0), /* p, q, r, s, t, u, v, w, */
2822 pcg 1.90 make_byte (0,0,0,0,0,0,0,0), /* x, y, z, {, |, }, ~, */
2823 pcg 1.36 };
2824 pcg 1.1
2825 root 1.512 void ecb_hot
2826 pcg 1.34 rxvt_term::process_csi_seq ()
2827 pcg 1.1 {
2828 sf-exg 1.534 unicode_t ch, priv, prev_ch, i;
2829 pcg 1.81 unsigned int nargs, p;
2830     int n, ndef;
2831 ayin 1.349 int arg[ESC_ARGS] = { };
2832 pcg 1.36
2833 ayin 1.335 nargs = 0;
2834 pcg 1.36
2835     priv = 0;
2836     ch = cmd_getc ();
2837 root 1.423 if ((ch >= '<' && ch <= '?') || ch == '!')
2838 ayin 1.369 {
2839 root 1.423 /* '<' '=' '>' '?' '!' */
2840 pcg 1.36 priv = ch;
2841     ch = cmd_getc ();
2842     }
2843 pcg 1.81
2844 sf-exg 1.534 prev_ch = 0;
2845 pcg 1.36 /* read any numerical arguments */
2846     for (n = -1; ch < CSI_ICH; )
2847     {
2848 pcg 1.43 if (isdigit (ch))
2849 pcg 1.36 {
2850     if (n < 0)
2851     n = ch - '0';
2852     else
2853     n = n * 10 + ch - '0';
2854     }
2855     else if (ch == ';')
2856     {
2857     if (nargs < ESC_ARGS)
2858     arg[nargs++] = n;
2859     n = -1;
2860     }
2861 pcg 1.81 else if (IS_CONTROL (ch))
2862     process_nonprinting (ch);
2863    
2864 sf-exg 1.534 prev_ch = ch;
2865 pcg 1.36 ch = cmd_getc ();
2866     }
2867 pcg 1.1
2868 pcg 1.36 if (ch > CSI_7F)
2869     return;
2870 pcg 1.1
2871 pcg 1.36 if (nargs < ESC_ARGS)
2872     arg[nargs++] = n;
2873    
2874     i = ch - CSI_ICH;
2875 pcg 1.43 ndef = get_byte_array_bit (csi_defaults, i);
2876 pcg 1.36 for (p = 0; p < nargs; p++)
2877     if (arg[p] == -1)
2878     arg[p] = ndef;
2879 pcg 1.1
2880 pcg 1.36 /*
2881     * private mode handling
2882     */
2883     if (priv)
2884     {
2885     switch (priv)
2886     {
2887     case '>':
2888     if (ch == CSI_DA) /* secondary device attributes */
2889 root 1.282 {
2890 ayin 1.334 // first parameter is normally 0 for vt100, 1 for vt220, 'R' for rxvt,
2891 root 1.289 // 'U' for rxvt-unicode != 7.[34] (where it was broken).
2892 root 1.282 //
2893     // second parameter is xterm patch level for xterm, MMmmpp (e.g. 20703) for rxvt
2894 ayin 1.360 // and Mm (e.g. 72 for 7.2) for urxvt <= 7.2, 94 for urxvt <= 8.3, and 95 for later
2895     // versions.
2896 root 1.282 //
2897 ayin 1.360 tt_printf ("\033[>%d;95;0c", 'U');
2898 root 1.282 }
2899 pcg 1.36 break;
2900 root 1.395
2901 pcg 1.36 case '?':
2902     if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
2903     process_terminal_mode (ch, priv, nargs, arg);
2904     break;
2905 root 1.423
2906     case '!':
2907     if (ch == CSI_70)
2908     {
2909     /* DECSTR: soft terminal reset, used by our terminfo since 9.06 */
2910     scr_soft_reset ();
2911    
2912     static const int pm_h[] = { 7, 25 };
2913 root 1.462 static const int pm_l[] = { 1, 3, 4, 5, 6, 9, 66, 1000, 1001, 1005, 1015, 1049 };
2914 root 1.423
2915 sf-exg 1.488 process_terminal_mode ('h', 0, ecb_array_length (pm_h), pm_h);
2916     process_terminal_mode ('l', 0, ecb_array_length (pm_l), pm_l);
2917 root 1.423 }
2918     break;
2919 pcg 1.36 }
2920 root 1.423
2921 pcg 1.36 return;
2922 pcg 1.1 }
2923    
2924 pcg 1.36 switch (ch)
2925     {
2926     /*
2927 pcg 1.43 * ISO/IEC 6429:1992 (E) CSI sequences (defaults in parentheses)
2928 pcg 1.36 */
2929 pcg 1.1 #ifdef PRINTPIPE
2930 pcg 1.36 case CSI_MC: /* 8.3.83: (0) MEDIA COPY */
2931     switch (arg[0])
2932     {
2933     case 0: /* initiate transfer to primary aux device */
2934     scr_printscreen (0);
2935     break;
2936     case 5: /* start relay to primary aux device */
2937     process_print_pipe ();
2938     break;
2939     }
2940     break;
2941     #endif
2942 pcg 1.1
2943 pcg 1.36 case CSI_CUU: /* 8.3.22: (1) CURSOR UP */
2944 root 1.499 case CSI_VPB: /* 8.3.160: (1) LINE POSITION BACKWARD */
2945 pcg 1.36 arg[0] = -arg[0];
2946     /* FALLTHROUGH */
2947     case CSI_CUD: /* 8.3.19: (1) CURSOR DOWN */
2948 root 1.499 case CSI_VPR: /* 8.3.161: (1) LINE POSITION FORWARD */
2949 pcg 1.36 scr_gotorc (arg[0], 0, RELATIVE);
2950     break;
2951    
2952     case CSI_CUB: /* 8.3.18: (1) CURSOR LEFT */
2953     case CSI_HPB: /* 8.3.59: (1) CHARACTER POSITION BACKWARD */
2954 pcg 1.1 #ifdef ISO6429
2955 pcg 1.36 arg[0] = -arg[0];
2956 pcg 1.1 #else /* emulate common DEC VTs */
2957 pcg 1.36 arg[0] = arg[0] ? -arg[0] : -1;
2958 pcg 1.1 #endif
2959 pcg 1.36 /* FALLTHROUGH */
2960     case CSI_CUF: /* 8.3.20: (1) CURSOR RIGHT */
2961     case CSI_HPR: /* 8.3.60: (1) CHARACTER POSITION FORWARD */
2962 pcg 1.1 #ifdef ISO6429
2963 pcg 1.36 scr_gotorc (0, arg[0], RELATIVE);
2964 pcg 1.1 #else /* emulate common DEC VTs */
2965 pcg 1.36 scr_gotorc (0, arg[0] ? arg[0] : 1, RELATIVE);
2966 pcg 1.1 #endif
2967 pcg 1.36 break;
2968    
2969     case CSI_CPL: /* 8.3.13: (1) CURSOR PRECEDING LINE */
2970     arg[0] = -arg[0];
2971     /* FALLTHROUGH */
2972     case CSI_CNL: /* 8.3.12: (1) CURSOR NEXT LINE */
2973     scr_gotorc (arg[0], 0, R_RELATIVE);
2974     break;
2975    
2976     case CSI_CHA: /* 8.3.9: (1) CURSOR CHARACTER ABSOLUTE */
2977     case CSI_HPA: /* 8.3.58: (1) CURSOR POSITION ABSOLUTE */
2978     scr_gotorc (0, arg[0] - 1, R_RELATIVE);
2979     break;
2980    
2981     case CSI_VPA: /* 8.3.159: (1) LINE POSITION ABSOLUTE */
2982     scr_gotorc (arg[0] - 1, 0, C_RELATIVE);
2983     break;
2984    
2985     case CSI_CUP: /* 8.3.21: (1,1) CURSOR POSITION */
2986     case CSI_HVP: /* 8.3.64: (1,1) CHARACTER AND LINE POSITION */
2987     scr_gotorc (arg[0] - 1, nargs < 2 ? 0 : (arg[1] - 1), 0);
2988     break;
2989 pcg 1.1
2990 pcg 1.36 case CSI_CBT: /* 8.3.7: (1) CURSOR BACKWARD TABULATION */
2991     arg[0] = -arg[0];
2992     /* FALLTHROUGH */
2993     case CSI_CHT: /* 8.3.10: (1) CURSOR FORWARD TABULATION */
2994     scr_tab (arg[0]);
2995     break;
2996    
2997     case CSI_ED: /* 8.3.40: (0) ERASE IN PAGE */
2998     scr_erase_screen (arg[0]);
2999     break;
3000    
3001     case CSI_EL: /* 8.3.42: (0) ERASE IN LINE */
3002     scr_erase_line (arg[0]);
3003     break;
3004    
3005     case CSI_ICH: /* 8.3.65: (1) INSERT CHARACTER */
3006     scr_insdel_chars (arg[0], INSERT);
3007     break;
3008    
3009     case CSI_IL: /* 8.3.68: (1) INSERT LINE */
3010     scr_insdel_lines (arg[0], INSERT);
3011     break;
3012    
3013     case CSI_DL: /* 8.3.33: (1) DELETE LINE */
3014     scr_insdel_lines (arg[0], DELETE);
3015     break;
3016    
3017     case CSI_ECH: /* 8.3.39: (1) ERASE CHARACTER */
3018     scr_insdel_chars (arg[0], ERASE);
3019     break;
3020    
3021     case CSI_DCH: /* 8.3.26: (1) DELETE CHARACTER */
3022     scr_insdel_chars (arg[0], DELETE);
3023     break;
3024    
3025     case CSI_SD: /* 8.3.114: (1) SCROLL DOWN */
3026     arg[0] = -arg[0];
3027     /* FALLTHROUGH */
3028     case CSI_SU: /* 8.3.148: (1) SCROLL UP */
3029 root 1.210 scr_scroll_text (screen.tscroll, screen.bscroll, arg[0]);
3030 pcg 1.36 break;
3031    
3032     case CSI_DA: /* 8.3.24: (0) DEVICE ATTRIBUTES */
3033 root 1.234 tt_write (VT100_ANS, sizeof (VT100_ANS) - 1);
3034 pcg 1.36 break;
3035    
3036     case CSI_SGR: /* 8.3.118: (0) SELECT GRAPHIC RENDITION */
3037     process_sgr_mode (nargs, arg);
3038     break;
3039    
3040     case CSI_DSR: /* 8.3.36: (0) DEVICE STATUS REPORT */
3041     switch (arg[0])
3042     {
3043     case 5: /* DSR requested */
3044 pcg 1.43 tt_printf ("\033[0n");
3045 pcg 1.36 break;
3046     case 6: /* CPR requested */
3047     scr_report_position ();
3048     break;
3049     case 7: /* unofficial extension */
3050 root 1.321 if (option (Opt_insecure))
3051 root 1.145 tt_printf ("%-.250s\012", rs[Rs_display_name]);
3052 pcg 1.36 break;
3053     case 8: /* unofficial extension */
3054 pcg 1.90 process_xterm_seq (XTerm_title, RESNAME "-" VERSION, CHAR_ST);
3055 pcg 1.36 break;
3056     }
3057     break;
3058 pcg 1.1
3059 pcg 1.36 case CSI_TBC: /* 8.3.155: (0) TABULATION CLEAR */
3060     switch (arg[0])
3061     {
3062     case 0: /* char tab stop cleared at active position */
3063     scr_set_tab (0);
3064     break;
3065     /* case 1: */ /* line tab stop cleared in active line */
3066     /* case 2: */ /* char tab stops cleared in active line */
3067     case 3: /* all char tab stops are cleared */
3068     /* case 4: */ /* all line tab stops are cleared */
3069     case 5: /* all tab stops are cleared */
3070     scr_set_tab (-1);
3071     break;
3072     }
3073     break;
3074    
3075     case CSI_CTC: /* 8.3.17: (0) CURSOR TABULATION CONTROL */
3076     switch (arg[0])
3077     {
3078     case 0: /* char tab stop set at active position */
3079     scr_set_tab (1);
3080     break; /* = ESC H */
3081     /* case 1: */ /* line tab stop set at active line */
3082     case 2: /* char tab stop cleared at active position */
3083     scr_set_tab (0);
3084     break; /* = ESC [ 0 g */
3085     /* case 3: */ /* line tab stop cleared at active line */
3086     /* case 4: */ /* char tab stops cleared at active line */
3087     case 5: /* all char tab stops are cleared */
3088     scr_set_tab (-1);
3089     break; /* = ESC [ 3 g */
3090     /* case 6: */ /* all line tab stops are cleared */
3091     }
3092     break;
3093    
3094     case CSI_RM: /* 8.3.107: RESET MODE */
3095     if (arg[0] == 4)
3096     scr_insert_mode (0);
3097 root 1.145 else if (arg[0] == 20)
3098     priv_modes &= ~PrivMode_LFNL;
3099 pcg 1.36 break;
3100    
3101     case CSI_SM: /* 8.3.126: SET MODE */
3102     if (arg[0] == 4)
3103     scr_insert_mode (1);
3104 root 1.145 else if (arg[0] == 20)
3105     priv_modes |= PrivMode_LFNL;
3106 pcg 1.36 break;
3107    
3108 sf-exg 1.556 case CSI_71: // DECSCUSR: set cursor style
3109 sf-exg 1.534 if (prev_ch == ' ')
3110     set_cursor_style (arg[0]);
3111     break;
3112    
3113 pcg 1.36 /*
3114     * PRIVATE USE beyond this point. All CSI_7? sequences here
3115     */
3116     case CSI_72: /* DECSTBM: set top and bottom margins */
3117     if (nargs == 1)
3118     scr_scroll_region (arg[0] - 1, MAX_ROWS - 1);
3119     else if (nargs == 0 || arg[0] >= arg[1])
3120     scr_scroll_region (0, MAX_ROWS - 1);
3121     else
3122     scr_scroll_region (arg[0] - 1, arg[1] - 1);
3123     break;
3124    
3125     case CSI_73:
3126     scr_cursor (SAVE);
3127     break;
3128     case CSI_75:
3129     scr_cursor (RESTORE);
3130     break;
3131 pcg 1.1
3132 root 1.294 #if !ENABLE_MINIMAL
3133 pcg 1.36 case CSI_74:
3134     process_window_ops (arg, nargs);
3135     break;
3136 pcg 1.1 #endif
3137    
3138 pcg 1.36 case CSI_78: /* DECREQTPARM */
3139     if (arg[0] == 0 || arg[0] == 1)
3140 pcg 1.43 tt_printf ("\033[%d;1;1;128;128;1;0x", arg[0] + 2);
3141 pcg 1.81 break;
3142 pcg 1.1
3143 pcg 1.36 default:
3144     break;
3145 pcg 1.1 }
3146     }
3147     /*}}} */
3148    
3149 root 1.294 #if !ENABLE_MINIMAL
3150 pcg 1.1 void
3151 pcg 1.34 rxvt_term::process_window_ops (const int *args, unsigned int nargs)
3152 pcg 1.1 {
3153 pcg 1.81 int x, y;
3154 pcg 1.36 XWindowAttributes wattr;
3155 pcg 1.81 Window wdummy;
3156 root 1.285
3157 root 1.305 dLocal (Display *, dpy);
3158 pcg 1.1
3159 pcg 1.36 if (nargs == 0)
3160     return;
3161 pcg 1.81
3162 pcg 1.36 switch (args[0])
3163     {
3164 pcg 1.81 /*
3165     * commands
3166     */
3167 pcg 1.36 case 1: /* deiconify window */
3168 sf-exg 1.482 XMapWindow (dpy, parent);
3169 pcg 1.36 break;
3170     case 2: /* iconify window */
3171 sf-exg 1.482 XIconifyWindow (dpy, parent, display->screen);
3172 pcg 1.36 break;
3173     case 3: /* set position (pixels) */
3174 sf-exg 1.482 XMoveWindow (dpy, parent, args[1], args[2]);
3175 pcg 1.36 break;
3176     case 4: /* set size (pixels) */
3177     set_widthheight ((unsigned int)args[2], (unsigned int)args[1]);
3178     break;
3179     case 5: /* raise window */
3180 sf-exg 1.482 XRaiseWindow (dpy, parent);
3181 pcg 1.36 break;
3182     case 6: /* lower window */
3183 sf-exg 1.482 XLowerWindow (dpy, parent);
3184 pcg 1.36 break;
3185     case 7: /* refresh window */
3186     scr_touch (true);
3187     break;
3188     case 8: /* set size (chars) */
3189 root 1.208 set_widthheight ((unsigned int) (args[2] * fwidth),
3190     (unsigned int) (args[1] * fheight));
3191 pcg 1.36 break;
3192 pcg 1.81
3193     //case 9: NYI, TODO, restore maximized window or maximize window
3194 pcg 1.36 default:
3195     if (args[0] >= 24) /* set height (chars) */
3196 sf-exg 1.504 set_widthheight ((unsigned int)vt_width,
3197 root 1.208 (unsigned int) (args[1] * fheight));
3198 pcg 1.36 break;
3199 pcg 1.81
3200     /*
3201     * reports - some output format copied from XTerm
3202     */
3203 pcg 1.36 case 11: /* report window state */
3204 sf-exg 1.482 XGetWindowAttributes (dpy, parent, &wattr);
3205 pcg 1.43 tt_printf ("\033[%dt", wattr.map_state == IsViewable ? 1 : 2);
3206 pcg 1.36 break;
3207     case 13: /* report window position */
3208 sf-exg 1.482 XGetWindowAttributes (dpy, parent, &wattr);
3209     XTranslateCoordinates (dpy, parent, wattr.root,
3210 pcg 1.90 -wattr.border_width, -wattr.border_width,
3211     &x, &y, &wdummy);
3212 pcg 1.43 tt_printf ("\033[3;%d;%dt", x, y);
3213 pcg 1.36 break;
3214     case 14: /* report window size (pixels) */
3215 sf-exg 1.482 XGetWindowAttributes (dpy, parent, &wattr);
3216 pcg 1.43 tt_printf ("\033[4;%d;%dt", wattr.height, wattr.width);
3217 pcg 1.36 break;
3218 pcg 1.81 case 18: /* report text area size (chars) */
3219 root 1.208 tt_printf ("\033[8;%d;%dt", nrow, ncol);
3220 pcg 1.36 break;
3221 pcg 1.81 case 19: /* report window size (chars) */
3222 root 1.208 tt_printf ("\033[9;%d;%dt", nrow, ncol);
3223 pcg 1.81 break;
3224 pcg 1.36 case 20: /* report icon label */
3225 root 1.131 {
3226     char *s;
3227 sf-exg 1.482 XGetIconName (dpy, parent, &s);
3228 root 1.321 tt_printf ("\033]L%-.250s\234", option (Opt_insecure) && s ? s : ""); /* 8bit ST */
3229 root 1.131 XFree (s);
3230     }
3231 pcg 1.36 break;
3232     case 21: /* report window title */
3233 root 1.131 {
3234     char *s;
3235 sf-exg 1.482 XFetchName (dpy, parent, &s);
3236 root 1.321 tt_printf ("\033]l%-.250s\234", option (Opt_insecure) && s ? s : ""); /* 8bit ST */
3237 root 1.131 XFree (s);
3238     }
3239 pcg 1.36 break;
3240 pcg 1.1 }
3241     }
3242     #endif
3243    
3244     /*----------------------------------------------------------------------*/
3245     /*
3246     * get input up until STRING TERMINATOR (or BEL)
3247 pcg 1.93 * ends_how is terminator used. returned input must be free()'d
3248 pcg 1.1 */
3249 root 1.234 char *
3250 pcg 1.81 rxvt_term::get_to_st (unicode_t &ends_how)
3251 pcg 1.1 {
3252 root 1.175 unicode_t ch;
3253     bool seen_esc = false;
3254 pcg 1.81 unsigned int n = 0;
3255 root 1.541 wchar_t string[CBUFSIZ];
3256 pcg 1.36
3257 root 1.97 while ((ch = cmd_getc ()) != NOCHAR)
3258 pcg 1.36 {
3259 root 1.163 if (seen_esc)
3260 pcg 1.36 {
3261 root 1.97 if (ch == 0x5c) /* 7bit ST */
3262     break;
3263     else
3264     return NULL;
3265 pcg 1.36 }
3266 root 1.163 else if (ch == C0_ESC)
3267     {
3268 root 1.175 seen_esc = true;
3269 root 1.163 continue;
3270     }
3271 root 1.97 else if (ch == C0_BEL || ch == CHAR_ST)
3272     break;
3273 root 1.315 else if (ch == C0_SYN)
3274     ch = cmd_get8 ();
3275 root 1.97 else if (ch < 0x20)
3276 pcg 1.36 return NULL; /* other control character - exit */
3277 pcg 1.81
3278 root 1.175 seen_esc = false;
3279 root 1.163
3280 root 1.541 if (n >= sizeof (string) - 1)
3281 pcg 1.90 // stop at some sane length
3282     return NULL;
3283 pcg 1.81
3284 root 1.315 string[n++] = ch;
3285 pcg 1.36 }
3286 pcg 1.81
3287 pcg 1.36 string[n++] = '\0';
3288 pcg 1.81
3289 root 1.175 ends_how = (ch == 0x5c ? C0_ESC : ch);
3290 pcg 1.81
3291 root 1.234 return rxvt_wcstombs (string);
3292 pcg 1.1 }
3293    
3294     /*----------------------------------------------------------------------*/
3295     /*
3296     * process DEVICE CONTROL STRING `ESC P ... (ST|BEL)' or `0x90 ... (ST|BEL)'
3297     */
3298     void
3299 pcg 1.34 rxvt_term::process_dcs_seq ()
3300 pcg 1.1 {
3301 pcg 1.36 /*
3302     * Not handled yet
3303     */
3304 root 1.451
3305     unicode_t eh;
3306     char *s = get_to_st (eh);
3307 pcg 1.36 if (s)
3308 pcg 1.43 free (s);
3309 pcg 1.81
3310 pcg 1.36 return;
3311 pcg 1.1 }
3312    
3313     /*----------------------------------------------------------------------*/
3314     /*
3315     * process OPERATING SYSTEM COMMAND sequence `ESC ] Ps ; Pt (ST|BEL)'
3316     */
3317     void
3318 pcg 1.34 rxvt_term::process_osc_seq ()
3319 pcg 1.1 {
3320 pcg 1.81 int arg;
3321 pcg 1.1
3322 root 1.451 unicode_t ch = cmd_getc ();
3323 pcg 1.43 for (arg = 0; isdigit (ch); ch = cmd_getc ())
3324 pcg 1.36 arg = arg * 10 + (ch - '0');
3325 pcg 1.1
3326 pcg 1.36 if (ch == ';')
3327     {
3328 root 1.451 unicode_t eh;
3329 root 1.234 char *s = get_to_st (eh);
3330 pcg 1.81
3331 pcg 1.36 if (s)
3332     {
3333 root 1.234 process_xterm_seq (arg, s, eh);
3334 pcg 1.90 free (s);
3335     }
3336     }
3337     }
3338 pcg 1.81
3339 sf-exg 1.570 /*
3340     * Find the nearest color slot in the hidden color cube,
3341     * adapt its value to the 24bit RGB color.
3342     */
3343     unsigned int
3344     rxvt_term::map_rgb24_color (unsigned int r, unsigned int g, unsigned int b)
3345     {
3346     unsigned int idx_r = (r & 0xff) / (0xff / (Red_levels - 1));
3347     unsigned int idx_g = (g & 0xff) / (0xff / (Green_levels - 1));
3348     unsigned int idx_b = (b & 0xff) / (0xff / (Blue_levels - 1));
3349     unsigned int idx;
3350    
3351     idx = minTermCOLOR24 + idx_r * Blue_levels * Green_levels +
3352     idx_g * Blue_levels +
3353     idx_b;
3354    
3355     pix_colors_focused [idx].free (this);
3356     pix_colors_focused [idx].set (this, rgba (r * 0x0101,
3357     g * 0x0101,
3358     b * 0x0101));
3359     update_fade_color (idx, false);
3360    
3361     return idx;
3362     }
3363    
3364 pcg 1.90 void
3365 root 1.234 rxvt_term::process_color_seq (int report, int color, const char *str, char resp)
3366 pcg 1.90 {
3367     if (str[0] == '?' && !str[1])
3368     {
3369 root 1.298 rgba c;
3370 root 1.300 pix_colors_focused[color].get (c);
3371 root 1.291
3372     #if XFT
3373 root 1.298 if (c.a != rgba::MAX_CC)
3374 sf-exg 1.567 tt_printf ("\033]%d;rgba:%04x/%04x/%04x/%04x%c", report, c.r, c.g, c.b, c.a, resp);
3375 root 1.291 else
3376     #endif
3377     tt_printf ("\033]%d;rgb:%04x/%04x/%04x%c", report, c.r, c.g, c.b, resp);
3378 pcg 1.1 }
3379 pcg 1.90 else
3380     set_window_color (color, str);
3381 pcg 1.1 }
3382 pcg 1.90
3383 pcg 1.1 /*
3384     * XTerm escape sequences: ESC ] Ps;Pt (ST|BEL)
3385     */
3386     void
3387 sf-exg 1.468 rxvt_term::process_xterm_seq (int op, char *str, char resp)
3388 pcg 1.1 {
3389 pcg 1.81 int color;
3390     char *buf, *name;
3391 pcg 1.90 bool query = str[0] == '?' && !str[1];
3392 root 1.163 int saveop = op;
3393 root 1.285
3394 root 1.305 dLocal (Display *, dpy);
3395 pcg 1.36
3396 pcg 1.43 assert (str != NULL);
3397 ayin 1.329
3398 root 1.311 if (HOOK_INVOKE ((this, HOOK_OSC_SEQ, DT_INT, op, DT_STR, str, DT_END)))
3399 root 1.312 return;
3400 root 1.311
3401 pcg 1.36 switch (op)
3402     {
3403     case XTerm_name:
3404     set_title (str);
3405     /* FALLTHROUGH */
3406     case XTerm_iconName:
3407 pcg 1.81 set_icon_name (str);
3408 pcg 1.36 break;
3409     case XTerm_title:
3410     set_title (str);
3411     break;
3412 pcg 1.90 case XTerm_property:
3413     if (str[0] == '?')
3414     {
3415 root 1.175 Atom prop = display->atom (str + 1);
3416 pcg 1.90 Atom actual_type;
3417     int actual_format;
3418     unsigned long nitems;
3419     unsigned long bytes_after;
3420     unsigned char *value = 0;
3421     const char *str = "";
3422    
3423     if (prop
3424 sf-exg 1.482 && XGetWindowProperty (dpy, parent,
3425 pcg 1.90 prop, 0, 1<<16, 0, AnyPropertyType,
3426     &actual_type, &actual_format,
3427     &nitems, &bytes_after, &value) == Success
3428     && actual_type != None
3429     && actual_format == 8)
3430     str = (const char *)(value);
3431    
3432 root 1.542 tt_printf ("\033]%d;%s%c", op, option (Opt_insecure) ? str : "", resp);
3433 pcg 1.90
3434     XFree (value);
3435     }
3436     else
3437     {
3438 root 1.433 char *eq = strchr (str, '=');
3439 pcg 1.90
3440     if (eq)
3441     {
3442     *eq = 0;
3443 root 1.175 set_utf8_property (display->atom (str), eq + 1);
3444 pcg 1.90 }
3445     else
3446 sf-exg 1.482 XDeleteProperty (dpy, parent,
3447 pcg 1.90 display->atom (str));
3448     }
3449     break;
3450    
3451 pcg 1.36 case XTerm_Color:
3452     for (buf = (char *)str; buf && *buf;)
3453     {
3454 root 1.145 if ((name = strchr (buf, ';')) == NULL)
3455 pcg 1.36 break;
3456 pcg 1.81
3457 pcg 1.36 *name++ = '\0';
3458 root 1.256 color = atoi (buf) + minCOLOR;
3459 pcg 1.81
3460 root 1.257 if (!IN_RANGE_INC (color, minCOLOR, maxTermCOLOR))
3461 pcg 1.36 break;
3462 pcg 1.81
3463 root 1.145 if ((buf = strchr (name, ';')) != NULL)
3464 pcg 1.36 *buf++ = '\0';
3465 pcg 1.81
3466 root 1.291 process_color_seq (op, color, name, resp);
3467 pcg 1.36 }
3468     break;
3469 ayin 1.394 case Rxvt_restoreFG:
3470 pcg 1.90 case XTerm_Color00:
3471 root 1.290 process_color_seq (op, Color_fg, str, resp);
3472 pcg 1.90 break;
3473 ayin 1.394 case Rxvt_restoreBG:
3474 pcg 1.90 case XTerm_Color01:
3475 root 1.290 process_color_seq (op, Color_bg, str, resp);
3476 pcg 1.90 break;
3477 pcg 1.1 #ifndef NO_CURSORCOLOR
3478 pcg 1.36 case XTerm_Color_cursor:
3479 root 1.290 process_color_seq (op, Color_cursor, str, resp);
3480 pcg 1.36 break;
3481     #endif
3482 pcg 1.90 case XTerm_Color_pointer_fg:
3483 root 1.290 process_color_seq (op, Color_pointer_fg, str, resp);
3484 pcg 1.90 break;
3485     case XTerm_Color_pointer_bg:
3486 root 1.290 process_color_seq (op, Color_pointer_bg, str, resp);
3487 pcg 1.36 break;
3488 sf-exg 1.448 #ifdef OPTION_HC
3489     case XTerm_Color_HC:
3490     process_color_seq (op, Color_HC, str, resp);
3491     break;
3492 sf-exg 1.450 case XTerm_Color_HTC:
3493     process_color_seq (op, Color_HTC, str, resp);
3494     break;
3495 sf-exg 1.448 #endif
3496 pcg 1.1 #ifndef NO_BOLD_UNDERLINE_REVERSE
3497 root 1.257 case URxvt_Color_BD:
3498     process_color_seq (op, Color_BD, str, resp);
3499     break;
3500     case URxvt_Color_UL:
3501     process_color_seq (op, Color_UL, str, resp);
3502     break;
3503 root 1.201 case URxvt_Color_IT:
3504 root 1.290 process_color_seq (op, Color_IT, str, resp);
3505 root 1.201 break;
3506 pcg 1.1 #endif
3507 root 1.427 case URxvt_Color_border:
3508     process_color_seq (op, Color_border, str, resp);
3509     break;
3510 sf-exg 1.527
3511     #if BG_IMAGE_FROM_ROOT
3512 root 1.201 case URxvt_Color_tint:
3513 root 1.290 process_color_seq (op, Color_tint, str, resp);
3514 sasha 1.343 {
3515     bool changed = false;
3516 root 1.385
3517 sasha 1.343 if (ISSET_PIXCOLOR (Color_tint))
3518 sf-exg 1.513 changed = root_effects.set_tint (pix_colors_focused [Color_tint]);
3519 root 1.385
3520 sasha 1.343 if (changed)
3521 sasha 1.348 update_background ();
3522 sasha 1.343 }
3523 root 1.297
3524 root 1.163 break;
3525     #endif
3526 pcg 1.1
3527 sasha 1.354 #if BG_IMAGE_FROM_FILE
3528 root 1.257 case Rxvt_Pixmap:
3529 sasha 1.343 if (!strcmp (str, "?"))
3530     {
3531     char str[256];
3532 sf-exg 1.518 int h_scale = fimage.h_scale;
3533     int v_scale = fimage.v_scale;
3534     int h_align = fimage.h_align;
3535     int v_align = fimage.v_align;
3536 root 1.271
3537 sf-exg 1.437 sprintf (str, "[%dx%d+%d+%d]",
3538 sf-exg 1.510 h_scale, v_scale,
3539     h_align, v_align);
3540 sasha 1.343 process_xterm_seq (XTerm_title, str, CHAR_ST);
3541     }
3542     else
3543     {
3544 sf-exg 1.493 bool changed = false;
3545 root 1.256
3546 sasha 1.343 if (*str != ';')
3547     {
3548 sf-exg 1.522 try
3549     {
3550     fimage.set_file_geometry (this, str);
3551     changed = true;
3552     }
3553     catch (const class rxvt_failure_exception &e)
3554     {
3555     }
3556 sasha 1.343 }
3557 sf-exg 1.458 else
3558 sasha 1.343 {
3559     str++;
3560 sf-exg 1.518 if (fimage.set_geometry (str, true))
3561     changed = true;
3562 sasha 1.343 }
3563 root 1.385
3564 sasha 1.343 if (changed)
3565 sf-exg 1.460 {
3566 sf-exg 1.473 if (bg_window_position_sensitive ())
3567 sf-exg 1.460 {
3568     int x, y;
3569     get_window_origin (x, y);
3570 sf-exg 1.521 parent_x = x;
3571     parent_y = y;
3572 sf-exg 1.460 }
3573     update_background ();
3574     }
3575 sasha 1.343 }
3576 pcg 1.36 break;
3577 ayin 1.339 #endif
3578 pcg 1.36
3579     case XTerm_logfile:
3580 pcg 1.81 // TODO, when secure mode?
3581 pcg 1.36 break;
3582 pcg 1.90
3583 root 1.201 #if 0
3584 root 1.257 case Rxvt_dumpscreen: /* no error notices */
3585 root 1.201 {
3586     int fd;
3587     if ((fd = open (str, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0)
3588     {
3589     scr_dump (fd);
3590     close (fd);
3591     }
3592     }
3593     break;
3594     #endif
3595 pcg 1.36 case XTerm_font:
3596 root 1.163 op = URxvt_font;
3597     case URxvt_font:
3598     #if ENABLE_STYLES
3599     case URxvt_boldFont:
3600     case URxvt_italicFont:
3601     case URxvt_boldItalicFont:
3602     #endif
3603 pcg 1.90 if (query)
3604 root 1.163 tt_printf ("\33]%d;%-.250s%c", saveop,
3605 root 1.321 option (Opt_insecure) && fontset[op - URxvt_font]->fontdesc
3606 root 1.208 ? fontset[op - URxvt_font]->fontdesc : "",
3607 root 1.131 resp);
3608 pcg 1.90 else
3609 root 1.163 {
3610     const char *&res = rs[Rs_font + (op - URxvt_font)];
3611    
3612     res = strdup (str);
3613     allocated.push_back ((void *)res);
3614     set_fonts ();
3615     }
3616 pcg 1.51 break;
3617 pcg 1.90
3618 root 1.288 case URxvt_version:
3619     if (query)
3620     tt_printf ("\33]%d;rxvt-unicode;%-.20s;%c;%c%c",
3621 root 1.290 op,
3622     rs[Rs_name], VERSION[0], VERSION[2],
3623 root 1.288 resp);
3624     break;
3625    
3626 root 1.294 #if !ENABLE_MINIMAL
3627 root 1.201 case URxvt_locale:
3628 pcg 1.90 if (query)
3629 root 1.321 tt_printf ("\33]%d;%-.250s%c", op, option (Opt_insecure) ? locale : "", resp);
3630 pcg 1.54 else
3631     {
3632     set_locale (str);
3633 root 1.269 pty->set_utf8_mode (enc_utf8);
3634 root 1.199 init_xlocale ();
3635 pcg 1.54 }
3636 pcg 1.36 break;
3637 pcg 1.90
3638 root 1.201 case URxvt_view_up:
3639     case URxvt_view_down:
3640 root 1.231 {
3641     int lines = atoi (str);
3642 root 1.201
3643 root 1.231 if (lines)
3644     scr_page (op == URxvt_view_up ? UP : DN, lines);
3645     else
3646     scr_erase_savelines ();
3647     }
3648 root 1.230
3649     break;
3650     #endif
3651 root 1.201
3652 root 1.230 #if ENABLE_PERL
3653     case URxvt_perl:
3654 root 1.418 HOOK_INVOKE ((this, HOOK_OSC_SEQ_PERL, DT_STR, str, DT_STR_LEN, &resp, 1, DT_END));
3655 pcg 1.36 break;
3656 pcg 1.1 #endif
3657     }
3658     }
3659     /*----------------------------------------------------------------------*/
3660    
3661     /*{{{ process DEC private mode sequences `ESC [ ? Ps mode' */
3662     /*
3663     * mode can only have the following values:
3664     * 'l' = low
3665     * 'h' = high
3666     * 's' = save
3667     * 'r' = restore
3668     * 't' = toggle
3669     * so no need for fancy checking
3670     */
3671 root 1.512 int ecb_cold
3672 pcg 1.34 rxvt_term::privcases (int mode, unsigned long bit)
3673 pcg 1.1 {
3674 pcg 1.81 int state;
3675 pcg 1.1
3676 pcg 1.36 if (mode == 's')
3677     {
3678 sf-exg 1.508 if (priv_modes & bit)
3679     SavedModes |= bit;
3680     else
3681     SavedModes &= ~bit;
3682 pcg 1.36 return -1;
3683 pcg 1.1 }
3684 pcg 1.36 else
3685     {
3686     if (mode == 'r')
3687     state = (SavedModes & bit) ? 1 : 0; /* no overlapping */
3688     else
3689 root 1.145 state = (mode == 't') ? ! (priv_modes & bit) : mode;
3690 root 1.451
3691 sf-exg 1.496 if (state)
3692     priv_modes |= bit;
3693     else
3694     priv_modes &= ~bit;
3695 pcg 1.36 }
3696 pcg 1.81
3697 pcg 1.36 return state;
3698 pcg 1.1 }
3699    
3700     /* we're not using priv _yet_ */
3701     void
3702 sf-exg 1.488 rxvt_term::process_terminal_mode (int mode, int priv ecb_unused, unsigned int nargs, const int *arg)
3703 pcg 1.1 {
3704 pcg 1.81 unsigned int i, j;
3705     int state;
3706    
3707 pcg 1.36 static const struct
3708 root 1.344 {
3709     const int argval;
3710     const unsigned long bit;
3711     } argtopriv[] = {
3712 root 1.425 { 1, PrivMode_aplCUR }, // DECCKM
3713 sf-exg 1.490 { 2, PrivMode_vt52 }, // DECANM
3714 root 1.425 { 3, PrivMode_132 }, // DECCOLM
3715     { 4, PrivMode_smoothScroll }, // DECSCLM
3716     { 5, PrivMode_rVideo }, // DECSCNM
3717     { 6, PrivMode_relOrigin }, // DECOM
3718     { 7, PrivMode_Autowrap }, // DECAWM
3719     // 8, auto-repeat keys // DECARM
3720 pcg 1.36 { 9, PrivMode_MouseX10 },
3721 sf-exg 1.560 { 12, PrivMode_BlinkingCursor },
3722 root 1.426 // 18 end FF to printer after print screen
3723 sf-exg 1.454 // 19 Print screen prints full screen/scroll region
3724 sf-exg 1.490 { 25, PrivMode_VisibleCursor }, // DECTCEM cnorm/cvvis/civis
3725 pcg 1.1 #ifdef scrollBar_esc
3726 pcg 1.36 { scrollBar_esc, PrivMode_scrollBar },
3727 pcg 1.1 #endif
3728 root 1.425 { 35, PrivMode_ShiftKeys }, // rxvt extension
3729     // 38, tektronix mode // DECTEK
3730 pcg 1.36 { 40, PrivMode_132OK },
3731 pcg 1.73 // 41 xterm more fixes NYI
3732     // 45 margin bell NYI
3733     // 46 start logging
3734 pcg 1.36 { 47, PrivMode_Screen },
3735 sf-exg 1.490 { 66, PrivMode_aplKP }, // DECNKM
3736 pcg 1.1 #ifndef NO_BACKSPACE_KEY
3737 root 1.425 { 67, PrivMode_BackSpace }, // DECBKM
3738 pcg 1.1 #endif
3739 pcg 1.36 { 1000, PrivMode_MouseX11 },
3740 ayin 1.360 { 1002, PrivMode_MouseBtnEvent },
3741     { 1003, PrivMode_MouseAnyEvent },
3742 root 1.461 #if ENABLE_FRILLS
3743 sf-exg 1.569 { 1004, PrivMode_FocusEvent },
3744 root 1.461 { 1005, PrivMode_ExtModeMouse },
3745     #endif
3746 pcg 1.73 { 1010, PrivMode_TtyOutputInh }, // rxvt extension
3747     { 1011, PrivMode_Keypress }, // rxvt extension
3748 root 1.461 #if ENABLE_FRILLS
3749     { 1015, PrivMode_ExtMouseRight }, // urxvt extension of 1005
3750     #endif
3751 pcg 1.73 // 1035 enable modifiers for alt, numlock NYI
3752     // 1036 send ESC for meta keys NYI
3753     // 1037 send DEL for keypad delete NYI
3754 pcg 1.36 { 1047, PrivMode_Screen },
3755 root 1.461 // 1048 save and restore cursor, implemented in code
3756 pcg 1.90 { 1049, PrivMode_Screen }, /* xterm extension, clear screen on ti rather than te */
3757 pcg 1.73 // 1051, 1052, 1060, 1061 keyboard emulation NYI
3758 ayin 1.396 { 2004, PrivMode_BracketPaste },
3759 pcg 1.36 };
3760    
3761     if (nargs == 0)
3762     return;
3763    
3764     /* make lo/hi boolean */
3765     if (mode == 'l')
3766     mode = 0; /* reset */
3767     else if (mode == 'h')
3768     mode = 1; /* set */
3769    
3770     for (i = 0; i < nargs; i++)
3771     {
3772     state = -1;
3773    
3774     /* basic handling */
3775 sf-exg 1.488 for (j = 0; j < ecb_array_length (argtopriv); j++)
3776 pcg 1.36 if (argtopriv[j].argval == arg[i])
3777     {
3778     state = privcases (mode, argtopriv[j].bit);
3779     break;
3780     }
3781 pcg 1.1
3782 pcg 1.36 /* extra handling for values with state unkept */
3783 pcg 1.73 switch (arg[i])
3784     {
3785 root 1.220 #if ENABLE_STYLES
3786     case 1021:
3787 root 1.249 set_option (Opt_intensityStyles, mode);
3788 root 1.222
3789 root 1.225 scr_touch (true);
3790 root 1.222 break;
3791 root 1.220 #endif
3792 pcg 1.73 case 1048: /* alternative cursor save */
3793 root 1.321 if (option (Opt_secondaryScreen))
3794 pcg 1.90 if (mode == 0)
3795     scr_cursor (RESTORE);
3796     else if (mode == 1)
3797     scr_cursor (SAVE);
3798     break;
3799 pcg 1.73 }
3800    
3801     if (state >= 0)
3802     /* extra handling for values with valid 0 or 1 state */
3803 pcg 1.36 switch (arg[i])
3804     {
3805 pcg 1.73 /* case 1: - application cursor keys */
3806     case 2: /* VT52 mode */
3807     /* oddball mode. should be set regardless of set/reset
3808     * parameter. Return from VT52 mode with an ESC < from
3809     * within VT52 mode
3810     */
3811 sf-exg 1.496 priv_modes |= PrivMode_vt52;
3812 pcg 1.73 break;
3813     case 3: /* 80/132 */
3814 root 1.145 if (priv_modes & PrivMode_132OK)
3815 root 1.425 set_widthheight ((state ? 132 : 80) * fwidth, 24 * fheight);
3816 pcg 1.73 break;
3817     case 4: /* smooth scrolling */
3818 root 1.249 set_option (Opt_jumpScroll, !state);
3819 pcg 1.73 break;
3820     case 5: /* reverse video */
3821     scr_rvideo_mode (state);
3822     break;
3823     case 6: /* relative/absolute origins */
3824     scr_relative_origin (state);
3825     break;
3826     case 7: /* autowrap */
3827     scr_autowrap (state);
3828     break;
3829 pcg 1.90 /* case 8: - auto repeat, can't do on a per window basis */
3830 pcg 1.73 case 9: /* X10 mouse reporting */
3831     if (state) /* orthogonal */
3832 ayin 1.360 priv_modes &= ~(PrivMode_MouseX11|PrivMode_MouseBtnEvent|PrivMode_MouseAnyEvent);
3833 pcg 1.73 break;
3834 pcg 1.1 #ifdef scrollBar_esc
3835 pcg 1.73 case scrollBar_esc:
3836 sf-exg 1.495 scrollBar.map (state);
3837     resize_all_windows (0, 0, 0);
3838     scr_touch (true);
3839 pcg 1.73 break;
3840 pcg 1.1 #endif
3841 sf-exg 1.560 #ifdef CURSOR_BLINK
3842     case 12:
3843     cursor_blink_reset ();
3844     break;
3845     #endif
3846 pcg 1.73 case 25: /* visible/invisible cursor */
3847     scr_cursor_visible (state);
3848     break;
3849 pcg 1.90 /* case 35: - shift keys */
3850     /* case 40: - 80 <--> 132 mode */
3851 pcg 1.73 case 47: /* secondary screen */
3852     scr_change_screen (state);
3853     break;
3854 pcg 1.90 /* case 66: - application key pad */
3855     /* case 67: - backspace key */
3856 pcg 1.73 case 1000: /* X11 mouse reporting */
3857     if (state) /* orthogonal */
3858 ayin 1.360 priv_modes &= ~(PrivMode_MouseX10|PrivMode_MouseBtnEvent|PrivMode_MouseAnyEvent);
3859 pcg 1.73 break;
3860 ayin 1.360 case 1002:
3861     case 1003:
3862 ayin 1.365 if (state)
3863     {
3864     priv_modes &= ~(PrivMode_MouseX10|PrivMode_MouseX11);
3865     priv_modes &= arg[i] == 1003 ? ~PrivMode_MouseBtnEvent : ~PrivMode_MouseAnyEvent;
3866 root 1.462 mouse_row = mouse_col = 0;
3867 ayin 1.365 vt_emask_mouse = PointerMotionMask;
3868     }
3869     else
3870 ayin 1.360 vt_emask_mouse = NoEventMask;
3871 root 1.425
3872 ayin 1.360 vt_select_input ();
3873     break;
3874 pcg 1.73 case 1010: /* scroll to bottom on TTY output inhibit */
3875 root 1.249 set_option (Opt_scrollTtyOutput, !state);
3876 pcg 1.73 break;
3877     case 1011: /* scroll to bottom on key press */
3878 root 1.249 set_option (Opt_scrollTtyKeypress, state);
3879 pcg 1.73 break;
3880 pcg 1.90 case 1047: /* secondary screen w/ clearing last */
3881 root 1.321 if (option (Opt_secondaryScreen))
3882 root 1.428 if (!state)
3883 pcg 1.90 scr_erase_screen (2);
3884 root 1.425
3885 pcg 1.90 scr_change_screen (state);
3886     break;
3887     case 1049: /* secondary screen w/ clearing first */
3888 root 1.429 if (option (Opt_secondaryScreen))
3889     if (state)
3890     scr_cursor (SAVE);
3891 root 1.428
3892 pcg 1.73 scr_change_screen (state);
3893 root 1.428
3894 root 1.429 if (option (Opt_secondaryScreen))
3895     if (state)
3896     scr_erase_screen (2);
3897     else
3898     scr_cursor (RESTORE);
3899 pcg 1.90 break;
3900 pcg 1.73 default:
3901     break;
3902     }
3903 pcg 1.1 }
3904     }
3905     /*}}} */
3906    
3907     /*{{{ process sgr sequences */
3908 root 1.512 void ecb_hot
3909 pcg 1.34 rxvt_term::process_sgr_mode (unsigned int nargs, const int *arg)
3910 pcg 1.1 {
3911 pcg 1.81 unsigned int i;
3912     short rendset;
3913     int rendstyle;
3914 pcg 1.36
3915     if (nargs == 0)
3916     {
3917     scr_rendition (0, ~RS_None);
3918     return;
3919     }
3920 pcg 1.81
3921 pcg 1.36 for (i = 0; i < nargs; i++)
3922     {
3923     rendset = -1;
3924     switch (arg[i])
3925     {
3926     case 0:
3927     rendset = 0, rendstyle = ~RS_None;
3928     break;
3929     case 1:
3930     rendset = 1, rendstyle = RS_Bold;
3931     break;
3932 root 1.163 //case 2: // low intensity
3933     case 3:
3934     rendset = 1, rendstyle = RS_Italic;
3935     break;
3936 pcg 1.36 case 4:
3937     rendset = 1, rendstyle = RS_Uline;
3938     break;
3939 root 1.107 case 5: // slowly blinking
3940     case 6: // rapidly blinking
3941 pcg 1.36 rendset = 1, rendstyle = RS_Blink;
3942     break;
3943 pcg 1.93 //case 6: // scoansi light background
3944 pcg 1.36 case 7:
3945     rendset = 1, rendstyle = RS_RVid;
3946     break;
3947 pcg 1.73 case 8:
3948     // invisible. NYI
3949     break;
3950 root 1.107 //case 9: // crossed out
3951     //case 10: // scoansi acs off, primary font
3952     //case 11: // scoansi acs on, first alt font
3953     //case 12: // scoansi acs on, |0x80, second alt font
3954     //...
3955     //case 19: // ninth alt font
3956     //case 20: // gothic
3957 root 1.163 case 21: // disable bold, faint, sometimes doubly underlined (iso 8613)
3958 root 1.107 rendset = 0, rendstyle = RS_Bold;
3959 pcg 1.93 break;
3960 root 1.562 case 22: // bold off (vt220)
3961 pcg 1.36 rendset = 0, rendstyle = RS_Bold;
3962     break;
3963 root 1.163 case 23: // disable italic
3964     rendset = 0, rendstyle = RS_Italic;
3965     break;
3966 root 1.562 case 24: // underline off (vt220)
3967 pcg 1.36 rendset = 0, rendstyle = RS_Uline;
3968     break;
3969 root 1.562 case 25: // blink off (vt220)
3970 pcg 1.36 rendset = 0, rendstyle = RS_Blink;
3971     break;
3972 root 1.163 case 26: // variable spacing (iso 8613)
3973 root 1.145 rendset = 0, rendstyle = RS_Blink;
3974     break;
3975 root 1.562 case 27: // reverse off (vt220)
3976 pcg 1.36 rendset = 0, rendstyle = RS_RVid;
3977     break;
3978 root 1.107 //case 28: // visible. NYI
3979     //case 29: // not crossed-out
3980 pcg 1.36 }
3981 pcg 1.73
3982 pcg 1.36 if (rendset != -1)
3983     {
3984     scr_rendition (rendset, rendstyle);
3985 pcg 1.43 continue; /* for (;i;) */
3986 pcg 1.36 }
3987    
3988     switch (arg[i])
3989     {
3990     case 30:
3991     case 31: /* set fg color */
3992     case 32:
3993     case 33:
3994     case 34:
3995     case 35:
3996     case 36:
3997     case 37:
3998 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 30)), Color_fg);
3999 pcg 1.36 break;
4000 root 1.163 case 38: // set fg color, ISO 8613-6
4001 pcg 1.36 if (nargs > i + 2 && arg[i + 1] == 5)
4002     {
4003 pcg 1.73 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_fg);
4004 pcg 1.36 i += 2;
4005     }
4006 sf-exg 1.570 else if (nargs > i + 4 && arg[i + 1] == 2)
4007     {
4008     unsigned int r = arg[i + 2];
4009     unsigned int g = arg[i + 3];
4010     unsigned int b = arg[i + 4];
4011     unsigned int idx = map_rgb24_color (r, g, b);
4012     scr_color (idx, Color_fg);
4013     i += 4;
4014     }
4015 pcg 1.36 break;
4016     case 39: /* default fg */
4017     scr_color (Color_fg, Color_fg);
4018     break;
4019    
4020     case 40:
4021     case 41: /* set bg color */
4022     case 42:
4023     case 43:
4024     case 44:
4025     case 45:
4026     case 46:
4027     case 47:
4028 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 40)), Color_bg);
4029 pcg 1.36 break;
4030 root 1.163 case 48: // set bg color, ISO 8613-6
4031 pcg 1.36 if (nargs > i + 2 && arg[i + 1] == 5)
4032     {
4033 pcg 1.73 scr_color ((unsigned int) (minCOLOR + arg[i + 2]), Color_bg);
4034 pcg 1.36 i += 2;
4035     }
4036 sf-exg 1.570 else if (nargs > i + 4 && arg[i + 1] == 2)
4037     {
4038     unsigned int r = arg[i + 2];
4039     unsigned int g = arg[i + 3];
4040     unsigned int b = arg[i + 4];
4041     unsigned int idx = map_rgb24_color (r, g, b);
4042     scr_color (idx, Color_bg);
4043     i += 4;
4044     }
4045 pcg 1.36 break;
4046     case 49: /* default bg */
4047     scr_color (Color_bg, Color_bg);
4048     break;
4049 pcg 1.1
4050 root 1.163 //case 50: // not variable spacing
4051    
4052 root 1.294 #if !ENABLE_MINIMAL
4053 pcg 1.36 case 90:
4054     case 91: /* set bright fg color */
4055     case 92:
4056     case 93:
4057     case 94:
4058     case 95:
4059     case 96:
4060     case 97:
4061 root 1.163 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 90)), Color_fg);
4062 pcg 1.36 break;
4063     case 100:
4064     case 101: /* set bright bg color */
4065     case 102:
4066     case 103:
4067     case 104:
4068     case 105:
4069     case 106:
4070     case 107:
4071 root 1.163 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 100)), Color_bg);
4072 pcg 1.36 break;
4073 pcg 1.1 #endif
4074 pcg 1.36 }
4075 pcg 1.1 }
4076     }
4077 sf-exg 1.534
4078     void
4079     rxvt_term::set_cursor_style (int style)
4080     {
4081 sf-exg 1.557 if (!IN_RANGE_INC (style, 0, 6))
4082 sf-exg 1.534 return;
4083    
4084 sf-exg 1.557 if (style == 0)
4085     style = 1;
4086    
4087     cursor_type = (style - 1) / 2;
4088     set_option (Opt_cursorUnderline, cursor_type == 1);
4089 sf-exg 1.534
4090     #ifdef CURSOR_BLINK
4091 sf-exg 1.557 set_option (Opt_cursorBlink, style & 1);
4092 sf-exg 1.534 cursor_blink_reset ();
4093     #endif
4094    
4095     want_refresh = 1;
4096     }
4097 pcg 1.1 /*}}} */
4098    
4099 root 1.549 /* ---------------------------------------------------------------------- */
4100     /* Write data to the pty as typed by the user, pasted with the mouse,
4101     * or generated by us in response to a query ESC sequence.
4102     */
4103 pcg 1.1
4104     /*
4105 pcg 1.43 * Send printf () formatted output to the command.
4106 pcg 1.1 * Only use for small amounts of data.
4107     */
4108     void
4109 pcg 1.10 rxvt_term::tt_printf (const char *fmt,...)
4110 pcg 1.1 {
4111 pcg 1.10 va_list arg_ptr;
4112 root 1.234 char buf[256];
4113 pcg 1.1
4114 pcg 1.10 va_start (arg_ptr, fmt);
4115     vsnprintf ((char *)buf, 256, fmt, arg_ptr);
4116     va_end (arg_ptr);
4117 root 1.145 tt_write (buf, strlen (buf));
4118 pcg 1.1 }
4119    
4120 sf-exg 1.548 /* Write data to the pty as typed by the user. */
4121     void
4122     rxvt_term::tt_write_user_input (const char *data, unsigned int len)
4123     {
4124 root 1.549 if (HOOK_INVOKE ((this, HOOK_TT_WRITE, DT_STR_LEN, data, len, DT_END)))
4125     return;
4126    
4127 sf-exg 1.548 if (option (Opt_scrollTtyKeypress))
4128     if (view_start)
4129     {
4130     view_start = 0;
4131     want_refresh = 1;
4132     }
4133    
4134 root 1.549 tt_write_ (data, len);
4135 sf-exg 1.548 }
4136    
4137 pcg 1.1 void
4138 root 1.234 rxvt_term::tt_write (const char *data, unsigned int len)
4139 pcg 1.1 {
4140 root 1.253 if (HOOK_INVOKE ((this, HOOK_TT_WRITE, DT_STR_LEN, data, len, DT_END)))
4141     return;
4142    
4143 root 1.549 tt_write_ (data, len);
4144     }
4145    
4146     static const unsigned int MAX_PTY_WRITE = 255; // minimum MAX_INPUT
4147    
4148     void
4149     rxvt_term::tt_write_ (const char *data, unsigned int len)
4150     {
4151 root 1.269 if (pty->pty < 0)
4152 root 1.239 return;
4153    
4154 root 1.177 if (v_buflen == 0)
4155     {
4156 root 1.269 ssize_t written = write (pty->pty, data, min (len, MAX_PTY_WRITE));
4157 pcg 1.10
4158 sf-exg 1.480 max_it (written, 0);
4159    
4160     if (written == len)
4161 root 1.177 return;
4162 pcg 1.34
4163 root 1.177 data += written;
4164     len -= written;
4165     }
4166 pcg 1.10
4167 sf-exg 1.469 v_buffer = (char *)rxvt_realloc (v_buffer, v_buflen + len);
4168 pcg 1.10
4169 root 1.177 memcpy (v_buffer + v_buflen, data, len);
4170     v_buflen += len;
4171 pcg 1.10
4172 root 1.363 pty_ev.set (ev::READ | ev::WRITE);
4173 root 1.177 }
4174 pcg 1.10
4175 root 1.177 void rxvt_term::pty_write ()
4176     {
4177 root 1.269 int written = write (pty->pty, v_buffer, min (v_buflen, MAX_PTY_WRITE));
4178 pcg 1.1
4179 root 1.177 if (written > 0)
4180 pcg 1.10 {
4181 root 1.177 v_buflen -= written;
4182 pcg 1.10
4183 root 1.177 if (v_buflen == 0)
4184 pcg 1.10 {
4185 root 1.177 free (v_buffer);
4186     v_buffer = 0;
4187 pcg 1.10
4188 root 1.363 pty_ev.set (ev::READ);
4189 pcg 1.10 return;
4190     }
4191 root 1.177
4192     memmove (v_buffer, v_buffer + written, v_buflen);
4193 pcg 1.1 }
4194 root 1.177 else if (written != -1 || (errno != EAGAIN && errno != EINTR))
4195 root 1.363 pty_ev.set (ev::READ);
4196 pcg 1.1 }
4197 pcg 1.10
4198 pcg 1.1 /*----------------------- end-of-file (C source) -----------------------*/
4199