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