ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.601
Committed: Sat May 6 06:47:29 2023 UTC (12 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.600: +17 -7 lines
Log Message:
Revise mouse reporting of buttons 8-11

This commit changes the encoding of buttons 8-11 in mouse reporting
sequences to match xterm's, so as to make it unambiguous, and enables
reporting of release events for them.

Patch by Pierre-Marc Fournier.

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