ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.604
Committed: Sat Feb 3 15:47:24 2024 UTC (2 months, 3 weeks ago) by sf-exg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.603: +13 -7 lines
Log Message:
Fix mouse reporting of motion notify events

On motion notify events, when no mouse button is pressed, urxvt
encodes either the number of the last button pressed or an invalid
value of -1, before the first button press, in mouse reporting
sequences. This commit fixes urxvt to report 3 as the button number,
same as xterm. Bug reported by Uli Schlachter.

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