ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/command.C
Revision: 1.448
Committed: Sat Apr 17 23:00:45 2010 UTC (14 years ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.447: +5 -3 lines
Log Message:
Disable colorRV resource.
Make OSC 17 apply to highlightColor.
Make highlightColor apply also to selected cells with reverse video.
Add highlightTextColor resource to change the foreground colour of
highlighted characters.

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