ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.603
Committed: Mon Jun 5 13:39:34 2023 UTC (11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.602: +4 -2 lines
Log Message:
*** empty log message ***

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.586 button_number = MEvent.button - Button1;
1302 sf-exg 1.601 if (button_number > 10)
1303     return;
1304     else if (button_number >= 7)
1305     button_number += 128 - 7;
1306     else if (button_number >= 3)
1307 sf-exg 1.586 button_number += 64 - 3;
1308 pcg 1.1
1309 root 1.145 if (priv_modes & PrivMode_MouseX10)
1310 pcg 1.36 {
1311     /*
1312     * do not report ButtonRelease
1313     * no state info allowed
1314     */
1315 sf-exg 1.586 if (release)
1316 pcg 1.36 return;
1317     }
1318     else
1319     {
1320     /* XTerm mouse reporting needs these values:
1321     * 4 = Shift
1322     * 8 = Meta
1323     * 16 = Control
1324     * plus will add in our own Double-Click reporting
1325     * 32 = Double Click
1326     */
1327 sf-exg 1.586 state += ((MEvent.state & ShiftMask) ? 4 : 0)
1328     + ((MEvent.state & ModMetaMask) ? 8 : 0)
1329     + ((MEvent.state & ControlMask) ? 16 : 0);
1330 pcg 1.1 #ifdef MOUSE_REPORT_DOUBLECLICK
1331 sf-exg 1.586 state += ((MEvent.clicks > 1) ? 32 : 0);
1332 pcg 1.1 #endif
1333     }
1334    
1335 sf-exg 1.586 int code = 32 + (release ? 3 : button_number) + state;
1336    
1337 root 1.163 #if DEBUG_MOUSEREPORT
1338 pcg 1.43 fprintf (stderr, "Mouse [");
1339 sf-exg 1.586 if (state & 16)
1340 pcg 1.43 fputc ('C', stderr);
1341 sf-exg 1.586 if (state & 4)
1342 pcg 1.43 fputc ('S', stderr);
1343 sf-exg 1.586 if (state & 8)
1344 pcg 1.43 fputc ('A', stderr);
1345 sf-exg 1.586 if (state & 32)
1346 pcg 1.43 fputc ('2', stderr);
1347     fprintf (stderr, "]: <%d>, %d/%d\n",
1348 pcg 1.36 button_number,
1349 root 1.461 x,
1350     y);
1351 root 1.163 #endif
1352    
1353 root 1.461 #if ENABLE_FRILLS
1354 sf-exg 1.586 if (priv_modes & PrivMode_ExtMouseSGR)
1355     tt_printf ("\033[<%d;%d;%d%c",
1356     button_number + state,
1357     x,
1358     y,
1359     release ? 'm' : 'M');
1360 sf-exg 1.587 else if (priv_modes & PrivMode_ExtMouseUrxvt)
1361 root 1.461 tt_printf ("\033[%d;%d;%dM",
1362 sf-exg 1.586 code,
1363 root 1.461 x,
1364     y);
1365 sf-exg 1.587 else if (priv_modes & PrivMode_ExtMouseUTF8)
1366 sf-exg 1.601 if (code < 128)
1367     tt_printf ("\033[M%c%lc%lc",
1368     code,
1369     wint_t (32 + x),
1370     wint_t (32 + y));
1371     else
1372     tt_printf ("\033[M%c%c%lc%lc",
1373     0xc0 + (code >> 6),
1374     0x80 + (code & 0x3f),
1375     wint_t (32 + x),
1376     wint_t (32 + y));
1377 root 1.461 else
1378     #endif
1379     tt_printf ("\033[M%c%c%c",
1380 sf-exg 1.586 code,
1381 root 1.461 32 + x,
1382     32 + y);
1383 pcg 1.1 }
1384    
1385     /*{{{ process an X event */
1386 root 1.512 void ecb_hot
1387 pcg 1.38 rxvt_term::x_cb (XEvent &ev)
1388 pcg 1.1 {
1389 root 1.264 make_current ();
1390    
1391 root 1.305 dLocal (Display *, dpy);
1392 root 1.192
1393 root 1.259 if (ev.xany.window == vt
1394 root 1.265 && SHOULD_INVOKE (HOOK_X_EVENT)
1395 root 1.259 && HOOK_INVOKE ((this, HOOK_X_EVENT, DT_XEVENT, &ev, DT_END)))
1396     return;
1397    
1398 root 1.260 // for XQueryPointer
1399 root 1.175 Window unused_root, unused_child;
1400     int unused_root_x, unused_root_y;
1401     unsigned int unused_mask;
1402 pcg 1.3
1403 pcg 1.38 switch (ev.type)
1404 pcg 1.36 {
1405     case KeyPress:
1406 root 1.306 key_press (ev.xkey);
1407 pcg 1.36 break;
1408 pcg 1.1
1409 pcg 1.36 case KeyRelease:
1410 root 1.306 key_release (ev.xkey);
1411     break;
1412 pcg 1.36
1413     case ButtonPress:
1414 pcg 1.38 button_press (ev.xbutton);
1415 pcg 1.36 break;
1416    
1417     case ButtonRelease:
1418 pcg 1.38 button_release (ev.xbutton);
1419 pcg 1.36 break;
1420    
1421     case ClientMessage:
1422 root 1.277 if (ev.xclient.format == 32
1423     && !HOOK_INVOKE ((this, HOOK_CLIENT_MESSAGE, DT_XEVENT, &ev, DT_END)))
1424 root 1.200 {
1425 root 1.276 if (ev.xclient.message_type == xa[XA_WM_PROTOCOLS])
1426     {
1427 root 1.277 if (!HOOK_INVOKE ((this, HOOK_WM_PROTOCOLS, DT_XEVENT, &ev, DT_END)))
1428 root 1.276 {
1429 root 1.277 if (ev.xclient.data.l[0] == xa[XA_WM_DELETE_WINDOW])
1430     {
1431     if (!HOOK_INVOKE ((this, HOOK_WM_DELETE_WINDOW, DT_XEVENT, &ev, DT_END)))
1432     destroy ();
1433     }
1434 root 1.200 #if ENABLE_EWMH
1435 root 1.277 else if (ev.xclient.data.l[0] == xa[XA_NET_WM_PING])
1436 root 1.305 XSendEvent (dpy, ev.xclient.window = display->root,
1437 root 1.277 False, SubstructureRedirectMask | SubstructureNotifyMask,
1438     &ev);
1439 root 1.200 #endif
1440 root 1.277 }
1441 root 1.276 }
1442 root 1.198 #if ENABLE_XEMBED
1443 root 1.276 else if (ev.xclient.format == 32 && ev.xclient.message_type == xa[XA_XEMBED])
1444     {
1445     if (ev.xclient.data.l[1] == XEMBED_FOCUS_IN)
1446     focus_in ();
1447     else if (ev.xclient.data.l[1] == XEMBED_FOCUS_OUT)
1448     focus_out ();
1449     }
1450 root 1.198 #endif
1451 pcg 1.36 }
1452     break;
1453 pcg 1.1
1454 pcg 1.36 /*
1455     * XXX: this is not the _current_ arrangement
1456     * Here's my conclusion:
1457     * If the window is completely unobscured, use bitblt's
1458     * to scroll. Even then, they're only used when doing partial
1459     * screen scrolling. When partially obscured, we have to fill
1460     * in the GraphicsExpose parts, which means that after each refresh,
1461     * we need to wait for the graphics expose or Noexpose events,
1462     * which ought to make things real slow!
1463     */
1464     case VisibilityNotify:
1465 pcg 1.38 switch (ev.xvisibility.state)
1466 pcg 1.8 {
1467     case VisibilityUnobscured:
1468 pcg 1.34 refresh_type = FAST_REFRESH;
1469 pcg 1.8 break;
1470     case VisibilityPartiallyObscured:
1471 pcg 1.34 refresh_type = SLOW_REFRESH;
1472 pcg 1.8 break;
1473     default:
1474 pcg 1.34 refresh_type = NO_REFRESH;
1475 pcg 1.8 break;
1476     }
1477 pcg 1.36 break;
1478 pcg 1.1
1479 pcg 1.36 case FocusIn:
1480 root 1.320 if (ev.xfocus.detail != NotifyInferior
1481     && ev.xfocus.detail != NotifyPointer
1482     && ev.xfocus.mode != NotifyGrab)
1483 root 1.316 focus_in ();
1484 pcg 1.36 break;
1485    
1486     case FocusOut:
1487 root 1.320 if (ev.xfocus.detail != NotifyInferior
1488     && ev.xfocus.detail != NotifyPointer
1489     && ev.xfocus.mode != NotifyGrab)
1490 root 1.316 focus_out ();
1491 pcg 1.36 break;
1492    
1493     case ConfigureNotify:
1494 sf-exg 1.482 if (ev.xconfigure.window == parent)
1495 pcg 1.36 {
1496 root 1.398 while (XCheckTypedWindowEvent (dpy, ev.xconfigure.window, ConfigureNotify, &ev))
1497 root 1.208 ;
1498 pcg 1.38
1499 root 1.515 bool want_position_change = SHOULD_INVOKE (HOOK_POSITION_CHANGE);
1500    
1501     if (want_position_change)
1502 sf-exg 1.460 {
1503     int x, y;
1504 root 1.515
1505 sf-exg 1.460 if (ev.xconfigure.send_event)
1506     {
1507     x = ev.xconfigure.x;
1508     y = ev.xconfigure.y;
1509     }
1510     else
1511     get_window_origin (x, y);
1512    
1513 root 1.515 if (x != parent_x || y != parent_y)
1514     {
1515     parent_x = x;
1516     parent_y = y;
1517 root 1.519 HOOK_INVOKE ((this, HOOK_POSITION_CHANGE, DT_INT, x, DT_INT, y, DT_END));
1518 root 1.515 }
1519 sf-exg 1.460 }
1520    
1521 root 1.208 if (szHint.width != ev.xconfigure.width || szHint.height != ev.xconfigure.height)
1522 root 1.163 {
1523     seen_resize = 1;
1524 root 1.208 resize_all_windows (ev.xconfigure.width, ev.xconfigure.height, 1);
1525 sasha 1.347 }
1526 root 1.385
1527 root 1.270 HOOK_INVOKE ((this, HOOK_CONFIGURE_NOTIFY, DT_XEVENT, &ev, DT_END));
1528 pcg 1.36 }
1529     break;
1530    
1531 root 1.131 case PropertyNotify:
1532 sf-exg 1.476 HOOK_INVOKE ((this, HOOK_PROPERTY_NOTIFY, DT_XEVENT, &ev, DT_END));
1533 root 1.131 break;
1534    
1535 pcg 1.36 case SelectionClear:
1536 sf-exg 1.436 selection_clear (ev.xselectionclear.selection == xa[XA_CLIPBOARD]);
1537 pcg 1.36 break;
1538    
1539     case SelectionRequest:
1540 pcg 1.38 selection_send (ev.xselectionrequest);
1541 pcg 1.36 break;
1542 pcg 1.1
1543 root 1.247 case MapNotify:
1544     mapped = 1;
1545 pcg 1.31 #ifdef TEXT_BLINK
1546 root 1.374 text_blink_ev.start ();
1547 pcg 1.31 #endif
1548 root 1.247 HOOK_INVOKE ((this, HOOK_MAP_NOTIFY, DT_XEVENT, &ev, DT_END));
1549 pcg 1.36 break;
1550 pcg 1.1
1551 root 1.247 case UnmapNotify:
1552     mapped = 0;
1553 pcg 1.31 #ifdef TEXT_BLINK
1554 root 1.247 text_blink_ev.stop ();
1555 pcg 1.31 #endif
1556 root 1.247 HOOK_INVOKE ((this, HOOK_UNMAP_NOTIFY, DT_XEVENT, &ev, DT_END));
1557 pcg 1.36 break;
1558 pcg 1.1
1559 pcg 1.36 case GraphicsExpose:
1560     case Expose:
1561 root 1.208 if (ev.xany.window == vt)
1562 pcg 1.36 {
1563 root 1.116 do
1564 sasha 1.357 {
1565     scr_expose (ev.xexpose.x, ev.xexpose.y,
1566 sf-exg 1.475 ev.xexpose.width, ev.xexpose.height, false);
1567 sasha 1.357 }
1568 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, ev.xany.type, &ev));
1569 root 1.116
1570     ev.xany.type = ev.xany.type == Expose ? GraphicsExpose : Expose;
1571    
1572 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, ev.xany.type, &ev))
1573 sasha 1.357 {
1574     scr_expose (ev.xexpose.x, ev.xexpose.y,
1575 sf-exg 1.475 ev.xexpose.width, ev.xexpose.height, false);
1576 sasha 1.357 }
1577 root 1.381
1578 root 1.254 want_refresh = 1;
1579 pcg 1.36 }
1580     else
1581     {
1582 pcg 1.38 XEvent unused_event;
1583 pcg 1.36
1584 root 1.305 while (XCheckTypedWindowEvent (dpy, ev.xany.window, Expose, &unused_event))
1585 pcg 1.95 ;
1586 root 1.305 while (XCheckTypedWindowEvent (dpy, ev.xany.window, GraphicsExpose, &unused_event))
1587 pcg 1.95 ;
1588    
1589 ayin 1.389 if (scrollBar.state && ev.xany.window == scrollBar.win)
1590 pcg 1.36 {
1591 sf-exg 1.497 scrollBar.state = SB_STATE_IDLE;
1592 ayin 1.414 scrollBar.show (0);
1593 pcg 1.36 }
1594     }
1595     break;
1596    
1597     case MotionNotify:
1598 pcg 1.1 #ifdef POINTER_BLANK
1599 pcg 1.36 if (hidden_pointer)
1600     pointer_unblank ();
1601 pcg 1.1 #endif
1602 sf-exg 1.566 if (!bypass_keystate
1603     && ((priv_modes & PrivMode_MouseBtnEvent && ev.xbutton.state & (Button1Mask|Button2Mask|Button3Mask))
1604     || priv_modes & PrivMode_MouseAnyEvent))
1605 ayin 1.360 mouse_report (ev.xbutton);
1606 root 1.168 if ((priv_modes & PrivMode_mouse_report) && !bypass_keystate)
1607 pcg 1.36 break;
1608    
1609 root 1.208 if (ev.xany.window == vt)
1610 pcg 1.36 {
1611 root 1.265 if (SHOULD_INVOKE (HOOK_MOTION_NOTIFY)
1612     && HOOK_INVOKE ((this, HOOK_MOTION_NOTIFY, DT_XEVENT, &ev, DT_END)))
1613 root 1.240 ; // nop
1614     else if (ev.xbutton.state & (Button1Mask | Button3Mask))
1615 pcg 1.36 {
1616 root 1.305 while (XCheckTypedWindowEvent (dpy, vt, MotionNotify, &ev))
1617 pcg 1.38 ;
1618    
1619 root 1.305 XQueryPointer (dpy, vt,
1620 root 1.145 &unused_root, &unused_child,
1621     &unused_root_x, &unused_root_y,
1622 root 1.168 &ev.xbutton.x, &ev.xbutton.y,
1623     &ev.xbutton.state);
1624 pcg 1.1 #ifdef MOUSE_THRESHOLD
1625 pcg 1.36 /* deal with a `jumpy' mouse */
1626 root 1.565 if (ev.xmotion.time - MEvent.time > MOUSE_THRESHOLD)
1627     #endif
1628 pcg 1.36 {
1629 root 1.145 #if ISO_14755
1630     // 5.4
1631     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
1632     {
1633     iso14755_54 (ev.xbutton.x, ev.xbutton.y);
1634     break;
1635     }
1636     #endif
1637     selection_extend (ev.xbutton.x, ev.xbutton.y,
1638 root 1.168 ev.xbutton.state & Button3Mask ? 2 : 0);
1639    
1640 pcg 1.1 #ifdef SELECTION_SCROLLING
1641 root 1.208 if (ev.xbutton.y < int_bwidth
1642     || Pixel2Row (ev.xbutton.y) > (nrow-1))
1643 pcg 1.36 {
1644 sf-exg 1.540 page_dirn scroll_selection_dir;
1645 pcg 1.36 int dist;
1646    
1647     /* don't clobber the current delay if we are
1648     * already in the middle of scrolling.
1649     */
1650 root 1.376 if (!sel_scroll_ev.is_active ())
1651 root 1.363 sel_scroll_ev.start (SCROLLBAR_INITIAL_DELAY, SCROLLBAR_CONTINUOUS_DELAY);
1652 pcg 1.36
1653     /* save the event params so we can highlight
1654     * the selection in the pending-scroll loop
1655     */
1656 root 1.145 selection_save_x = ev.xbutton.x;
1657     selection_save_y = ev.xbutton.y;
1658     selection_save_state = (ev.xbutton.state & Button3Mask) ? 2 : 0;
1659 pcg 1.36
1660     /* calc number of lines to scroll */
1661 root 1.208 if (ev.xbutton.y < int_bwidth)
1662 pcg 1.36 {
1663     scroll_selection_dir = UP;
1664 root 1.208 dist = int_bwidth - ev.xbutton.y;
1665 pcg 1.36 }
1666     else
1667     {
1668     scroll_selection_dir = DN;
1669 sf-exg 1.504 dist = ev.xbutton.y - (int_bwidth + vt_height);
1670 pcg 1.36 }
1671 root 1.145
1672     scroll_selection_lines = Pixel2Height (dist)
1673     / SELECTION_SCROLL_LINE_SPEEDUP
1674     + 1;
1675 root 1.212 min_it (scroll_selection_lines,
1676 root 1.145 SELECTION_SCROLL_MAX_LINES);
1677 sf-exg 1.540 scroll_selection_lines *= scroll_selection_dir;
1678 pcg 1.36 }
1679     else
1680     {
1681     /* we are within the text window, so we
1682     * shouldn't be scrolling
1683     */
1684 root 1.376 sel_scroll_ev.stop();
1685 pcg 1.36 }
1686 pcg 1.1 #endif
1687 pcg 1.36 }
1688     }
1689     }
1690 sf-exg 1.497 else if (scrollBar.state == SB_STATE_MOTION && ev.xany.window == scrollBar.win)
1691 pcg 1.36 {
1692 root 1.305 while (XCheckTypedWindowEvent (dpy, scrollBar.win,
1693 root 1.168 MotionNotify, &ev))
1694     ;
1695    
1696 root 1.305 XQueryPointer (dpy, scrollBar.win,
1697 pcg 1.36 &unused_root, &unused_child,
1698     &unused_root_x, &unused_root_y,
1699 root 1.168 &ev.xbutton.x, &ev.xbutton.y,
1700 pcg 1.36 &unused_mask);
1701 sf-exg 1.494 scr_move_to (scrollBar.position (ev.xbutton.y) - csrO,
1702 ayin 1.413 scrollBar.size ());
1703 root 1.254 want_refresh = 1;
1704 ayin 1.414 scrollBar.show (1);
1705 pcg 1.36 }
1706     break;
1707     }
1708 root 1.248
1709     #if defined(CURSOR_BLINK)
1710 sf-exg 1.506 if (ev.type == KeyPress)
1711     cursor_blink_reset ();
1712 root 1.248 #endif
1713    
1714     #if defined(POINTER_BLANK)
1715 root 1.321 if (option (Opt_pointerBlank) && pointerBlankDelay > 0)
1716 root 1.248 {
1717     if (ev.type == MotionNotify
1718     || ev.type == ButtonPress
1719     || ev.type == ButtonRelease)
1720     if (hidden_pointer)
1721     pointer_unblank ();
1722    
1723     if (ev.type == KeyPress && hidden_pointer == 0)
1724     pointer_blank ();
1725     }
1726     #endif
1727 root 1.381
1728     refresh_check ();
1729 pcg 1.36 }
1730 pcg 1.1
1731 root 1.430 #if ENABLE_FRILLS
1732 root 1.512 void ecb_cold
1733 root 1.420 rxvt_term::set_urgency (bool enable)
1734     {
1735 sf-exg 1.503 if (enable == urgency_hint)
1736 root 1.420 return;
1737    
1738 sf-exg 1.482 if (XWMHints *h = XGetWMHints (dpy, parent))
1739 root 1.420 {
1740     h->flags = h->flags & ~XUrgencyHint | (enable ? XUrgencyHint : 0);
1741 sf-exg 1.482 XSetWMHints (dpy, parent, h);
1742 root 1.420 urgency_hint = enable;
1743 sf-exg 1.498 XFree (h);
1744 root 1.420 }
1745     }
1746 root 1.430 #endif
1747 root 1.420
1748 root 1.512 void ecb_cold
1749 root 1.198 rxvt_term::focus_in ()
1750     {
1751 root 1.208 if (!focus)
1752 root 1.198 {
1753 root 1.208 focus = 1;
1754 root 1.296 want_refresh = 1;
1755 root 1.227
1756 root 1.206 #if USE_XIM
1757 root 1.198 if (Input_Context != NULL)
1758     {
1759 sf-exg 1.489 im_set_position ();
1760 root 1.198 XSetICFocus (Input_Context);
1761     }
1762     #endif
1763 root 1.206 #if CURSOR_BLINK
1764 root 1.321 if (option (Opt_cursorBlink))
1765 root 1.375 cursor_blink_ev.again ();
1766 root 1.198 #endif
1767 root 1.206 #if OFF_FOCUS_FADING
1768 root 1.198 if (rs[Rs_fade])
1769     {
1770     pix_colors = pix_colors_focused;
1771 root 1.563 scr_recolor ();
1772 root 1.198 }
1773     #endif
1774 ayin 1.322 #if ENABLE_FRILLS
1775     if (option (Opt_urgentOnBell))
1776 root 1.420 set_urgency (0);
1777 sf-exg 1.569
1778     if (priv_modes & PrivMode_FocusEvent)
1779     tt_printf ("\x1b[I");
1780 ayin 1.322 #endif
1781 root 1.420
1782     HOOK_INVOKE ((this, HOOK_FOCUS_IN, DT_END));
1783 root 1.198 }
1784     }
1785    
1786 root 1.512 void ecb_cold
1787 root 1.198 rxvt_term::focus_out ()
1788     {
1789 root 1.208 if (focus)
1790 root 1.198 {
1791 root 1.208 focus = 0;
1792 root 1.296 want_refresh = 1;
1793 root 1.198
1794 root 1.420 #if ENABLE_FRILLS
1795     if (option (Opt_urgentOnBell))
1796     set_urgency (0);
1797 sf-exg 1.569
1798     if (priv_modes & PrivMode_FocusEvent)
1799     tt_printf ("\x1b[O");
1800 root 1.420 #endif
1801 root 1.198 #if ENABLE_FRILLS || ISO_14755
1802 root 1.227 if (iso14755buf)
1803     {
1804     iso14755buf = 0;
1805 ayin 1.337 # if ISO_14755
1806 root 1.227 scr_overlay_off ();
1807     # endif
1808     }
1809 root 1.198 #endif
1810 root 1.206 #if USE_XIM
1811 root 1.198 if (Input_Context != NULL)
1812     XUnsetICFocus (Input_Context);
1813     #endif
1814 root 1.206 #if CURSOR_BLINK
1815 root 1.321 if (option (Opt_cursorBlink))
1816 root 1.198 cursor_blink_ev.stop ();
1817 root 1.363
1818 root 1.198 hidden_cursor = 0;
1819     #endif
1820 root 1.206 #if OFF_FOCUS_FADING
1821 root 1.198 if (rs[Rs_fade])
1822     {
1823     pix_colors = pix_colors_unfocused;
1824 root 1.563 scr_recolor ();
1825 root 1.198 }
1826     #endif
1827 root 1.420
1828     HOOK_INVOKE ((this, HOOK_FOCUS_OUT, DT_END));
1829 root 1.198 }
1830     }
1831    
1832 root 1.512 void ecb_cold
1833 root 1.563 rxvt_term::update_fade_color (unsigned int idx, bool first_time)
1834 root 1.313 {
1835     #if OFF_FOCUS_FADING
1836     if (rs[Rs_fade])
1837     {
1838 root 1.563 if (!first_time)
1839     pix_colors_focused [idx].free (this);
1840    
1841 root 1.313 rgba c;
1842     pix_colors [Color_fade].get (c);
1843     pix_colors_focused [idx].fade (this, atoi (rs[Rs_fade]), pix_colors_unfocused [idx], c);
1844     }
1845     #endif
1846     }
1847    
1848 sf-exg 1.582 #if ENABLE_PERL
1849 root 1.512 void ecb_hot
1850 pcg 1.38 rxvt_term::rootwin_cb (XEvent &ev)
1851     {
1852 root 1.264 make_current ();
1853 pcg 1.38
1854 root 1.314 if (SHOULD_INVOKE (HOOK_ROOT_EVENT)
1855     && HOOK_INVOKE ((this, HOOK_ROOT_EVENT, DT_XEVENT, &ev, DT_END)))
1856     return;
1857    
1858 pcg 1.40 switch (ev.type)
1859 pcg 1.38 {
1860 pcg 1.40 case PropertyNotify:
1861 root 1.131 /*
1862     * if user used some Esetroot compatible prog to set the root bg,
1863     * use the property to determine the pixmap. We use it later on.
1864     */
1865 sasha 1.343 if (ev.xproperty.atom == xa[XA_XROOTPMAP_ID]
1866     || ev.xproperty.atom == xa[XA_ESETROOT_PMAP_ID])
1867     {
1868 root 1.516 HOOK_INVOKE ((this, HOOK_ROOTPMAP_CHANGE, DT_END));
1869 sasha 1.343 }
1870 root 1.385
1871 pcg 1.40 break;
1872 pcg 1.38 }
1873 root 1.381
1874     refresh_check ();
1875 pcg 1.38 }
1876 root 1.131 #endif
1877 pcg 1.38
1878     void
1879 pcg 1.56 rxvt_term::button_press (XButtonEvent &ev)
1880 pcg 1.1 {
1881 pcg 1.36 int reportmode = 0, clickintime;
1882 pcg 1.1
1883 pcg 1.38 bypass_keystate = ev.state & (ModMetaMask | ShiftMask);
1884 root 1.229
1885 pcg 1.36 if (!bypass_keystate)
1886 root 1.145 reportmode = !! (priv_modes & PrivMode_mouse_report);
1887    
1888 pcg 1.36 /*
1889     * VT window processing of button press
1890     */
1891 root 1.208 if (ev.window == vt)
1892 pcg 1.36 {
1893 root 1.280 if (HOOK_INVOKE ((this, HOOK_BUTTON_PRESS, DT_XEVENT, &ev, DT_END)))
1894     return;
1895    
1896 root 1.145 #if ISO_14755
1897     // 5.4
1898     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
1899     {
1900     iso14755_54 (ev.x, ev.y);
1901     return;
1902     }
1903     #endif
1904    
1905 sf-exg 1.555 clickintime = ev.time - MEvent.time < multiClickTime;
1906 root 1.168
1907 pcg 1.50 if (reportmode)
1908 pcg 1.36 {
1909 pcg 1.50 /* mouse report from vt window */
1910     /* save the xbutton state (for ButtonRelease) */
1911     MEvent.state = ev.state;
1912     #ifdef MOUSE_REPORT_DOUBLECLICK
1913     if (ev.button == MEvent.button && clickintime)
1914 pcg 1.36 {
1915 sf-exg 1.452 /* same button, within allowed time */
1916 pcg 1.50 MEvent.clicks++;
1917 root 1.243
1918 pcg 1.50 if (MEvent.clicks > 1)
1919 pcg 1.36 {
1920 pcg 1.50 /* only report double clicks */
1921     MEvent.clicks = 2;
1922 pcg 1.36 mouse_report (ev);
1923 pcg 1.50
1924     /* don't report the release */
1925     MEvent.clicks = 0;
1926     MEvent.button = AnyButton;
1927 pcg 1.36 }
1928 pcg 1.50 }
1929     else
1930     {
1931     /* different button, or time expired */
1932     MEvent.clicks = 1;
1933 pcg 1.38 MEvent.button = ev.button;
1934 pcg 1.36 mouse_report (ev);
1935 pcg 1.50 }
1936     #else
1937     MEvent.button = ev.button;
1938     mouse_report (ev);
1939 ayin 1.366 #endif /* MOUSE_REPORT_DOUBLECLICK */
1940 pcg 1.36
1941 pcg 1.50 }
1942     else
1943     {
1944     if (ev.button != MEvent.button)
1945     MEvent.clicks = 0;
1946 root 1.168
1947 root 1.280 switch (ev.button)
1948     {
1949     case Button1:
1950     /* allow meta + click to select rectangular areas */
1951     /* should be done in screen.C */
1952 root 1.168 #if ENABLE_FRILLS
1953 root 1.280 selection.rect = !!(ev.state & ModMetaMask);
1954 root 1.168 #else
1955 root 1.280 selection.rect = false;
1956 root 1.168 #endif
1957    
1958 root 1.280 /* allow shift+left click to extend selection */
1959     if (ev.state & ShiftMask && !(priv_modes & PrivMode_mouse_report))
1960     {
1961     if (MEvent.button == Button1 && clickintime)
1962     selection_rotate (ev.x, ev.y);
1963     else
1964     selection_extend (ev.x, ev.y, 1);
1965     }
1966     else
1967     {
1968     if (MEvent.button == Button1 && clickintime)
1969     MEvent.clicks++;
1970     else
1971     MEvent.clicks = 1;
1972 pcg 1.21
1973 root 1.280 selection_click (MEvent.clicks, ev.x, ev.y);
1974     }
1975 pcg 1.21
1976 root 1.280 MEvent.button = Button1;
1977     break;
1978 pcg 1.1
1979 root 1.280 case Button3:
1980     if (MEvent.button == Button3 && clickintime)
1981     selection_rotate (ev.x, ev.y);
1982     else
1983     selection_extend (ev.x, ev.y, 1);
1984 root 1.145
1985 root 1.280 MEvent.button = Button3;
1986     break;
1987     }
1988     }
1989 root 1.145
1990 pcg 1.50 MEvent.time = ev.time;
1991     return;
1992 pcg 1.36 }
1993 pcg 1.1
1994 pcg 1.36 /*
1995     * Scrollbar window processing of button press
1996     */
1997 ayin 1.389 if (scrollBar.state && ev.window == scrollBar.win)
1998 pcg 1.36 {
1999 ayin 1.403 page_dirn direction = NO_DIR;
2000 ayin 1.400
2001     if (scrollBar.upButton (ev.y))
2002 ayin 1.403 direction = UP; /* up */
2003 ayin 1.400 else if (scrollBar.dnButton (ev.y))
2004 ayin 1.403 direction = DN; /* down */
2005 ayin 1.400
2006 sf-exg 1.497 scrollBar.state = SB_STATE_IDLE;
2007 pcg 1.36 /*
2008     * Rxvt-style scrollbar:
2009     * move up if mouse is above slider
2010     * move dn if mouse is below slider
2011     *
2012     * XTerm-style scrollbar:
2013     * Move display proportional to pointer location
2014     * pointer near top -> scroll one line
2015     * pointer near bot -> scroll full page
2016     */
2017 pcg 1.1 #ifndef NO_SCROLLBAR_REPORT
2018 pcg 1.36 if (reportmode)
2019     {
2020     /*
2021     * Mouse report disabled scrollbar:
2022     * arrow buttons - send up/down
2023     * click on scrollbar - send pageup/down
2024     */
2025 ayin 1.403 if (direction == UP)
2026 pcg 1.43 tt_printf ("\033[A");
2027 ayin 1.403 else if (direction == DN)
2028 pcg 1.43 tt_printf ("\033[B");
2029 pcg 1.36 else
2030 pcg 1.38 switch (ev.button)
2031 pcg 1.36 {
2032     case Button2:
2033 pcg 1.43 tt_printf ("\014");
2034 pcg 1.36 break;
2035     case Button1:
2036 pcg 1.43 tt_printf ("\033[6~");
2037 pcg 1.36 break;
2038     case Button3:
2039 pcg 1.43 tt_printf ("\033[5~");
2040 pcg 1.36 break;
2041     }
2042     }
2043     else
2044 ayin 1.366 #endif /* NO_SCROLLBAR_REPORT */
2045 pcg 1.36 {
2046 ayin 1.403 if (direction != NO_DIR)
2047 pcg 1.36 {
2048 pcg 1.1 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
2049 root 1.376 if (!cont_scroll_ev.is_active ())
2050     cont_scroll_ev.start (SCROLLBAR_INITIAL_DELAY, SCROLLBAR_CONTINUOUS_DELAY);
2051 pcg 1.1 #endif
2052 ayin 1.403 if (scr_page (direction, 1))
2053 pcg 1.36 {
2054 ayin 1.403 if (direction == UP)
2055 sf-exg 1.497 scrollBar.state = SB_STATE_UP;
2056 pcg 1.36 else
2057 sf-exg 1.497 scrollBar.state = SB_STATE_DOWN;
2058 pcg 1.36 }
2059     }
2060     else
2061 pcg 1.38 switch (ev.button)
2062 pcg 1.36 {
2063     case Button2:
2064 ayin 1.387 switch (scrollBar.align)
2065 pcg 1.36 {
2066 sf-exg 1.497 case SB_ALIGN_TOP:
2067 pcg 1.36 csrO = 0;
2068     break;
2069 sf-exg 1.497 case SB_ALIGN_CENTRE:
2070 pcg 1.36 csrO = (scrollBar.bot - scrollBar.top) / 2;
2071     break;
2072 sf-exg 1.497 case SB_ALIGN_BOTTOM:
2073 pcg 1.36 csrO = scrollBar.bot - scrollBar.top;
2074     break;
2075     }
2076 root 1.120
2077 sf-exg 1.497 if (scrollBar.style == SB_STYLE_XTERM
2078 sf-exg 1.494 || scrollBar.above_slider (ev.y)
2079     || scrollBar.below_slider (ev.y))
2080     scr_move_to (scrollBar.position (ev.y) - csrO, scrollBar.size ());
2081 root 1.120
2082 sf-exg 1.497 scrollBar.state = SB_STATE_MOTION;
2083 pcg 1.36 break;
2084    
2085     case Button1:
2086 sf-exg 1.497 if (scrollBar.align == SB_ALIGN_CENTRE)
2087 pcg 1.38 csrO = ev.y - scrollBar.top;
2088 pcg 1.36 /* FALLTHROUGH */
2089    
2090     case Button3:
2091 sf-exg 1.497 if (scrollBar.style != SB_STYLE_XTERM)
2092 pcg 1.36 {
2093 sf-exg 1.494 if (scrollBar.above_slider (ev.y))
2094 pcg 1.1 # ifdef RXVT_SCROLL_FULL
2095 root 1.208 scr_page (UP, nrow - 1);
2096 pcg 1.1 # else
2097 root 1.208 scr_page (UP, nrow / 4);
2098 pcg 1.1 # endif
2099 sf-exg 1.494 else if (scrollBar.below_slider (ev.y))
2100 pcg 1.1 # ifdef RXVT_SCROLL_FULL
2101 root 1.208 scr_page (DN, nrow - 1);
2102 pcg 1.1 # else
2103 root 1.208 scr_page (DN, nrow / 4);
2104 pcg 1.1 # endif
2105 pcg 1.36 else
2106 sf-exg 1.497 scrollBar.state = SB_STATE_MOTION;
2107 pcg 1.36 }
2108     else
2109     {
2110 pcg 1.38 scr_page ((ev.button == Button1 ? DN : UP),
2111 root 1.208 (nrow
2112 sf-exg 1.494 * scrollBar.position (ev.y)
2113 ayin 1.413 / scrollBar.size ()));
2114 pcg 1.36 }
2115 root 1.120
2116 pcg 1.36 break;
2117     }
2118     }
2119 root 1.243
2120 pcg 1.36 return;
2121 pcg 1.1 }
2122     }
2123    
2124     void
2125 pcg 1.56 rxvt_term::button_release (XButtonEvent &ev)
2126 pcg 1.1 {
2127 pcg 1.38 int reportmode = 0;
2128 pcg 1.1
2129 pcg 1.36 csrO = 0; /* reset csr Offset */
2130     if (!bypass_keystate)
2131 root 1.145 reportmode = !! (priv_modes & PrivMode_mouse_report);
2132 pcg 1.36
2133 sf-exg 1.497 if (scrollBar.state == SB_STATE_UP || scrollBar.state == SB_STATE_DOWN)
2134 pcg 1.36 {
2135 sf-exg 1.497 scrollBar.state = SB_STATE_IDLE;
2136 ayin 1.414 scrollBar.show (0);
2137 root 1.145 }
2138 pcg 1.36
2139 pcg 1.1 #ifdef SELECTION_SCROLLING
2140 root 1.376 sel_scroll_ev.stop();
2141 pcg 1.1 #endif
2142 root 1.145
2143 root 1.208 if (ev.window == vt)
2144 pcg 1.36 {
2145 root 1.280 if (HOOK_INVOKE ((this, HOOK_BUTTON_RELEASE, DT_XEVENT, &ev, DT_END)))
2146     return;
2147    
2148 root 1.145 #if ISO_14755
2149     // 5.4
2150     if (iso14755buf & (ISO_14755_STARTED | ISO_14755_54))
2151     return;
2152     #endif
2153 root 1.280
2154 pcg 1.50 if (reportmode)
2155 pcg 1.36 {
2156 pcg 1.50 /* mouse report from vt window */
2157     /* don't report release of wheel "buttons" */
2158 sf-exg 1.601 if (ev.button >= 4 && ev.button <= 7)
2159 pcg 1.50 return;
2160     #ifdef MOUSE_REPORT_DOUBLECLICK
2161     /* only report the release of 'slow' single clicks */
2162     if (MEvent.button != AnyButton
2163     && (ev.button != MEvent.button
2164     || (ev.time - MEvent.time
2165 sf-exg 1.555 > multiClickTime / 2)))
2166 pcg 1.36 {
2167 pcg 1.50 MEvent.clicks = 0;
2168 sf-exg 1.586 MEvent.button = ev.button;
2169 pcg 1.36 mouse_report (ev);
2170 pcg 1.50 }
2171     #else /* MOUSE_REPORT_DOUBLECLICK */
2172 sf-exg 1.586 MEvent.button = ev.button;
2173 pcg 1.50 mouse_report (ev);
2174 ayin 1.366 #endif /* MOUSE_REPORT_DOUBLECLICK */
2175 pcg 1.50 return;
2176     }
2177 root 1.145
2178 pcg 1.50 /*
2179     * dumb hack to compensate for the failure of click-and-drag
2180     * when overriding mouse reporting
2181     */
2182 root 1.145 if (priv_modes & PrivMode_mouse_report
2183 pcg 1.50 && bypass_keystate
2184     && ev.button == Button1 && MEvent.clicks <= 1)
2185     selection_extend (ev.x, ev.y, 0);
2186    
2187     switch (ev.button)
2188     {
2189     case Button1:
2190     case Button3:
2191     selection_make (ev.time);
2192     break;
2193 root 1.272
2194 pcg 1.50 case Button2:
2195 sf-exg 1.504 if (IN_RANGE_EXC (ev.x, 0, vt_width) && IN_RANGE_EXC (ev.y, 0, vt_height)) // inside window?
2196 sf-exg 1.447 selection_request (ev.time, ev.state & ModMetaMask ? Sel_Clipboard : Sel_Primary);
2197 pcg 1.50 break;
2198 root 1.272
2199 pcg 1.50 #ifdef MOUSE_WHEEL
2200     case Button4:
2201     case Button5:
2202 pcg 1.36 {
2203 sf-exg 1.537 int lines;
2204     page_dirn dirn;
2205 pcg 1.36
2206 sf-exg 1.537 dirn = ev.button == Button4 ? UP : DN;
2207 root 1.97
2208 pcg 1.50 if (ev.state & ShiftMask)
2209 sf-exg 1.537 lines = 1;
2210 root 1.321 else if (option (Opt_mouseWheelScrollPage))
2211 sf-exg 1.537 lines = nrow - 1;
2212 pcg 1.50 else
2213 sf-exg 1.537 lines = 5;
2214 root 1.97
2215 pcg 1.1 # ifdef MOUSE_SLIP_WHEELING
2216 pcg 1.50 if (ev.state & ControlMask)
2217     {
2218 sf-exg 1.537 mouse_slip_wheel_speed += dirn;
2219 sf-exg 1.539 clamp_it (mouse_slip_wheel_speed, -nrow, nrow);
2220 root 1.107
2221 root 1.376 if (!slip_wheel_ev.is_active ())
2222     slip_wheel_ev.start (SCROLLBAR_CONTINUOUS_DELAY, SCROLLBAR_CONTINUOUS_DELAY);
2223 pcg 1.50 }
2224 root 1.107 else
2225 ayin 1.390 # endif
2226 root 1.107 {
2227 sf-exg 1.537 scr_page (dirn, lines);
2228 ayin 1.414 scrollBar.show (1);
2229 pcg 1.50 }
2230     }
2231     break;
2232 pcg 1.1 #endif
2233 pcg 1.36 }
2234     }
2235 pcg 1.1 }
2236    
2237     /*}}} */
2238    
2239 root 1.512 void ecb_hot
2240 pcg 1.81 rxvt_term::cmd_parse ()
2241     {
2242 root 1.245 wchar_t ch = NOCHAR;
2243 root 1.234 char *seq_begin; // remember start of esc-sequence here
2244 pcg 1.81
2245     for (;;)
2246     {
2247 sf-exg 1.488 if (ecb_unlikely (ch == NOCHAR))
2248 pcg 1.81 {
2249     seq_begin = cmdbuf_ptr;
2250     ch = next_char ();
2251 root 1.238
2252     if (ch == NOCHAR)
2253     break;
2254 pcg 1.81 }
2255    
2256 sf-exg 1.488 if (ecb_likely (!IS_CONTROL (ch) || ch == C0_LF || ch == C0_CR || ch == C0_HT))
2257 pcg 1.81 {
2258 sf-exg 1.488 if (ecb_unlikely (!seen_input))
2259 root 1.145 {
2260     seen_input = 1;
2261     // many badly-written programs (e.g. jed) contain a race condition:
2262     // they first read the screensize and then install a SIGWINCH handler.
2263     // some window managers resize the window early, and these programs
2264     // then sometimes get the size wrong.
2265 root 1.163 // unfortunately other programs are even more buggy and dislike
2266     // being sent SIGWINCH, so only do it when we were in fact being
2267     // resized.
2268 root 1.197 if (seen_resize && cmd_pid)
2269 root 1.163 kill (-cmd_pid, SIGWINCH);
2270 root 1.145 }
2271    
2272 pcg 1.81 /* Read a text string from the input buffer */
2273 root 1.245 wchar_t buf[UBUFSIZ];
2274 pcg 1.81 bool refreshnow = false;
2275     int nlines = 0;
2276 root 1.245 wchar_t *str = buf;
2277     wchar_t *eol = str + min (ncol, UBUFSIZ);
2278 pcg 1.81
2279     for (;;)
2280     {
2281 sf-exg 1.488 if (ecb_unlikely (ch == NOCHAR || (IS_CONTROL (ch) && ch != C0_LF && ch != C0_CR && ch != C0_HT)))
2282 pcg 1.81 break;
2283    
2284     *str++ = ch;
2285    
2286 sf-exg 1.488 if (ecb_unlikely (ch == C0_LF || str >= eol))
2287 pcg 1.81 {
2288 root 1.205 if (ch == C0_LF)
2289     nlines++;
2290    
2291 pcg 1.81 refresh_count++;
2292    
2293 root 1.330 if (!option (Opt_jumpScroll) || refresh_count >= nrow - 1)
2294 pcg 1.81 {
2295 root 1.226 refresh_count = 0;
2296 root 1.330
2297 root 1.367 if (!option (Opt_skipScroll) || ev_time () > ev::now () + 1. / 60.)
2298 root 1.330 {
2299     refreshnow = true;
2300     ch = NOCHAR;
2301     break;
2302     }
2303 pcg 1.81 }
2304    
2305 root 1.208 // scr_add_lines only works for nlines <= nrow - 1.
2306     if (nlines >= nrow - 1)
2307 pcg 1.81 {
2308 root 1.266 if (!(SHOULD_INVOKE (HOOK_ADD_LINES)
2309     && HOOK_INVOKE ((this, HOOK_ADD_LINES, DT_WCS_LEN, buf, str - buf, DT_END))))
2310 root 1.245 scr_add_lines (buf, str - buf, nlines);
2311 root 1.236
2312 pcg 1.81 nlines = 0;
2313     str = buf;
2314 root 1.208 eol = str + min (ncol, UBUFSIZ);
2315 root 1.204 }
2316    
2317     if (str >= eol)
2318     {
2319     if (eol >= buf + UBUFSIZ)
2320     {
2321     ch = NOCHAR;
2322     break;
2323     }
2324     else
2325 root 1.208 eol = min (eol + ncol, buf + UBUFSIZ);
2326 pcg 1.81 }
2327    
2328     }
2329 root 1.120
2330     seq_begin = cmdbuf_ptr;
2331     ch = next_char ();
2332 pcg 1.81 }
2333    
2334 root 1.266 if (!(SHOULD_INVOKE (HOOK_ADD_LINES)
2335     && HOOK_INVOKE ((this, HOOK_ADD_LINES, DT_WCS_LEN, buf, str - buf, DT_END))))
2336 root 1.245 scr_add_lines (buf, str - buf, nlines);
2337 pcg 1.81
2338     /*
2339     * If there have been a lot of new lines, then update the screen
2340 root 1.330 * What the heck we'll cheat and only refresh less than every page-full.
2341     * if skipScroll is enabled.
2342 pcg 1.81 */
2343     if (refreshnow)
2344     {
2345 root 1.330 scr_refresh ();
2346     want_refresh = 1;
2347 pcg 1.81 }
2348     }
2349     else
2350     {
2351     try
2352     {
2353     process_nonprinting (ch);
2354     }
2355     catch (const class out_of_input &o)
2356     {
2357     // we ran out of input, retry later
2358     cmdbuf_ptr = seq_begin;
2359     break;
2360     }
2361    
2362     ch = NOCHAR;
2363     }
2364     }
2365     }
2366    
2367     // read the next character
2368 root 1.512 wchar_t ecb_hot
2369 sf-exg 1.591 rxvt_term::next_char () noexcept
2370 pcg 1.81 {
2371     while (cmdbuf_ptr < cmdbuf_endp)
2372     {
2373 root 1.584 // assume 7-bit to be ascii ALWAYS (always true in POSIX)
2374     if (ecb_likely ((unsigned char)*cmdbuf_ptr <= 0x7f))
2375 pcg 1.81 return *cmdbuf_ptr++;
2376    
2377     wchar_t wc;
2378 root 1.234 size_t len = mbrtowc (&wc, cmdbuf_ptr, cmdbuf_endp - cmdbuf_ptr, mbstate);
2379 pcg 1.81
2380     if (len == (size_t)-2)
2381     {
2382     // the mbstate stores incomplete sequences. didn't know this :/
2383     cmdbuf_ptr = cmdbuf_endp;
2384     break;
2385     }
2386    
2387     if (len == (size_t)-1)
2388 root 1.415 {
2389 root 1.431 mbstate.reset (); // reset now undefined conversion state
2390 sf-exg 1.525 // a -1 might indicate that a previous incomplete char is invalid (previous return -2)
2391     // in which case we "erroneously" return the next byte which might be valid.
2392 root 1.415 return (unsigned char)*cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
2393     }
2394 pcg 1.81
2395     // assume wchar == unicode
2396     cmdbuf_ptr += len;
2397 root 1.183 return wc & UNICODE_MASK;
2398 pcg 1.81 }
2399    
2400     return NOCHAR;
2401     }
2402    
2403 root 1.245 // read the next octet
2404 root 1.512 uint32_t ecb_hot
2405 sf-exg 1.591 rxvt_term::next_octet () noexcept
2406 root 1.245 {
2407     return cmdbuf_ptr < cmdbuf_endp
2408 root 1.246 ? (unsigned char)*cmdbuf_ptr++
2409 root 1.245 : NOCHAR;
2410     }
2411    
2412 root 1.274 static class out_of_input out_of_input;
2413    
2414 root 1.512 wchar_t ecb_hot
2415 sf-exg 1.591 rxvt_term::cmd_getc ()
2416 pcg 1.81 {
2417 root 1.245 wchar_t c = next_char ();
2418 pcg 1.81
2419     if (c == NOCHAR)
2420     throw out_of_input;
2421    
2422     return c;
2423     }
2424    
2425 root 1.512 uint32_t ecb_hot
2426 sf-exg 1.591 rxvt_term::cmd_get8 ()
2427 root 1.97 {
2428 root 1.245 uint32_t c = next_octet ();
2429 root 1.97
2430     if (c == NOCHAR)
2431     throw out_of_input;
2432    
2433     return c;
2434     }
2435    
2436 pcg 1.1 /*{{{ print pipe */
2437     /*----------------------------------------------------------------------*/
2438     #ifdef PRINTPIPE
2439 root 1.512 FILE * ecb_cold
2440 pcg 1.34 rxvt_term::popen_printer ()
2441 pcg 1.1 {
2442 root 1.416 FILE *stream = popen (rs[Rs_print_pipe] ? rs[Rs_print_pipe] : PRINTPIPE, "w");
2443 pcg 1.1
2444 pcg 1.36 if (stream == NULL)
2445 pcg 1.81 rxvt_warn ("can't open printer pipe, not printing.\n");
2446    
2447 pcg 1.36 return stream;
2448 pcg 1.1 }
2449    
2450 root 1.512 int ecb_cold
2451 pcg 1.34 rxvt_term::pclose_printer (FILE *stream)
2452 pcg 1.1 {
2453 pcg 1.11 fflush (stream);
2454     return pclose (stream);
2455 pcg 1.1 }
2456    
2457     /*
2458     * simulate attached vt100 printer
2459     */
2460 root 1.512 void ecb_cold
2461 pcg 1.34 rxvt_term::process_print_pipe ()
2462 pcg 1.1 {
2463 root 1.416 FILE *fd = popen_printer ();
2464 pcg 1.36
2465 root 1.416 if (!fd)
2466 pcg 1.36 return;
2467    
2468     /*
2469     * Send all input to the printer until either ESC[4i or ESC[?4i
2470     * is received.
2471     */
2472 root 1.416 for (int done = 0; !done; )
2473 pcg 1.36 {
2474 pcg 1.81 unsigned char buf[8];
2475     unicode_t ch;
2476     unsigned int i, len;
2477 pcg 1.1
2478 pcg 1.36 if ((ch = cmd_getc ()) != C0_ESC)
2479     {
2480 pcg 1.43 if (putc (ch, fd) == EOF)
2481 pcg 1.36 break; /* done = 1 */
2482     }
2483     else
2484     {
2485     len = 0;
2486     buf[len++] = ch;
2487 pcg 1.1
2488 pcg 1.36 if ((buf[len++] = cmd_getc ()) == '[')
2489     {
2490     if ((ch = cmd_getc ()) == '?')
2491     {
2492     buf[len++] = '?';
2493     ch = cmd_getc ();
2494     }
2495     if ((buf[len++] = ch) == '4')
2496     {
2497     if ((buf[len++] = cmd_getc ()) == 'i')
2498     break; /* done = 1 */
2499     }
2500     }
2501 ayin 1.329
2502 pcg 1.36 for (i = 0; i < len; i++)
2503 pcg 1.43 if (putc (buf[i], fd) == EOF)
2504 pcg 1.36 {
2505     done = 1;
2506     break;
2507     }
2508     }
2509 pcg 1.1 }
2510 pcg 1.81
2511 pcg 1.36 pclose_printer (fd);
2512 pcg 1.1 }
2513 ayin 1.366 #endif /* PRINTPIPE */
2514 pcg 1.1 /*}}} */
2515    
2516     enum {
2517 pcg 1.36 C1_40 = 0x40,
2518 pcg 1.90 C1_41 , C1_BPH, C1_NBH, C1_44 , C1_NEL, C1_SSA, C1_ESA,
2519 pcg 1.36 C1_HTS, C1_HTJ, C1_VTS, C1_PLD, C1_PLU, C1_RI , C1_SS2, C1_SS3,
2520     C1_DCS, C1_PU1, C1_PU2, C1_STS, C1_CCH, C1_MW , C1_SPA, C1_EPA,
2521 pcg 1.90 C1_SOS, C1_59 , C1_SCI, C1_CSI, CS_ST , C1_OSC, C1_PM , C1_APC,
2522 pcg 1.1 };
2523    
2524     /*{{{ process non-printing single characters */
2525 root 1.512 void ecb_hot
2526 pcg 1.81 rxvt_term::process_nonprinting (unicode_t ch)
2527 pcg 1.1 {
2528 pcg 1.36 switch (ch)
2529     {
2530 pcg 1.81 case C0_ESC:
2531     process_escape_seq ();
2532     break;
2533 pcg 1.36 case C0_ENQ: /* terminal Status */
2534     if (rs[Rs_answerbackstring])
2535 root 1.234 tt_write (rs [Rs_answerbackstring], strlen (rs [Rs_answerbackstring]));
2536 pcg 1.36 else
2537 root 1.234 tt_write (VT100_ANS, strlen (VT100_ANS));
2538 pcg 1.36 break;
2539     case C0_BEL: /* bell */
2540     scr_bell ();
2541     break;
2542     case C0_BS: /* backspace */
2543     scr_backspace ();
2544     break;
2545     case C0_HT: /* tab */
2546     scr_tab (1);
2547     break;
2548     case C0_CR: /* carriage return */
2549     scr_gotorc (0, 0, R_RELATIVE);
2550     break;
2551     case C0_VT: /* vertical tab, form feed */
2552     case C0_FF:
2553     case C0_LF: /* line feed */
2554     scr_index (UP);
2555     break;
2556     case C0_SO: /* shift out - acs */
2557     scr_charset_choose (1);
2558     break;
2559     case C0_SI: /* shift in - acs */
2560     scr_charset_choose (0);
2561     break;
2562 pcg 1.81
2563 root 1.97 #ifdef EIGHT_BIT_CONTROLS
2564 pcg 1.81 // 8-bit controls
2565 root 1.559 case 0x90: /* DCS */
2566 pcg 1.81 process_dcs_seq ();
2567     break;
2568 root 1.559 case 0x9b: /* CSI */
2569 pcg 1.81 process_csi_seq ();
2570     break;
2571 root 1.559 case 0x9d: /* OSC */
2572 pcg 1.81 process_osc_seq ();
2573     break;
2574 root 1.97 #endif
2575 pcg 1.1 }
2576     }
2577     /*}}} */
2578    
2579    
2580     /*{{{ process VT52 escape sequences */
2581 root 1.512 void ecb_cold
2582 pcg 1.81 rxvt_term::process_escape_vt52 (unicode_t ch)
2583 pcg 1.1 {
2584 pcg 1.36 int row, col;
2585    
2586     switch (ch)
2587     {
2588     case 'A': /* cursor up */
2589     scr_gotorc (-1, 0, R_RELATIVE | C_RELATIVE);
2590     break;
2591     case 'B': /* cursor down */
2592     scr_gotorc (1, 0, R_RELATIVE | C_RELATIVE);
2593     break;
2594     case 'C': /* cursor right */
2595     scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
2596     break;
2597     case 'D': /* cursor left */
2598     scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
2599     break;
2600     case 'H': /* cursor home */
2601     scr_gotorc (0, 0, 0);
2602     break;
2603     case 'I': /* cursor up and scroll down if needed */
2604     scr_index (DN);
2605     break;
2606     case 'J': /* erase to end of screen */
2607     scr_erase_screen (0);
2608     break;
2609     case 'K': /* erase to end of line */
2610     scr_erase_line (0);
2611     break;
2612     case 'Y': /* move to specified row and col */
2613     /* full command is 'ESC Y row col' where row and col
2614     * are encoded by adding 32 and sending the ascii
2615     * character. eg. SPACE = 0, '+' = 13, '0' = 18,
2616     * etc. */
2617     row = cmd_getc () - ' ';
2618     col = cmd_getc () - ' ';
2619     scr_gotorc (row, col, 0);
2620     break;
2621     case 'Z': /* identify the terminal type */
2622 pcg 1.43 tt_printf ("\033/Z"); /* I am a VT100 emulating a VT52 */
2623 pcg 1.1 break;
2624 pcg 1.36 case '<': /* turn off VT52 mode */
2625 sf-exg 1.496 priv_modes &= ~PrivMode_vt52;
2626 pcg 1.36 break;
2627     case 'F': /* use special graphics character set */
2628     case 'G': /* use regular character set */
2629     /* unimplemented */
2630     break;
2631     case '=': /* use alternate keypad mode */
2632     case '>': /* use regular keypad mode */
2633     /* unimplemented */
2634     break;
2635 pcg 1.1 }
2636     }
2637     /*}}} */
2638    
2639    
2640     /*{{{ process escape sequences */
2641 root 1.512 void ecb_hot
2642 pcg 1.34 rxvt_term::process_escape_seq ()
2643 pcg 1.1 {
2644 pcg 1.81 unicode_t ch = cmd_getc ();
2645 pcg 1.36
2646 root 1.145 if (priv_modes & PrivMode_vt52)
2647 pcg 1.36 {
2648     process_escape_vt52 (ch);
2649     return;
2650     }
2651 pcg 1.1
2652 pcg 1.36 switch (ch)
2653     {
2654     case '#':
2655     if (cmd_getc () == '8')
2656     scr_E ();
2657     break;
2658 pcg 1.44 case '(':
2659 pcg 1.36 scr_charset_set (0, (unsigned int)cmd_getc ());
2660     break;
2661     case ')':
2662     scr_charset_set (1, (unsigned int)cmd_getc ());
2663     break;
2664     case '*':
2665     scr_charset_set (2, (unsigned int)cmd_getc ());
2666     break;
2667     case '+':
2668     scr_charset_set (3, (unsigned int)cmd_getc ());
2669     break;
2670 root 1.294 #if !ENABLE_MINIMAL
2671 pcg 1.36 case '6':
2672     scr_backindex ();
2673     break;
2674     #endif
2675     case '7':
2676     scr_cursor (SAVE);
2677     break;
2678     case '8':
2679     scr_cursor (RESTORE);
2680     break;
2681 root 1.294 #if !ENABLE_MINIMAL
2682 pcg 1.36 case '9':
2683     scr_forwardindex ();
2684     break;
2685     #endif
2686 sf-exg 1.490 // DECPAM/DECPNM
2687 pcg 1.36 case '=':
2688 sf-exg 1.496 priv_modes |= PrivMode_aplKP;
2689     break;
2690 pcg 1.36 case '>':
2691 sf-exg 1.496 priv_modes &= ~PrivMode_aplKP;
2692 pcg 1.36 break;
2693    
2694     case C1_40:
2695     cmd_getc ();
2696     break;
2697     case C1_44:
2698     scr_index (UP);
2699     break;
2700 pcg 1.1
2701 pcg 1.36 /* 8.3.87: NEXT LINE */
2702     case C1_NEL: /* ESC E */
2703 pcg 1.1 {
2704 root 1.245 wchar_t nlcr[] = { C0_LF, C0_CR };
2705 sf-exg 1.488 scr_add_lines (nlcr, ecb_array_length (nlcr), 1);
2706 pcg 1.1 }
2707 pcg 1.36 break;
2708    
2709 root 1.585 #if 0 // disabled because embedded newlines can make exploits easier
2710 pcg 1.36 /* kidnapped escape sequence: Should be 8.3.48 */
2711     case C1_ESA: /* ESC G */
2712 root 1.479 // used by original rxvt for rob nations own graphics mode
2713 root 1.583 if (cmd_getc () == 'Q' && option (Opt_insecure))
2714 root 1.479 tt_printf ("\033G0\012"); /* query graphics - no graphics */
2715 pcg 1.36 break;
2716 root 1.585 #endif
2717 pcg 1.36
2718     /* 8.3.63: CHARACTER TABULATION SET */
2719     case C1_HTS: /* ESC H */
2720     scr_set_tab (1);
2721     break;
2722    
2723     /* 8.3.105: REVERSE LINE FEED */
2724     case C1_RI: /* ESC M */
2725     scr_index (DN);
2726     break;
2727    
2728     /* 8.3.142: SINGLE-SHIFT TWO */
2729 sf-exg 1.487 /* case C1_SS2: break; */
2730 pcg 1.36
2731     /* 8.3.143: SINGLE-SHIFT THREE */
2732 sf-exg 1.487 /* case C1_SS3: break; */
2733 pcg 1.36
2734     /* 8.3.27: DEVICE CONTROL STRING */
2735     case C1_DCS: /* ESC P */
2736     process_dcs_seq ();
2737     break;
2738    
2739     /* 8.3.110: SINGLE CHARACTER INTRODUCER */
2740     case C1_SCI: /* ESC Z */
2741 root 1.234 tt_write (ESCZ_ANSWER, sizeof (ESCZ_ANSWER) - 1);
2742 pcg 1.36 break; /* steal obsolete ESC [ c */
2743    
2744 root 1.423 /* 8.3.16: CONTROL SEQUENCE INTRODUCER (CSI) */
2745 pcg 1.36 case C1_CSI: /* ESC [ */
2746     process_csi_seq ();
2747     break;
2748 pcg 1.1
2749 root 1.423 /* 8.3.90: OPERATING SYSTEM COMMAND (OSC) */
2750 pcg 1.36 case C1_OSC: /* ESC ] */
2751     process_osc_seq ();
2752     break;
2753    
2754 root 1.423 /* 8.3.106: RESET TO INITIAL STATE (RIS) */
2755 pcg 1.36 case 'c':
2756 pcg 1.90 mbstate.reset ();
2757 pcg 1.36 scr_poweron ();
2758 ayin 1.414 scrollBar.show (1);
2759 pcg 1.36 break;
2760    
2761     /* 8.3.79: LOCKING-SHIFT TWO (see ISO2022) */
2762     case 'n':
2763     scr_charset_choose (2);
2764     break;
2765    
2766     /* 8.3.81: LOCKING-SHIFT THREE (see ISO2022) */
2767     case 'o':
2768     scr_charset_choose (3);
2769     break;
2770 pcg 1.1 }
2771     }
2772     /*}}} */
2773    
2774     /*{{{ process CONTROL SEQUENCE INTRODUCER (CSI) sequences `ESC[' */
2775     enum {
2776 pcg 1.36 CSI_ICH = 0x40,
2777 pcg 1.95 CSI_CUU, CSI_CUD, CSI_CUF, CSI_CUB, CSI_CNL, CSI_CPL, CSI_CHA,
2778 pcg 1.36 CSI_CUP, CSI_CHT, CSI_ED , CSI_EL , CSI_IL , CSI_DL , CSI_EF , CSI_EA ,
2779     CSI_DCH, CSI_SEE, CSI_CPR, CSI_SU , CSI_SD , CSI_NP , CSI_PP , CSI_CTC,
2780     CSI_ECH, CSI_CVT, CSI_CBT, CSI_SRS, CSI_PTX, CSI_SDS, CSI_SIMD, CSI_5F,
2781     CSI_HPA, CSI_HPR, CSI_REP, CSI_DA , CSI_VPA, CSI_VPR, CSI_HVP, CSI_TBC,
2782     CSI_SM , CSI_MC , CSI_HPB, CSI_VPB, CSI_RM , CSI_SGR, CSI_DSR, CSI_DAQ,
2783     CSI_70 , CSI_71 , CSI_72 , CSI_73 , CSI_74 , CSI_75 , CSI_76 , CSI_77 ,
2784     CSI_78 , CSI_79 , CSI_7A , CSI_7B , CSI_7C , CSI_7D , CSI_7E , CSI_7F
2785 pcg 1.1 };
2786    
2787 sf-exg 1.465 #define make_byte(b0,b1,b2,b3,b4,b5,b6,b7) \
2788 pcg 1.1 (((b7) << 7) | ((b6) << 6) | ((b5) << 5) | ((b4) << 4) \
2789     | ((b3) << 3) | ((b2) << 2) | ((b1) << 1) | (b0))
2790     #define get_byte_array_bit(array, bit) \
2791 sf-exg 1.465 (!! ((array)[(bit) >> 3] & (1 << ((bit) & 7))))
2792 pcg 1.1
2793 sf-exg 1.464 static const unsigned char csi_defaults[] =
2794 pcg 1.36 {
2795 pcg 1.43 make_byte (1,1,1,1,1,1,1,1), /* @, A, B, C, D, E, F, G, */
2796     make_byte (1,1,0,0,1,1,0,0), /* H, I, J, K, L, M, N, O, */
2797     make_byte (1,0,1,1,1,1,1,0), /* P, Q, R, S, T, U, V, W, */
2798     make_byte (1,1,1,0,0,0,1,0), /* X, Y, Z, [, \, ], ^, _, */
2799     make_byte (1,1,1,0,1,1,1,0), /* `, a, b, c, d, e, f, g, */
2800     make_byte (0,0,1,1,0,0,0,0), /* h, i, j, k, l, m, n, o, */
2801     make_byte (0,0,0,0,0,0,0,0), /* p, q, r, s, t, u, v, w, */
2802 pcg 1.90 make_byte (0,0,0,0,0,0,0,0), /* x, y, z, {, |, }, ~, */
2803 pcg 1.36 };
2804 pcg 1.1
2805 root 1.512 void ecb_hot
2806 pcg 1.34 rxvt_term::process_csi_seq ()
2807 pcg 1.1 {
2808 sf-exg 1.534 unicode_t ch, priv, prev_ch, i;
2809 pcg 1.81 unsigned int nargs, p;
2810     int n, ndef;
2811 ayin 1.349 int arg[ESC_ARGS] = { };
2812 pcg 1.36
2813 ayin 1.335 nargs = 0;
2814 pcg 1.36
2815     priv = 0;
2816     ch = cmd_getc ();
2817 root 1.423 if ((ch >= '<' && ch <= '?') || ch == '!')
2818 ayin 1.369 {
2819 root 1.423 /* '<' '=' '>' '?' '!' */
2820 pcg 1.36 priv = ch;
2821     ch = cmd_getc ();
2822     }
2823 pcg 1.81
2824 sf-exg 1.534 prev_ch = 0;
2825 pcg 1.36 /* read any numerical arguments */
2826     for (n = -1; ch < CSI_ICH; )
2827     {
2828 pcg 1.43 if (isdigit (ch))
2829 pcg 1.36 {
2830     if (n < 0)
2831     n = ch - '0';
2832     else
2833     n = n * 10 + ch - '0';
2834     }
2835     else if (ch == ';')
2836     {
2837     if (nargs < ESC_ARGS)
2838     arg[nargs++] = n;
2839     n = -1;
2840     }
2841 pcg 1.81 else if (IS_CONTROL (ch))
2842     process_nonprinting (ch);
2843    
2844 sf-exg 1.534 prev_ch = ch;
2845 pcg 1.36 ch = cmd_getc ();
2846     }
2847 pcg 1.1
2848 pcg 1.36 if (ch > CSI_7F)
2849     return;
2850 pcg 1.1
2851 pcg 1.36 if (nargs < ESC_ARGS)
2852     arg[nargs++] = n;
2853    
2854     i = ch - CSI_ICH;
2855 pcg 1.43 ndef = get_byte_array_bit (csi_defaults, i);
2856 pcg 1.36 for (p = 0; p < nargs; p++)
2857     if (arg[p] == -1)
2858     arg[p] = ndef;
2859 pcg 1.1
2860 pcg 1.36 /*
2861     * private mode handling
2862     */
2863     if (priv)
2864     {
2865     switch (priv)
2866     {
2867     case '>':
2868     if (ch == CSI_DA) /* secondary device attributes */
2869 root 1.282 {
2870 ayin 1.334 // first parameter is normally 0 for vt100, 1 for vt220, 'R' for rxvt,
2871 root 1.289 // 'U' for rxvt-unicode != 7.[34] (where it was broken).
2872 root 1.282 //
2873     // second parameter is xterm patch level for xterm, MMmmpp (e.g. 20703) for rxvt
2874 ayin 1.360 // and Mm (e.g. 72 for 7.2) for urxvt <= 7.2, 94 for urxvt <= 8.3, and 95 for later
2875     // versions.
2876 root 1.282 //
2877 ayin 1.360 tt_printf ("\033[>%d;95;0c", 'U');
2878 root 1.282 }
2879 pcg 1.36 break;
2880 root 1.395
2881 pcg 1.36 case '?':
2882     if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
2883     process_terminal_mode (ch, priv, nargs, arg);
2884 sf-exg 1.589 if (prev_ch == '$' && ch == 'p')
2885     process_terminal_mode (ch, priv, nargs, arg);
2886 pcg 1.36 break;
2887 root 1.423
2888     case '!':
2889     if (ch == CSI_70)
2890     {
2891     /* DECSTR: soft terminal reset, used by our terminfo since 9.06 */
2892     scr_soft_reset ();
2893    
2894     static const int pm_h[] = { 7, 25 };
2895 sf-exg 1.586 static const int pm_l[] = { 1, 3, 4, 5, 6, 9, 66, 1000, 1001, 1005, 1006, 1015, 1049 };
2896 root 1.423
2897 sf-exg 1.488 process_terminal_mode ('h', 0, ecb_array_length (pm_h), pm_h);
2898     process_terminal_mode ('l', 0, ecb_array_length (pm_l), pm_l);
2899 root 1.423 }
2900     break;
2901 pcg 1.36 }
2902 root 1.423
2903 pcg 1.36 return;
2904 pcg 1.1 }
2905    
2906 pcg 1.36 switch (ch)
2907     {
2908     /*
2909 pcg 1.43 * ISO/IEC 6429:1992 (E) CSI sequences (defaults in parentheses)
2910 pcg 1.36 */
2911 pcg 1.1 #ifdef PRINTPIPE
2912 pcg 1.36 case CSI_MC: /* 8.3.83: (0) MEDIA COPY */
2913     switch (arg[0])
2914     {
2915     case 0: /* initiate transfer to primary aux device */
2916     scr_printscreen (0);
2917     break;
2918     case 5: /* start relay to primary aux device */
2919     process_print_pipe ();
2920     break;
2921     }
2922     break;
2923     #endif
2924 pcg 1.1
2925 pcg 1.36 case CSI_CUU: /* 8.3.22: (1) CURSOR UP */
2926 root 1.499 case CSI_VPB: /* 8.3.160: (1) LINE POSITION BACKWARD */
2927 pcg 1.36 arg[0] = -arg[0];
2928     /* FALLTHROUGH */
2929     case CSI_CUD: /* 8.3.19: (1) CURSOR DOWN */
2930 root 1.499 case CSI_VPR: /* 8.3.161: (1) LINE POSITION FORWARD */
2931 pcg 1.36 scr_gotorc (arg[0], 0, RELATIVE);
2932     break;
2933    
2934     case CSI_CUB: /* 8.3.18: (1) CURSOR LEFT */
2935 root 1.583 case CSI_HPB: /* 8.3.59: (1) CHARACTER POSITION BACKWARD */
2936 pcg 1.1 #ifdef ISO6429
2937 pcg 1.36 arg[0] = -arg[0];
2938 pcg 1.1 #else /* emulate common DEC VTs */
2939 pcg 1.36 arg[0] = arg[0] ? -arg[0] : -1;
2940 pcg 1.1 #endif
2941 pcg 1.36 /* FALLTHROUGH */
2942     case CSI_CUF: /* 8.3.20: (1) CURSOR RIGHT */
2943     case CSI_HPR: /* 8.3.60: (1) CHARACTER POSITION FORWARD */
2944 pcg 1.1 #ifdef ISO6429
2945 pcg 1.36 scr_gotorc (0, arg[0], RELATIVE);
2946 pcg 1.1 #else /* emulate common DEC VTs */
2947 pcg 1.36 scr_gotorc (0, arg[0] ? arg[0] : 1, RELATIVE);
2948 pcg 1.1 #endif
2949 pcg 1.36 break;
2950    
2951     case CSI_CPL: /* 8.3.13: (1) CURSOR PRECEDING LINE */
2952     arg[0] = -arg[0];
2953     /* FALLTHROUGH */
2954     case CSI_CNL: /* 8.3.12: (1) CURSOR NEXT LINE */
2955     scr_gotorc (arg[0], 0, R_RELATIVE);
2956     break;
2957    
2958     case CSI_CHA: /* 8.3.9: (1) CURSOR CHARACTER ABSOLUTE */
2959     case CSI_HPA: /* 8.3.58: (1) CURSOR POSITION ABSOLUTE */
2960     scr_gotorc (0, arg[0] - 1, R_RELATIVE);
2961     break;
2962    
2963     case CSI_VPA: /* 8.3.159: (1) LINE POSITION ABSOLUTE */
2964     scr_gotorc (arg[0] - 1, 0, C_RELATIVE);
2965     break;
2966    
2967     case CSI_CUP: /* 8.3.21: (1,1) CURSOR POSITION */
2968     case CSI_HVP: /* 8.3.64: (1,1) CHARACTER AND LINE POSITION */
2969     scr_gotorc (arg[0] - 1, nargs < 2 ? 0 : (arg[1] - 1), 0);
2970     break;
2971 pcg 1.1
2972 pcg 1.36 case CSI_CBT: /* 8.3.7: (1) CURSOR BACKWARD TABULATION */
2973     arg[0] = -arg[0];
2974     /* FALLTHROUGH */
2975     case CSI_CHT: /* 8.3.10: (1) CURSOR FORWARD TABULATION */
2976     scr_tab (arg[0]);
2977     break;
2978    
2979     case CSI_ED: /* 8.3.40: (0) ERASE IN PAGE */
2980     scr_erase_screen (arg[0]);
2981     break;
2982    
2983     case CSI_EL: /* 8.3.42: (0) ERASE IN LINE */
2984     scr_erase_line (arg[0]);
2985     break;
2986    
2987     case CSI_ICH: /* 8.3.65: (1) INSERT CHARACTER */
2988     scr_insdel_chars (arg[0], INSERT);
2989     break;
2990    
2991     case CSI_IL: /* 8.3.68: (1) INSERT LINE */
2992     scr_insdel_lines (arg[0], INSERT);
2993     break;
2994    
2995     case CSI_DL: /* 8.3.33: (1) DELETE LINE */
2996     scr_insdel_lines (arg[0], DELETE);
2997     break;
2998    
2999     case CSI_ECH: /* 8.3.39: (1) ERASE CHARACTER */
3000     scr_insdel_chars (arg[0], ERASE);
3001     break;
3002    
3003     case CSI_DCH: /* 8.3.26: (1) DELETE CHARACTER */
3004     scr_insdel_chars (arg[0], DELETE);
3005     break;
3006    
3007     case CSI_SD: /* 8.3.114: (1) SCROLL DOWN */
3008     arg[0] = -arg[0];
3009     /* FALLTHROUGH */
3010     case CSI_SU: /* 8.3.148: (1) SCROLL UP */
3011 root 1.210 scr_scroll_text (screen.tscroll, screen.bscroll, arg[0]);
3012 pcg 1.36 break;
3013    
3014     case CSI_DA: /* 8.3.24: (0) DEVICE ATTRIBUTES */
3015 root 1.234 tt_write (VT100_ANS, sizeof (VT100_ANS) - 1);
3016 pcg 1.36 break;
3017    
3018     case CSI_SGR: /* 8.3.118: (0) SELECT GRAPHIC RENDITION */
3019     process_sgr_mode (nargs, arg);
3020     break;
3021    
3022     case CSI_DSR: /* 8.3.36: (0) DEVICE STATUS REPORT */
3023     switch (arg[0])
3024     {
3025     case 5: /* DSR requested */
3026 pcg 1.43 tt_printf ("\033[0n");
3027 pcg 1.36 break;
3028     case 6: /* CPR requested */
3029     scr_report_position ();
3030     break;
3031     case 7: /* unofficial extension */
3032 root 1.321 if (option (Opt_insecure))
3033 root 1.145 tt_printf ("%-.250s\012", rs[Rs_display_name]);
3034 pcg 1.36 break;
3035     case 8: /* unofficial extension */
3036 sf-exg 1.600 {
3037     string_term st;
3038     st.v[0] = CHAR_ST;
3039     st.v[1] = '\0';
3040     process_xterm_seq (XTerm_title, (char *)RESNAME "-" VERSION, st); // char * cast verified
3041     break;
3042     }
3043 pcg 1.36 }
3044     break;
3045 pcg 1.1
3046 pcg 1.36 case CSI_TBC: /* 8.3.155: (0) TABULATION CLEAR */
3047     switch (arg[0])
3048     {
3049     case 0: /* char tab stop cleared at active position */
3050     scr_set_tab (0);
3051     break;
3052     /* case 1: */ /* line tab stop cleared in active line */
3053     /* case 2: */ /* char tab stops cleared in active line */
3054     case 3: /* all char tab stops are cleared */
3055     /* case 4: */ /* all line tab stops are cleared */
3056     case 5: /* all tab stops are cleared */
3057     scr_set_tab (-1);
3058     break;
3059     }
3060     break;
3061    
3062     case CSI_CTC: /* 8.3.17: (0) CURSOR TABULATION CONTROL */
3063     switch (arg[0])
3064     {
3065     case 0: /* char tab stop set at active position */
3066     scr_set_tab (1);
3067     break; /* = ESC H */
3068     /* case 1: */ /* line tab stop set at active line */
3069     case 2: /* char tab stop cleared at active position */
3070     scr_set_tab (0);
3071     break; /* = ESC [ 0 g */
3072     /* case 3: */ /* line tab stop cleared at active line */
3073     /* case 4: */ /* char tab stops cleared at active line */
3074     case 5: /* all char tab stops are cleared */
3075     scr_set_tab (-1);
3076     break; /* = ESC [ 3 g */
3077     /* case 6: */ /* all line tab stops are cleared */
3078     }
3079     break;
3080    
3081     case CSI_RM: /* 8.3.107: RESET MODE */
3082     if (arg[0] == 4)
3083     scr_insert_mode (0);
3084 root 1.145 else if (arg[0] == 20)
3085     priv_modes &= ~PrivMode_LFNL;
3086 pcg 1.36 break;
3087    
3088     case CSI_SM: /* 8.3.126: SET MODE */
3089     if (arg[0] == 4)
3090     scr_insert_mode (1);
3091 root 1.145 else if (arg[0] == 20)
3092     priv_modes |= PrivMode_LFNL;
3093 pcg 1.36 break;
3094    
3095 sf-exg 1.556 case CSI_71: // DECSCUSR: set cursor style
3096 sf-exg 1.534 if (prev_ch == ' ')
3097     set_cursor_style (arg[0]);
3098     break;
3099    
3100 pcg 1.36 /*
3101     * PRIVATE USE beyond this point. All CSI_7? sequences here
3102     */
3103     case CSI_72: /* DECSTBM: set top and bottom margins */
3104     if (nargs == 1)
3105     scr_scroll_region (arg[0] - 1, MAX_ROWS - 1);
3106     else if (nargs == 0 || arg[0] >= arg[1])
3107     scr_scroll_region (0, MAX_ROWS - 1);
3108     else
3109     scr_scroll_region (arg[0] - 1, arg[1] - 1);
3110     break;
3111    
3112     case CSI_73:
3113     scr_cursor (SAVE);
3114     break;
3115     case CSI_75:
3116     scr_cursor (RESTORE);
3117     break;
3118 pcg 1.1
3119 root 1.294 #if !ENABLE_MINIMAL
3120 pcg 1.36 case CSI_74:
3121     process_window_ops (arg, nargs);
3122     break;
3123 pcg 1.1 #endif
3124    
3125 pcg 1.36 case CSI_78: /* DECREQTPARM */
3126     if (arg[0] == 0 || arg[0] == 1)
3127 pcg 1.43 tt_printf ("\033[%d;1;1;128;128;1;0x", arg[0] + 2);
3128 pcg 1.81 break;
3129 pcg 1.1
3130 pcg 1.36 default:
3131     break;
3132 pcg 1.1 }
3133     }
3134     /*}}} */
3135    
3136 root 1.294 #if !ENABLE_MINIMAL
3137 pcg 1.1 void
3138 pcg 1.34 rxvt_term::process_window_ops (const int *args, unsigned int nargs)
3139 pcg 1.1 {
3140 pcg 1.81 int x, y;
3141 pcg 1.36 XWindowAttributes wattr;
3142 pcg 1.81 Window wdummy;
3143 root 1.285
3144 root 1.305 dLocal (Display *, dpy);
3145 pcg 1.1
3146 pcg 1.36 if (nargs == 0)
3147     return;
3148 pcg 1.81
3149 pcg 1.36 switch (args[0])
3150     {
3151 pcg 1.81 /*
3152     * commands
3153     */
3154 pcg 1.36 case 1: /* deiconify window */
3155 sf-exg 1.482 XMapWindow (dpy, parent);
3156 pcg 1.36 break;
3157     case 2: /* iconify window */
3158 sf-exg 1.482 XIconifyWindow (dpy, parent, display->screen);
3159 pcg 1.36 break;
3160     case 3: /* set position (pixels) */
3161 sf-exg 1.482 XMoveWindow (dpy, parent, args[1], args[2]);
3162 pcg 1.36 break;
3163     case 4: /* set size (pixels) */
3164     set_widthheight ((unsigned int)args[2], (unsigned int)args[1]);
3165     break;
3166     case 5: /* raise window */
3167 sf-exg 1.482 XRaiseWindow (dpy, parent);
3168 pcg 1.36 break;
3169     case 6: /* lower window */
3170 sf-exg 1.482 XLowerWindow (dpy, parent);
3171 pcg 1.36 break;
3172     case 7: /* refresh window */
3173     scr_touch (true);
3174     break;
3175     case 8: /* set size (chars) */
3176 root 1.208 set_widthheight ((unsigned int) (args[2] * fwidth),
3177     (unsigned int) (args[1] * fheight));
3178 pcg 1.36 break;
3179 pcg 1.81
3180     //case 9: NYI, TODO, restore maximized window or maximize window
3181 pcg 1.36 default:
3182     if (args[0] >= 24) /* set height (chars) */
3183 sf-exg 1.504 set_widthheight ((unsigned int)vt_width,
3184 root 1.208 (unsigned int) (args[1] * fheight));
3185 pcg 1.36 break;
3186 pcg 1.81
3187     /*
3188     * reports - some output format copied from XTerm
3189     */
3190 pcg 1.36 case 11: /* report window state */
3191 sf-exg 1.482 XGetWindowAttributes (dpy, parent, &wattr);
3192 pcg 1.43 tt_printf ("\033[%dt", wattr.map_state == IsViewable ? 1 : 2);
3193 pcg 1.36 break;
3194     case 13: /* report window position */
3195 sf-exg 1.482 XGetWindowAttributes (dpy, parent, &wattr);
3196     XTranslateCoordinates (dpy, parent, wattr.root,
3197 pcg 1.90 -wattr.border_width, -wattr.border_width,
3198     &x, &y, &wdummy);
3199 pcg 1.43 tt_printf ("\033[3;%d;%dt", x, y);
3200 pcg 1.36 break;
3201     case 14: /* report window size (pixels) */
3202 sf-exg 1.482 XGetWindowAttributes (dpy, parent, &wattr);
3203 pcg 1.43 tt_printf ("\033[4;%d;%dt", wattr.height, wattr.width);
3204 pcg 1.36 break;
3205 pcg 1.81 case 18: /* report text area size (chars) */
3206 root 1.208 tt_printf ("\033[8;%d;%dt", nrow, ncol);
3207 pcg 1.36 break;
3208 pcg 1.81 case 19: /* report window size (chars) */
3209 root 1.208 tt_printf ("\033[9;%d;%dt", nrow, ncol);
3210 pcg 1.81 break;
3211 pcg 1.36 case 20: /* report icon label */
3212 root 1.131 {
3213     char *s;
3214 sf-exg 1.482 XGetIconName (dpy, parent, &s);
3215 root 1.321 tt_printf ("\033]L%-.250s\234", option (Opt_insecure) && s ? s : ""); /* 8bit ST */
3216 root 1.131 XFree (s);
3217     }
3218 pcg 1.36 break;
3219     case 21: /* report window title */
3220 root 1.131 {
3221     char *s;
3222 sf-exg 1.482 XFetchName (dpy, parent, &s);
3223 root 1.321 tt_printf ("\033]l%-.250s\234", option (Opt_insecure) && s ? s : ""); /* 8bit ST */
3224 root 1.131 XFree (s);
3225     }
3226 pcg 1.36 break;
3227 pcg 1.1 }
3228     }
3229     #endif
3230    
3231     /*----------------------------------------------------------------------*/
3232     /*
3233     * get input up until STRING TERMINATOR (or BEL)
3234 pcg 1.93 * ends_how is terminator used. returned input must be free()'d
3235 pcg 1.1 */
3236 root 1.234 char *
3237 sf-exg 1.600 rxvt_term::get_to_st (string_term &st)
3238 pcg 1.1 {
3239 root 1.175 unicode_t ch;
3240     bool seen_esc = false;
3241 pcg 1.81 unsigned int n = 0;
3242 root 1.541 wchar_t string[CBUFSIZ];
3243 pcg 1.36
3244 root 1.97 while ((ch = cmd_getc ()) != NOCHAR)
3245 pcg 1.36 {
3246 root 1.163 if (seen_esc)
3247 pcg 1.36 {
3248 root 1.97 if (ch == 0x5c) /* 7bit ST */
3249     break;
3250     else
3251     return NULL;
3252 pcg 1.36 }
3253 root 1.163 else if (ch == C0_ESC)
3254     {
3255 root 1.175 seen_esc = true;
3256 root 1.163 continue;
3257     }
3258 root 1.97 else if (ch == C0_BEL || ch == CHAR_ST)
3259     break;
3260 root 1.315 else if (ch == C0_SYN)
3261     ch = cmd_get8 ();
3262 root 1.97 else if (ch < 0x20)
3263 pcg 1.36 return NULL; /* other control character - exit */
3264 pcg 1.81
3265 root 1.175 seen_esc = false;
3266 root 1.163
3267 root 1.541 if (n >= sizeof (string) - 1)
3268 pcg 1.90 // stop at some sane length
3269     return NULL;
3270 pcg 1.81
3271 root 1.315 string[n++] = ch;
3272 pcg 1.36 }
3273 pcg 1.81
3274 pcg 1.36 string[n++] = '\0';
3275 pcg 1.81
3276 sf-exg 1.600 n = 0;
3277     if (ch == 0x5c)
3278     st.v[n++] = C0_ESC;
3279     st.v[n++] = ch;
3280     st.v[n] = '\0';
3281 pcg 1.81
3282 root 1.234 return rxvt_wcstombs (string);
3283 pcg 1.1 }
3284    
3285     /*----------------------------------------------------------------------*/
3286     /*
3287     * process DEVICE CONTROL STRING `ESC P ... (ST|BEL)' or `0x90 ... (ST|BEL)'
3288     */
3289     void
3290 pcg 1.34 rxvt_term::process_dcs_seq ()
3291 pcg 1.1 {
3292 pcg 1.36 /*
3293     * Not handled yet
3294     */
3295 root 1.451
3296 sf-exg 1.600 string_term st;
3297     char *s = get_to_st (st);
3298 pcg 1.36 if (s)
3299 pcg 1.43 free (s);
3300 pcg 1.81
3301 pcg 1.36 return;
3302 pcg 1.1 }
3303    
3304     /*----------------------------------------------------------------------*/
3305     /*
3306     * process OPERATING SYSTEM COMMAND sequence `ESC ] Ps ; Pt (ST|BEL)'
3307     */
3308     void
3309 pcg 1.34 rxvt_term::process_osc_seq ()
3310 pcg 1.1 {
3311 pcg 1.81 int arg;
3312 pcg 1.1
3313 root 1.451 unicode_t ch = cmd_getc ();
3314 pcg 1.43 for (arg = 0; isdigit (ch); ch = cmd_getc ())
3315 pcg 1.36 arg = arg * 10 + (ch - '0');
3316 pcg 1.1
3317 pcg 1.36 if (ch == ';')
3318     {
3319 sf-exg 1.600 string_term st;
3320     char *s = get_to_st (st);
3321 pcg 1.81
3322 pcg 1.36 if (s)
3323     {
3324 sf-exg 1.600 process_xterm_seq (arg, s, st);
3325 pcg 1.90 free (s);
3326     }
3327     }
3328     }
3329 pcg 1.81
3330 sf-exg 1.571 static unsigned int
3331     colorcube_index (unsigned int idx_r,
3332     unsigned int idx_g,
3333     unsigned int idx_b)
3334     {
3335     assert (idx_r < Red_levels);
3336     assert (idx_g < Green_levels);
3337     assert (idx_b < Blue_levels);
3338    
3339     return idx_r * Blue_levels * Green_levels +
3340     idx_g * Blue_levels +
3341     idx_b;
3342     }
3343    
3344 sf-exg 1.570 /*
3345     * Find the nearest color slot in the hidden color cube,
3346 root 1.580 * adapt its value to the 32bit RGBA color.
3347 sf-exg 1.570 */
3348     unsigned int
3349 root 1.580 rxvt_term::map_rgb24_color (unsigned int r, unsigned int g, unsigned int b, unsigned int a)
3350 sf-exg 1.570 {
3351 sf-exg 1.571 r &= 0xff;
3352     g &= 0xff;
3353     b &= 0xff;
3354 root 1.580 a &= 0xff;
3355    
3356     uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;
3357 sf-exg 1.571
3358 sf-exg 1.590 /* we allow one of the 6 closest neighbouring colours */
3359 root 1.573 /* to replace the current color, if they not used recently */
3360 root 1.597 #if 0
3361     static const unsigned char dxyz[][3] = {
3362 sf-exg 1.590 0, 0, 0,
3363     0, 0, 4,
3364     0, 4, 4,
3365     4, 4, 0,
3366     4, 0, 4,
3367 root 1.597 0, 4, 0,
3368     4, 0, 0,
3369     };
3370     #else
3371     // silly compressed verlapping triplets version of above
3372     static const unsigned char dxyz[] = {
3373     0, 0, 0, 4, 4, 0, 4, 0, 0,
3374 sf-exg 1.590 };
3375 root 1.597 #endif
3376 sf-exg 1.590
3377     static const unsigned char color_level[8][32] = {
3378     // neighbour index
3379     {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},
3380     {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},
3381     {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},
3382     {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},
3383     // Red_levels/Green_levels/Blue_levels index
3384     {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},
3385     {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},
3386     {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},
3387     {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},
3388 root 1.573 };
3389    
3390 sf-exg 1.590 unsigned int idx;
3391    
3392 root 1.597 for (int n = 0; n < ecb_array_length (dxyz) - 2; ++n)
3393 sf-exg 1.571 {
3394 root 1.597 unsigned int idx_r = color_level[ Red_levels - dxyz[n + 0]][r / 8];
3395     unsigned int idx_g = color_level[Green_levels - dxyz[n + 1]][g / 8];
3396     unsigned int idx_b = color_level[ Blue_levels - dxyz[n + 2]][b / 8];
3397 sf-exg 1.590 unsigned int index = colorcube_index (idx_r, idx_g, idx_b);
3398 sf-exg 1.571
3399 sf-exg 1.590 if (n == 0)
3400     idx = index;
3401 sf-exg 1.571
3402 root 1.578 if (rgb24_color[index] == color)
3403     {
3404 root 1.579 rgb24_seqno[index] = ++rgb24_sequence;
3405 root 1.578 return index + minTermCOLOR24;
3406     }
3407    
3408 root 1.573 // minor issue: could update index 0 few more times
3409     if ((rgb24_seqno[index] | rgb24_color[index]) == 0)
3410     {
3411     idx = index;
3412     goto update;
3413     }
3414 sf-exg 1.571
3415 root 1.573 // like (rgb24_seqno[idx] > rgb24_seqno[index])
3416 root 1.597 // but also handles wrap around values well enough
3417     if ((uint16_t)(rgb24_seqno[idx] - rgb24_seqno[index]) < 0x8000)
3418 root 1.573 idx = index;
3419 sf-exg 1.571 }
3420    
3421     update:
3422     rgb24_color[idx] = color;
3423     rgb24_seqno[idx] = ++rgb24_sequence;
3424 sf-exg 1.570
3425 sf-exg 1.571 idx += minTermCOLOR24;
3426 sf-exg 1.570 pix_colors_focused [idx].free (this);
3427 root 1.580 pix_colors_focused [idx].set (this, rgba (r * 0x0101, g * 0x0101, b * 0x0101, a * 0x0101));
3428 sf-exg 1.570 update_fade_color (idx, false);
3429    
3430     return idx;
3431     }
3432    
3433 pcg 1.90 void
3434 sf-exg 1.600 rxvt_term::process_color_seq (int report, int color, const char *str, string_term &st)
3435 pcg 1.90 {
3436     if (str[0] == '?' && !str[1])
3437     {
3438 root 1.298 rgba c;
3439 root 1.300 pix_colors_focused[color].get (c);
3440 sf-exg 1.598 char rgba_str[32];
3441 root 1.291
3442     #if XFT
3443 root 1.298 if (c.a != rgba::MAX_CC)
3444 sf-exg 1.598 snprintf (rgba_str, sizeof (rgba_str), "rgba:%04x/%04x/%04x/%04x", c.r, c.g, c.b, c.a);
3445 root 1.291 else
3446     #endif
3447 sf-exg 1.598 snprintf (rgba_str, sizeof (rgba_str), "rgb:%04x/%04x/%04x", c.r, c.g, c.b);
3448    
3449     if (IN_RANGE_INC (color, minCOLOR, maxTermCOLOR))
3450 sf-exg 1.600 tt_printf ("\033]%d;%d;%s%s", report, color - minCOLOR, rgba_str, st.v);
3451 sf-exg 1.598 else
3452 sf-exg 1.600 tt_printf ("\033]%d;%s%s", report, rgba_str, st.v);
3453 pcg 1.1 }
3454 pcg 1.90 else
3455     set_window_color (color, str);
3456 pcg 1.1 }
3457 pcg 1.90
3458 pcg 1.1 /*
3459     * XTerm escape sequences: ESC ] Ps;Pt (ST|BEL)
3460     */
3461     void
3462 sf-exg 1.600 rxvt_term::process_xterm_seq (int op, char *str, string_term &st)
3463 pcg 1.1 {
3464 pcg 1.81 int color;
3465     char *buf, *name;
3466 pcg 1.90 bool query = str[0] == '?' && !str[1];
3467 root 1.163 int saveop = op;
3468 root 1.285
3469 root 1.305 dLocal (Display *, dpy);
3470 pcg 1.36
3471 pcg 1.43 assert (str != NULL);
3472 ayin 1.329
3473 root 1.311 if (HOOK_INVOKE ((this, HOOK_OSC_SEQ, DT_INT, op, DT_STR, str, DT_END)))
3474 root 1.312 return;
3475 root 1.311
3476 pcg 1.36 switch (op)
3477     {
3478     case XTerm_name:
3479     set_title (str);
3480     /* FALLTHROUGH */
3481     case XTerm_iconName:
3482 pcg 1.81 set_icon_name (str);
3483 pcg 1.36 break;
3484     case XTerm_title:
3485     set_title (str);
3486     break;
3487 pcg 1.90 case XTerm_property:
3488     if (str[0] == '?')
3489     {
3490 root 1.175 Atom prop = display->atom (str + 1);
3491 pcg 1.90 Atom actual_type;
3492     int actual_format;
3493     unsigned long nitems;
3494     unsigned long bytes_after;
3495     unsigned char *value = 0;
3496     const char *str = "";
3497    
3498     if (prop
3499 sf-exg 1.482 && XGetWindowProperty (dpy, parent,
3500 pcg 1.90 prop, 0, 1<<16, 0, AnyPropertyType,
3501     &actual_type, &actual_format,
3502     &nitems, &bytes_after, &value) == Success
3503     && actual_type != None
3504     && actual_format == 8)
3505     str = (const char *)(value);
3506    
3507 sf-exg 1.600 tt_printf ("\033]%d;%s%s", op, option (Opt_insecure) ? str : "", st.v);
3508 pcg 1.90
3509     XFree (value);
3510     }
3511     else
3512     {
3513 root 1.433 char *eq = strchr (str, '=');
3514 pcg 1.90
3515     if (eq)
3516     {
3517     *eq = 0;
3518 root 1.175 set_utf8_property (display->atom (str), eq + 1);
3519 pcg 1.90 }
3520     else
3521 sf-exg 1.482 XDeleteProperty (dpy, parent,
3522 pcg 1.90 display->atom (str));
3523     }
3524     break;
3525    
3526 pcg 1.36 case XTerm_Color:
3527     for (buf = (char *)str; buf && *buf;)
3528     {
3529 root 1.145 if ((name = strchr (buf, ';')) == NULL)
3530 pcg 1.36 break;
3531 pcg 1.81
3532 pcg 1.36 *name++ = '\0';
3533 root 1.256 color = atoi (buf) + minCOLOR;
3534 pcg 1.81
3535 root 1.257 if (!IN_RANGE_INC (color, minCOLOR, maxTermCOLOR))
3536 pcg 1.36 break;
3537 pcg 1.81
3538 root 1.145 if ((buf = strchr (name, ';')) != NULL)
3539 pcg 1.36 *buf++ = '\0';
3540 pcg 1.81
3541 sf-exg 1.600 process_color_seq (op, color, name, st);
3542 pcg 1.36 }
3543     break;
3544 ayin 1.394 case Rxvt_restoreFG:
3545 pcg 1.90 case XTerm_Color00:
3546 sf-exg 1.600 process_color_seq (op, Color_fg, str, st);
3547 pcg 1.90 break;
3548 ayin 1.394 case Rxvt_restoreBG:
3549 pcg 1.90 case XTerm_Color01:
3550 sf-exg 1.600 process_color_seq (op, Color_bg, str, st);
3551 pcg 1.90 break;
3552 pcg 1.1 #ifndef NO_CURSORCOLOR
3553 pcg 1.36 case XTerm_Color_cursor:
3554 sf-exg 1.600 process_color_seq (op, Color_cursor, str, st);
3555 pcg 1.36 break;
3556     #endif
3557 pcg 1.90 case XTerm_Color_pointer_fg:
3558 sf-exg 1.600 process_color_seq (op, Color_pointer_fg, str, st);
3559 pcg 1.90 break;
3560     case XTerm_Color_pointer_bg:
3561 sf-exg 1.600 process_color_seq (op, Color_pointer_bg, str, st);
3562 pcg 1.36 break;
3563 sf-exg 1.448 #ifdef OPTION_HC
3564     case XTerm_Color_HC:
3565 sf-exg 1.600 process_color_seq (op, Color_HC, str, st);
3566 sf-exg 1.448 break;
3567 sf-exg 1.450 case XTerm_Color_HTC:
3568 sf-exg 1.600 process_color_seq (op, Color_HTC, str, st);
3569 sf-exg 1.450 break;
3570 sf-exg 1.448 #endif
3571 pcg 1.1 #ifndef NO_BOLD_UNDERLINE_REVERSE
3572 root 1.257 case URxvt_Color_BD:
3573 sf-exg 1.600 process_color_seq (op, Color_BD, str, st);
3574 root 1.257 break;
3575     case URxvt_Color_UL:
3576 sf-exg 1.600 process_color_seq (op, Color_UL, str, st);
3577 root 1.257 break;
3578 root 1.201 case URxvt_Color_IT:
3579 sf-exg 1.600 process_color_seq (op, Color_IT, str, st);
3580 root 1.201 break;
3581 pcg 1.1 #endif
3582 root 1.427 case URxvt_Color_border:
3583 sf-exg 1.600 process_color_seq (op, Color_border, str, st);
3584 root 1.427 break;
3585 sf-exg 1.527
3586 pcg 1.36 case XTerm_logfile:
3587 pcg 1.81 // TODO, when secure mode?
3588 pcg 1.36 break;
3589 pcg 1.90
3590 root 1.201 #if 0
3591 root 1.257 case Rxvt_dumpscreen: /* no error notices */
3592 root 1.201 {
3593     int fd;
3594     if ((fd = open (str, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0)
3595     {
3596     scr_dump (fd);
3597     close (fd);
3598     }
3599     }
3600     break;
3601     #endif
3602 pcg 1.36 case XTerm_font:
3603 root 1.163 op = URxvt_font;
3604     case URxvt_font:
3605     #if ENABLE_STYLES
3606     case URxvt_boldFont:
3607     case URxvt_italicFont:
3608     case URxvt_boldItalicFont:
3609     #endif
3610 pcg 1.90 if (query)
3611 sf-exg 1.600 tt_printf ("\33]%d;%-.250s%s", saveop,
3612 root 1.321 option (Opt_insecure) && fontset[op - URxvt_font]->fontdesc
3613 root 1.208 ? fontset[op - URxvt_font]->fontdesc : "",
3614 sf-exg 1.600 st.v);
3615 pcg 1.90 else
3616 root 1.163 {
3617     const char *&res = rs[Rs_font + (op - URxvt_font)];
3618    
3619     res = strdup (str);
3620     allocated.push_back ((void *)res);
3621     set_fonts ();
3622     }
3623 pcg 1.51 break;
3624 pcg 1.90
3625 root 1.288 case URxvt_version:
3626     if (query)
3627 sf-exg 1.600 tt_printf ("\33]%d;rxvt-unicode;%-.20s;%c;%c%s",
3628 root 1.290 op,
3629     rs[Rs_name], VERSION[0], VERSION[2],
3630 sf-exg 1.600 st.v);
3631 root 1.288 break;
3632    
3633 root 1.596 #if !ENABLE_MINIMAL
3634 root 1.595 case URxvt_cellinfo:
3635     if (query)
3636 sf-exg 1.600 tt_printf ("\33]%d;%d;%d;%d%s", saveop,
3637 root 1.595 fwidth, fheight, fbase,
3638 sf-exg 1.600 st.v);
3639 root 1.595 break;
3640    
3641 root 1.201 case URxvt_locale:
3642 pcg 1.90 if (query)
3643 sf-exg 1.600 tt_printf ("\33]%d;%-.250s%s", op, option (Opt_insecure) ? locale : "", st.v);
3644 pcg 1.54 else
3645     {
3646     set_locale (str);
3647 root 1.269 pty->set_utf8_mode (enc_utf8);
3648 root 1.199 init_xlocale ();
3649 pcg 1.54 }
3650 pcg 1.36 break;
3651 pcg 1.90
3652 root 1.201 case URxvt_view_up:
3653     case URxvt_view_down:
3654 root 1.231 {
3655     int lines = atoi (str);
3656 root 1.201
3657 root 1.231 if (lines)
3658     scr_page (op == URxvt_view_up ? UP : DN, lines);
3659     else
3660     scr_erase_savelines ();
3661     }
3662 root 1.230
3663     break;
3664     #endif
3665 root 1.201
3666 root 1.230 #if ENABLE_PERL
3667     case URxvt_perl:
3668 sf-exg 1.600 HOOK_INVOKE ((this, HOOK_OSC_SEQ_PERL, DT_STR, str, DT_STR, st.v, DT_END));
3669 pcg 1.36 break;
3670 pcg 1.1 #endif
3671     }
3672     }
3673     /*----------------------------------------------------------------------*/
3674    
3675     /*{{{ process DEC private mode sequences `ESC [ ? Ps mode' */
3676     /*
3677     * mode can only have the following values:
3678     * 'l' = low
3679     * 'h' = high
3680     * 's' = save
3681     * 'r' = restore
3682     * 't' = toggle
3683     * so no need for fancy checking
3684     */
3685 root 1.512 int ecb_cold
3686 pcg 1.34 rxvt_term::privcases (int mode, unsigned long bit)
3687 pcg 1.1 {
3688 pcg 1.81 int state;
3689 pcg 1.1
3690 pcg 1.36 if (mode == 's')
3691     {
3692 sf-exg 1.508 if (priv_modes & bit)
3693     SavedModes |= bit;
3694     else
3695     SavedModes &= ~bit;
3696 pcg 1.36 return -1;
3697 pcg 1.1 }
3698 pcg 1.36 else
3699     {
3700     if (mode == 'r')
3701     state = (SavedModes & bit) ? 1 : 0; /* no overlapping */
3702     else
3703 root 1.145 state = (mode == 't') ? ! (priv_modes & bit) : mode;
3704 root 1.451
3705 sf-exg 1.496 if (state)
3706     priv_modes |= bit;
3707     else
3708     priv_modes &= ~bit;
3709 pcg 1.36 }
3710 pcg 1.81
3711 pcg 1.36 return state;
3712 pcg 1.1 }
3713    
3714     /* we're not using priv _yet_ */
3715     void
3716 sf-exg 1.488 rxvt_term::process_terminal_mode (int mode, int priv ecb_unused, unsigned int nargs, const int *arg)
3717 pcg 1.1 {
3718 pcg 1.81 unsigned int i, j;
3719     int state;
3720    
3721 pcg 1.36 static const struct
3722 root 1.344 {
3723     const int argval;
3724     const unsigned long bit;
3725     } argtopriv[] = {
3726 root 1.425 { 1, PrivMode_aplCUR }, // DECCKM
3727 sf-exg 1.490 { 2, PrivMode_vt52 }, // DECANM
3728 root 1.425 { 3, PrivMode_132 }, // DECCOLM
3729     { 4, PrivMode_smoothScroll }, // DECSCLM
3730     { 5, PrivMode_rVideo }, // DECSCNM
3731     { 6, PrivMode_relOrigin }, // DECOM
3732     { 7, PrivMode_Autowrap }, // DECAWM
3733     // 8, auto-repeat keys // DECARM
3734 pcg 1.36 { 9, PrivMode_MouseX10 },
3735 sf-exg 1.560 { 12, PrivMode_BlinkingCursor },
3736 root 1.426 // 18 end FF to printer after print screen
3737 sf-exg 1.454 // 19 Print screen prints full screen/scroll region
3738 sf-exg 1.490 { 25, PrivMode_VisibleCursor }, // DECTCEM cnorm/cvvis/civis
3739 pcg 1.1 #ifdef scrollBar_esc
3740 pcg 1.36 { scrollBar_esc, PrivMode_scrollBar },
3741 pcg 1.1 #endif
3742 root 1.425 { 35, PrivMode_ShiftKeys }, // rxvt extension
3743     // 38, tektronix mode // DECTEK
3744 pcg 1.36 { 40, PrivMode_132OK },
3745 pcg 1.73 // 41 xterm more fixes NYI
3746     // 45 margin bell NYI
3747     // 46 start logging
3748 pcg 1.36 { 47, PrivMode_Screen },
3749 sf-exg 1.490 { 66, PrivMode_aplKP }, // DECNKM
3750 pcg 1.1 #ifndef NO_BACKSPACE_KEY
3751 root 1.425 { 67, PrivMode_BackSpace }, // DECBKM
3752 pcg 1.1 #endif
3753 pcg 1.36 { 1000, PrivMode_MouseX11 },
3754 ayin 1.360 { 1002, PrivMode_MouseBtnEvent },
3755     { 1003, PrivMode_MouseAnyEvent },
3756 root 1.461 #if ENABLE_FRILLS
3757 sf-exg 1.569 { 1004, PrivMode_FocusEvent },
3758 sf-exg 1.587 { 1005, PrivMode_ExtMouseUTF8 },
3759 sf-exg 1.586 { 1006, PrivMode_ExtMouseSGR },
3760 root 1.461 #endif
3761 pcg 1.73 { 1010, PrivMode_TtyOutputInh }, // rxvt extension
3762     { 1011, PrivMode_Keypress }, // rxvt extension
3763 root 1.461 #if ENABLE_FRILLS
3764 sf-exg 1.587 { 1015, PrivMode_ExtMouseUrxvt }, // urxvt extension of 1005
3765 root 1.461 #endif
3766 pcg 1.73 // 1035 enable modifiers for alt, numlock NYI
3767     // 1036 send ESC for meta keys NYI
3768     // 1037 send DEL for keypad delete NYI
3769 pcg 1.36 { 1047, PrivMode_Screen },
3770 root 1.461 // 1048 save and restore cursor, implemented in code
3771 pcg 1.90 { 1049, PrivMode_Screen }, /* xterm extension, clear screen on ti rather than te */
3772 pcg 1.73 // 1051, 1052, 1060, 1061 keyboard emulation NYI
3773 root 1.594 #if ENABLE_FRILLS
3774 ayin 1.396 { 2004, PrivMode_BracketPaste },
3775 root 1.594 #endif
3776 pcg 1.36 };
3777    
3778     if (nargs == 0)
3779     return;
3780    
3781 sf-exg 1.589 // DECRQM
3782     if (mode == 'p')
3783     {
3784     int status = 0;
3785     if (nargs != 1)
3786     return;
3787    
3788     for (j = 0; j < ecb_array_length (argtopriv); j++)
3789     if (argtopriv[j].argval == arg[0])
3790     {
3791     status = (priv_modes & argtopriv[j].bit) ? 1 : 2;
3792     break;
3793     }
3794    
3795     tt_printf ("\33[?%d;%d$y", arg[0], status);
3796     return;
3797     }
3798    
3799 pcg 1.36 /* make lo/hi boolean */
3800     if (mode == 'l')
3801     mode = 0; /* reset */
3802     else if (mode == 'h')
3803     mode = 1; /* set */
3804    
3805     for (i = 0; i < nargs; i++)
3806     {
3807     state = -1;
3808    
3809     /* basic handling */
3810 sf-exg 1.488 for (j = 0; j < ecb_array_length (argtopriv); j++)
3811 pcg 1.36 if (argtopriv[j].argval == arg[i])
3812     {
3813     state = privcases (mode, argtopriv[j].bit);
3814     break;
3815     }
3816 pcg 1.1
3817 pcg 1.36 /* extra handling for values with state unkept */
3818 pcg 1.73 switch (arg[i])
3819     {
3820 root 1.220 #if ENABLE_STYLES
3821     case 1021:
3822 root 1.249 set_option (Opt_intensityStyles, mode);
3823 root 1.222
3824 root 1.225 scr_touch (true);
3825 root 1.222 break;
3826 root 1.220 #endif
3827 pcg 1.73 case 1048: /* alternative cursor save */
3828 root 1.321 if (option (Opt_secondaryScreen))
3829 pcg 1.90 if (mode == 0)
3830     scr_cursor (RESTORE);
3831     else if (mode == 1)
3832     scr_cursor (SAVE);
3833     break;
3834 pcg 1.73 }
3835    
3836     if (state >= 0)
3837     /* extra handling for values with valid 0 or 1 state */
3838 pcg 1.36 switch (arg[i])
3839     {
3840 pcg 1.73 /* case 1: - application cursor keys */
3841     case 2: /* VT52 mode */
3842     /* oddball mode. should be set regardless of set/reset
3843     * parameter. Return from VT52 mode with an ESC < from
3844     * within VT52 mode
3845     */
3846 sf-exg 1.496 priv_modes |= PrivMode_vt52;
3847 pcg 1.73 break;
3848     case 3: /* 80/132 */
3849 root 1.145 if (priv_modes & PrivMode_132OK)
3850 root 1.425 set_widthheight ((state ? 132 : 80) * fwidth, 24 * fheight);
3851 pcg 1.73 break;
3852     case 4: /* smooth scrolling */
3853 root 1.249 set_option (Opt_jumpScroll, !state);
3854 pcg 1.73 break;
3855     case 5: /* reverse video */
3856     scr_rvideo_mode (state);
3857     break;
3858     case 6: /* relative/absolute origins */
3859     scr_relative_origin (state);
3860     break;
3861     case 7: /* autowrap */
3862     scr_autowrap (state);
3863     break;
3864 pcg 1.90 /* case 8: - auto repeat, can't do on a per window basis */
3865 pcg 1.73 case 9: /* X10 mouse reporting */
3866     if (state) /* orthogonal */
3867 ayin 1.360 priv_modes &= ~(PrivMode_MouseX11|PrivMode_MouseBtnEvent|PrivMode_MouseAnyEvent);
3868 pcg 1.73 break;
3869 pcg 1.1 #ifdef scrollBar_esc
3870 pcg 1.73 case scrollBar_esc:
3871 sf-exg 1.495 scrollBar.map (state);
3872     resize_all_windows (0, 0, 0);
3873     scr_touch (true);
3874 pcg 1.73 break;
3875 pcg 1.1 #endif
3876 sf-exg 1.560 #ifdef CURSOR_BLINK
3877     case 12:
3878     cursor_blink_reset ();
3879     break;
3880     #endif
3881 pcg 1.73 case 25: /* visible/invisible cursor */
3882     scr_cursor_visible (state);
3883     break;
3884 pcg 1.90 /* case 35: - shift keys */
3885     /* case 40: - 80 <--> 132 mode */
3886 pcg 1.73 case 47: /* secondary screen */
3887     scr_change_screen (state);
3888     break;
3889 pcg 1.90 /* case 66: - application key pad */
3890     /* case 67: - backspace key */
3891 pcg 1.73 case 1000: /* X11 mouse reporting */
3892     if (state) /* orthogonal */
3893 ayin 1.360 priv_modes &= ~(PrivMode_MouseX10|PrivMode_MouseBtnEvent|PrivMode_MouseAnyEvent);
3894 pcg 1.73 break;
3895 ayin 1.360 case 1002:
3896     case 1003:
3897 ayin 1.365 if (state)
3898     {
3899     priv_modes &= ~(PrivMode_MouseX10|PrivMode_MouseX11);
3900     priv_modes &= arg[i] == 1003 ? ~PrivMode_MouseBtnEvent : ~PrivMode_MouseAnyEvent;
3901 root 1.462 mouse_row = mouse_col = 0;
3902 ayin 1.365 vt_emask_mouse = PointerMotionMask;
3903     }
3904     else
3905 ayin 1.360 vt_emask_mouse = NoEventMask;
3906 root 1.425
3907 ayin 1.360 vt_select_input ();
3908     break;
3909 pcg 1.73 case 1010: /* scroll to bottom on TTY output inhibit */
3910 root 1.249 set_option (Opt_scrollTtyOutput, !state);
3911 pcg 1.73 break;
3912     case 1011: /* scroll to bottom on key press */
3913 root 1.249 set_option (Opt_scrollTtyKeypress, state);
3914 pcg 1.73 break;
3915 pcg 1.90 case 1047: /* secondary screen w/ clearing last */
3916 root 1.321 if (option (Opt_secondaryScreen))
3917 root 1.428 if (!state)
3918 pcg 1.90 scr_erase_screen (2);
3919 root 1.425
3920 pcg 1.90 scr_change_screen (state);
3921     break;
3922     case 1049: /* secondary screen w/ clearing first */
3923 root 1.429 if (option (Opt_secondaryScreen))
3924     if (state)
3925     scr_cursor (SAVE);
3926 root 1.428
3927 pcg 1.73 scr_change_screen (state);
3928 root 1.428
3929 root 1.429 if (option (Opt_secondaryScreen))
3930     if (state)
3931     scr_erase_screen (2);
3932     else
3933     scr_cursor (RESTORE);
3934 pcg 1.90 break;
3935 pcg 1.73 default:
3936     break;
3937     }
3938 pcg 1.1 }
3939     }
3940     /*}}} */
3941    
3942     /*{{{ process sgr sequences */
3943 root 1.512 void ecb_hot
3944 pcg 1.34 rxvt_term::process_sgr_mode (unsigned int nargs, const int *arg)
3945 pcg 1.1 {
3946 pcg 1.81 unsigned int i;
3947     short rendset;
3948     int rendstyle;
3949 pcg 1.36
3950     if (nargs == 0)
3951     {
3952     scr_rendition (0, ~RS_None);
3953     return;
3954     }
3955 pcg 1.81
3956 pcg 1.36 for (i = 0; i < nargs; i++)
3957     {
3958     rendset = -1;
3959     switch (arg[i])
3960     {
3961     case 0:
3962     rendset = 0, rendstyle = ~RS_None;
3963     break;
3964     case 1:
3965     rendset = 1, rendstyle = RS_Bold;
3966     break;
3967 root 1.163 //case 2: // low intensity
3968     case 3:
3969     rendset = 1, rendstyle = RS_Italic;
3970     break;
3971 pcg 1.36 case 4:
3972     rendset = 1, rendstyle = RS_Uline;
3973     break;
3974 root 1.107 case 5: // slowly blinking
3975     case 6: // rapidly blinking
3976 pcg 1.36 rendset = 1, rendstyle = RS_Blink;
3977     break;
3978 pcg 1.93 //case 6: // scoansi light background
3979 pcg 1.36 case 7:
3980     rendset = 1, rendstyle = RS_RVid;
3981     break;
3982 pcg 1.73 case 8:
3983     // invisible. NYI
3984     break;
3985 root 1.107 //case 9: // crossed out
3986     //case 10: // scoansi acs off, primary font
3987     //case 11: // scoansi acs on, first alt font
3988     //case 12: // scoansi acs on, |0x80, second alt font
3989     //...
3990     //case 19: // ninth alt font
3991     //case 20: // gothic
3992 root 1.163 case 21: // disable bold, faint, sometimes doubly underlined (iso 8613)
3993 root 1.107 rendset = 0, rendstyle = RS_Bold;
3994 pcg 1.93 break;
3995 root 1.562 case 22: // bold off (vt220)
3996 pcg 1.36 rendset = 0, rendstyle = RS_Bold;
3997     break;
3998 root 1.163 case 23: // disable italic
3999     rendset = 0, rendstyle = RS_Italic;
4000     break;
4001 root 1.562 case 24: // underline off (vt220)
4002 pcg 1.36 rendset = 0, rendstyle = RS_Uline;
4003     break;
4004 root 1.562 case 25: // blink off (vt220)
4005 pcg 1.36 rendset = 0, rendstyle = RS_Blink;
4006     break;
4007 root 1.163 case 26: // variable spacing (iso 8613)
4008 root 1.145 rendset = 0, rendstyle = RS_Blink;
4009     break;
4010 root 1.562 case 27: // reverse off (vt220)
4011 pcg 1.36 rendset = 0, rendstyle = RS_RVid;
4012     break;
4013 root 1.107 //case 28: // visible. NYI
4014     //case 29: // not crossed-out
4015 pcg 1.36 }
4016 pcg 1.73
4017 pcg 1.36 if (rendset != -1)
4018     {
4019     scr_rendition (rendset, rendstyle);
4020 pcg 1.43 continue; /* for (;i;) */
4021 pcg 1.36 }
4022    
4023     switch (arg[i])
4024     {
4025     case 30:
4026     case 31: /* set fg color */
4027     case 32:
4028     case 33:
4029     case 34:
4030     case 35:
4031     case 36:
4032     case 37:
4033 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 30)), Color_fg);
4034 pcg 1.36 break;
4035     case 39: /* default fg */
4036     scr_color (Color_fg, Color_fg);
4037     break;
4038    
4039     case 40:
4040     case 41: /* set bg color */
4041     case 42:
4042     case 43:
4043     case 44:
4044     case 45:
4045     case 46:
4046     case 47:
4047 pcg 1.73 scr_color ((unsigned int) (minCOLOR + (arg[i] - 40)), Color_bg);
4048 pcg 1.36 break;
4049     case 49: /* default bg */
4050     scr_color (Color_bg, Color_bg);
4051     break;
4052 pcg 1.1
4053 root 1.580 case 38: // set fg color, ISO 8613-6
4054     case 48: // set bg color, ISO 8613-6
4055     {
4056     unsigned int fgbg = arg[i] == 38 ? Color_fg : Color_bg;
4057     unsigned int idx;
4058 sf-exg 1.586
4059 root 1.580 if (nargs > i + 2 && arg[i + 1] == 5)
4060     {
4061     idx = minCOLOR + arg[i + 2];
4062     i += 2;
4063 root 1.581
4064     scr_color (idx, fgbg);
4065 root 1.580 }
4066     else if (nargs > i + 4 && arg[i + 1] == 2)
4067     {
4068     unsigned int r = arg[i + 2];
4069     unsigned int g = arg[i + 3];
4070     unsigned int b = arg[i + 4];
4071     unsigned int a = 0xff;
4072    
4073     idx = map_rgb24_color (r, g, b, a);
4074    
4075     i += 4;
4076 root 1.581
4077     scr_color (idx, fgbg);
4078 root 1.580 }
4079     }
4080     break;
4081    
4082 root 1.163 //case 50: // not variable spacing
4083    
4084 root 1.294 #if !ENABLE_MINIMAL
4085 pcg 1.36 case 90:
4086     case 91: /* set bright fg color */
4087     case 92:
4088     case 93:
4089     case 94:
4090     case 95:
4091     case 96:
4092     case 97:
4093 root 1.163 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 90)), Color_fg);
4094 pcg 1.36 break;
4095     case 100:
4096     case 101: /* set bright bg color */
4097     case 102:
4098     case 103:
4099     case 104:
4100     case 105:
4101     case 106:
4102     case 107:
4103 root 1.163 scr_color ((unsigned int) (minBrightCOLOR + (arg[i] - 100)), Color_bg);
4104 pcg 1.36 break;
4105 pcg 1.1 #endif
4106 pcg 1.36 }
4107 pcg 1.1 }
4108     }
4109 sf-exg 1.534
4110     void
4111     rxvt_term::set_cursor_style (int style)
4112     {
4113 sf-exg 1.557 if (!IN_RANGE_INC (style, 0, 6))
4114 sf-exg 1.534 return;
4115    
4116 sf-exg 1.557 if (style == 0)
4117     style = 1;
4118    
4119     cursor_type = (style - 1) / 2;
4120     set_option (Opt_cursorUnderline, cursor_type == 1);
4121 sf-exg 1.534
4122     #ifdef CURSOR_BLINK
4123 sf-exg 1.557 set_option (Opt_cursorBlink, style & 1);
4124 sf-exg 1.534 cursor_blink_reset ();
4125     #endif
4126    
4127     want_refresh = 1;
4128     }
4129 pcg 1.1 /*}}} */
4130    
4131 root 1.549 /* ---------------------------------------------------------------------- */
4132     /* Write data to the pty as typed by the user, pasted with the mouse,
4133     * or generated by us in response to a query ESC sequence.
4134     */
4135 pcg 1.1
4136     /*
4137 pcg 1.43 * Send printf () formatted output to the command.
4138 pcg 1.1 * Only use for small amounts of data.
4139     */
4140     void
4141 pcg 1.10 rxvt_term::tt_printf (const char *fmt,...)
4142 pcg 1.1 {
4143 pcg 1.10 va_list arg_ptr;
4144 root 1.234 char buf[256];
4145 pcg 1.1
4146 pcg 1.10 va_start (arg_ptr, fmt);
4147     vsnprintf ((char *)buf, 256, fmt, arg_ptr);
4148     va_end (arg_ptr);
4149 root 1.145 tt_write (buf, strlen (buf));
4150 pcg 1.1 }
4151    
4152 sf-exg 1.548 /* Write data to the pty as typed by the user. */
4153     void
4154     rxvt_term::tt_write_user_input (const char *data, unsigned int len)
4155     {
4156 root 1.549 if (HOOK_INVOKE ((this, HOOK_TT_WRITE, DT_STR_LEN, data, len, DT_END)))
4157     return;
4158    
4159 sf-exg 1.548 if (option (Opt_scrollTtyKeypress))
4160     if (view_start)
4161     {
4162     view_start = 0;
4163     want_refresh = 1;
4164     }
4165    
4166 root 1.549 tt_write_ (data, len);
4167 sf-exg 1.548 }
4168    
4169 pcg 1.1 void
4170 root 1.234 rxvt_term::tt_write (const char *data, unsigned int len)
4171 pcg 1.1 {
4172 root 1.253 if (HOOK_INVOKE ((this, HOOK_TT_WRITE, DT_STR_LEN, data, len, DT_END)))
4173     return;
4174    
4175 root 1.549 tt_write_ (data, len);
4176     }
4177    
4178     static const unsigned int MAX_PTY_WRITE = 255; // minimum MAX_INPUT
4179    
4180     void
4181     rxvt_term::tt_write_ (const char *data, unsigned int len)
4182     {
4183 root 1.269 if (pty->pty < 0)
4184 root 1.239 return;
4185    
4186 root 1.177 if (v_buflen == 0)
4187     {
4188 root 1.269 ssize_t written = write (pty->pty, data, min (len, MAX_PTY_WRITE));
4189 pcg 1.10
4190 sf-exg 1.480 max_it (written, 0);
4191    
4192     if (written == len)
4193 root 1.177 return;
4194 pcg 1.34
4195 root 1.177 data += written;
4196     len -= written;
4197     }
4198 pcg 1.10
4199 sf-exg 1.469 v_buffer = (char *)rxvt_realloc (v_buffer, v_buflen + len);
4200 pcg 1.10
4201 root 1.177 memcpy (v_buffer + v_buflen, data, len);
4202     v_buflen += len;
4203 pcg 1.10
4204 root 1.363 pty_ev.set (ev::READ | ev::WRITE);
4205 root 1.177 }
4206 pcg 1.10
4207 root 1.177 void rxvt_term::pty_write ()
4208     {
4209 root 1.269 int written = write (pty->pty, v_buffer, min (v_buflen, MAX_PTY_WRITE));
4210 pcg 1.1
4211 root 1.177 if (written > 0)
4212 pcg 1.10 {
4213 root 1.177 v_buflen -= written;
4214 pcg 1.10
4215 root 1.177 if (v_buflen == 0)
4216 pcg 1.10 {
4217 root 1.177 free (v_buffer);
4218     v_buffer = 0;
4219 pcg 1.10
4220 root 1.363 pty_ev.set (ev::READ);
4221 pcg 1.10 return;
4222     }
4223 root 1.177
4224     memmove (v_buffer, v_buffer + written, v_buflen);
4225 pcg 1.1 }
4226 root 1.177 else if (written != -1 || (errno != EAGAIN && errno != EINTR))
4227 root 1.363 pty_ev.set (ev::READ);
4228 pcg 1.1 }
4229 pcg 1.10
4230 pcg 1.1 /*----------------------- end-of-file (C source) -----------------------*/
4231