*** empty log message ***
[dana/urxvt.git] / src / rxvtperl.xs
1 /*----------------------------------------------------------------------*
2  * File:        rxvtperl.xs
3  *----------------------------------------------------------------------*
4  *
5  * All portions of code are copyright by their respective author/s.
6  * Copyright (c) 2005-2006 Marc Lehmann <pcg@goof.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *----------------------------------------------------------------------*/
22
23 #define line_t perl_line_t
24 #include <EXTERN.h>
25 #include <perl.h>
26 #include <XSUB.h>
27 #undef line_t
28
29 #include "../config.h"
30
31 #include <cstddef>
32 #include <cstdarg>
33
34 #include "unistd.h"
35
36 #include "iom.h"
37 #include "rxvt.h"
38 #include "keyboard.h"
39 #include "rxvtutil.h"
40 #include "rxvtperl.h"
41
42 #include "perlxsi.c"
43
44 #if defined(HAVE_SCROLLBARS) || defined(MENUBAR)
45 # define GRAB_CURSOR THIS->leftptr_cursor
46 #else
47 # define GRAB_CURSOR None
48 #endif
49
50 #undef LINENO
51 #define LINENO(n) MOD (THIS->term_start + int(n), THIS->total_rows)
52 #undef ROW
53 #define ROW(n) THIS->row_buf [LINENO (n)]
54
55 /////////////////////////////////////////////////////////////////////////////
56
57 static SV *
58 taint (SV *sv)
59 {
60   SvTAINT (sv);
61   return sv;
62 }
63
64 static SV *
65 taint_if (SV *sv, SV *src)
66 {
67   if (SvTAINTED (src))
68     SvTAINT (sv);
69
70   return sv;
71 }
72
73 static wchar_t *
74 sv2wcs (SV *sv)
75 {
76   STRLEN len;
77   char *str = SvPVutf8 (sv, len);
78   return rxvt_utf8towcs (str, len);
79 }
80
81 static SV *
82 wcs2sv (wchar_t *wstr, int len = -1)
83 {
84   char *str = rxvt_wcstoutf8 (wstr, len);
85
86   SV *sv = newSVpv (str, 0);
87   SvUTF8_on (sv);
88   free (str);
89
90   return sv;
91 }
92
93 static SV *
94 new_ref (HV *hv, const char *klass)
95 {
96   return sv_bless (newRV ((SV *)hv), gv_stashpv (klass, 1));
97 }
98
99 //TODO: use magic
100 static SV *
101 newSVptr (void *ptr, const char *klass)
102 {
103   HV *hv = newHV ();
104   sv_magic ((SV *)hv, 0, PERL_MAGIC_ext, (char *)ptr, 0);
105   return sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1));
106 }
107
108 static void
109 clearSVptr (SV *sv)
110 {
111   if (SvROK (sv))
112     sv = SvRV (sv);
113
114   hv_clear ((HV *)sv);
115   sv_unmagic (sv, PERL_MAGIC_ext);
116 }
117
118 static long
119 SvPTR (SV *sv, const char *klass)
120 {
121   if (!sv_derived_from (sv, klass))
122     croak ("object of type %s expected", klass);
123
124   MAGIC *mg = mg_find (SvRV (sv), PERL_MAGIC_ext);
125
126   if (!mg)
127     croak ("perl code used %s object, but C++ object is already destroyed, caught", klass);
128
129   return (long)mg->mg_ptr;
130 }
131
132 #define newSVterm(term) SvREFCNT_inc ((SV *)term->perl.self)
133 #define SvTERM(sv) (rxvt_term *)SvPTR (sv, "urxvt::term")
134
135 /////////////////////////////////////////////////////////////////////////////
136
137 struct perl_watcher
138 {
139   SV *cbsv;
140   HV *self;
141
142   perl_watcher ()
143   : cbsv (newSV (0))
144   {
145   }
146
147   ~perl_watcher ()
148   {
149     SvREFCNT_dec (cbsv);
150   }
151
152   void cb (SV *cb)
153   {
154     sv_setsv (cbsv, cb);
155   }
156
157   void invoke (const char *type, SV *self, int arg = -1);
158 };
159
160 void
161 perl_watcher::invoke (const char *type, SV *self, int arg)
162 {
163   dSP;
164
165   ENTER;
166   SAVETMPS;
167
168   PUSHMARK (SP);
169
170   XPUSHs (sv_2mortal (self));
171
172   if (arg >= 0)
173     XPUSHs (sv_2mortal (newSViv (arg)));
174
175   PUTBACK;
176   call_sv (cbsv, G_VOID | G_EVAL | G_DISCARD);
177   SPAGAIN;
178
179   PUTBACK;
180   FREETMPS;
181   LEAVE;
182
183   if (SvTRUE (ERRSV))
184     rxvt_warn ("%s callback evaluation error: %s", type, SvPV_nolen (ERRSV));
185 }
186
187 #define newSVtimer(timer) new_ref (timer->self, "urxvt::timer")
188 #define SvTIMER(sv) (timer *)SvPTR (sv, "urxvt::timer")
189
190 struct timer : time_watcher, perl_watcher
191 {
192   tstamp interval;
193
194   timer ()
195   : time_watcher (this, &timer::execute)
196   {
197   }
198
199   void execute (time_watcher &w)
200   {
201     if (interval)
202       start (at + interval);
203
204     invoke ("urxvt::timer", newSVtimer (this));
205   }
206 };
207
208 #define newSViow(iow) new_ref (iow->self, "urxvt::iow")
209 #define SvIOW(sv) (iow *)SvPTR (sv, "urxvt::iow")
210
211 struct iow : io_watcher, perl_watcher
212 {
213   iow ()
214   : io_watcher (this, &iow::execute)
215   {
216   }
217
218   void execute (io_watcher &w, short revents)
219   {
220     invoke ("urxvt::iow", newSViow (this), revents);
221   }
222 };
223
224 /////////////////////////////////////////////////////////////////////////////
225
226 #define SvOVERLAY(sv) (overlay *)SvPTR (sv, "urxvt::overlay")
227
228 struct overlay {
229   HV *self;
230   rxvt_term *THIS;
231   int x, y, w, h;
232   int border;
233   text_t **text;
234   rend_t **rend;
235
236   overlay (rxvt_term *THIS, int x_, int y_, int w_, int h_, rend_t rstyle, int border);
237   ~overlay ();
238
239   void show ();
240   void hide ();
241
242   void swap ();
243
244   void set (int x, int y, SV *str, SV *rend);
245 };
246
247 overlay::overlay (rxvt_term *THIS, int x_, int y_, int w_, int h_, rend_t rstyle, int border)
248 : THIS(THIS), x(x_), y(y_), w(w_), h(h_), border(border == 2)
249 {
250   if (border == 2)
251     {
252       w += 2;
253       h += 2;
254     }
255
256   text = new text_t *[h];
257   rend = new rend_t *[h];
258
259   for (int y = 0; y < h; y++)
260     {
261       text_t *tp = text[y] = new text_t[w];
262       rend_t *rp = rend[y] = new rend_t[w];
263
264       text_t t0, t1, t2;
265       rend_t r = rstyle;
266
267       if (border == 2)
268         {
269           if (y == 0)
270             t0 = 0x2554, t1 = 0x2550, t2 = 0x2557;
271           else if (y < h - 1)
272             t0 = 0x2551, t1 = 0x0020, t2 = 0x2551;
273           else
274             t0 = 0x255a, t1 = 0x2550, t2 = 0x255d;
275
276           *tp++ = t0;
277           *rp++ = r;
278
279           for (int x = w - 2; x-- > 0; )
280             {
281               *tp++ = t1;
282               *rp++ = r;
283             }
284
285           *tp = t2;
286           *rp = r;
287         }
288       else
289         for (int x = w; x-- > 0; )
290           {
291             *tp++ = 0x0020;
292             *rp++ = r;
293           }
294     }
295
296   show ();
297   THIS->want_refresh = 1;
298 }
299
300 overlay::~overlay ()
301 {
302   hide ();
303
304   for (int y = h; y--; )
305     {
306       delete [] text[y];
307       delete [] rend[y];
308     }
309
310   delete [] text;
311   delete [] rend;
312
313   THIS->want_refresh = 1;
314 }
315
316 void
317 overlay::show ()
318 {
319   char key[33]; sprintf (key, "%32lx", (long)this);
320
321   HV *hv = (HV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)THIS->perl.self), "_overlay", 8, 0));
322   hv_store (hv, key, 32, newSViv ((long)this), 0);
323 }
324
325 void
326 overlay::hide ()
327 {
328   SV **ovs = hv_fetch ((HV *)SvRV ((SV *)THIS->perl.self), "_overlay", 8, 0);
329
330   if (ovs)
331     {
332       char key[33]; sprintf (key, "%32lx", (long)this);
333
334       HV *hv = (HV *)SvRV (*ovs);
335       hv_delete (hv, key, 32, G_DISCARD);
336     }
337 }
338
339 void overlay::swap ()
340 {
341   int ov_x = max (0, min (MOD (x, THIS->ncol), THIS->ncol - w));
342   int ov_y = max (0, min (MOD (y, THIS->nrow), THIS->nrow - h));
343
344   int ov_w = min (w, THIS->ncol - ov_x);
345   int ov_h = min (h, THIS->nrow - ov_y);
346
347   for (int y = ov_h; y--; )
348     {
349       text_t *t1 = text [y];
350       rend_t *r1 = rend [y];
351
352       text_t *t2 = ROW(y + ov_y - THIS->view_start).t + ov_x;
353       rend_t *r2 = ROW(y + ov_y - THIS->view_start).r + ov_x;
354
355       for (int x = ov_w; x--; )
356         {
357           text_t t = *t1; *t1++ = *t2; *t2++ = t;
358           rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, THIS->fontset [GET_STYLE (r)]->find_font (t));
359         }
360     }
361
362 }
363
364 void overlay::set (int x, int y, SV *text, SV *rend)
365 {
366   x += border;
367   y += border;
368
369   if (!IN_RANGE_EXC (y, 0, h - border))
370     return;
371
372   wchar_t *wtext = sv2wcs (text);
373
374   for (int col = min (wcslen (wtext), w - x - border); col--; )
375     this->text [y][x + col] = wtext [col];
376
377   free (wtext);
378
379   if (rend)
380     {
381       if (!SvROK (rend) || SvTYPE (SvRV (rend)) != SVt_PVAV)
382         croak ("rend must be arrayref");
383
384       AV *av = (AV *)SvRV (rend);
385
386       for (int col = min (av_len (av) + 1, w - x - border); col--; )
387         this->rend [y][x + col] = SvIV (*av_fetch (av, col, 1));
388     }
389
390   THIS->want_refresh = 1;
391 }
392
393
394 /////////////////////////////////////////////////////////////////////////////
395
396 struct rxvt_perl_interp rxvt_perl;
397
398 static PerlInterpreter *perl;
399
400 rxvt_perl_interp::~rxvt_perl_interp ()
401 {
402   if (perl)
403     {
404       perl_destruct (perl);
405       perl_free (perl);
406     }
407 }
408
409 void
410 rxvt_perl_interp::init ()
411 {
412   if (!perl)
413     {
414       perl_environ = rxvt_environ;
415       swap (perl_environ, environ);
416
417       char *argv[] = {
418         "",
419         "-T",
420         "-edo '" LIBDIR "/urxvt.pm' or ($@ and die $@) or exit 1",
421       };
422
423       perl = perl_alloc ();
424       perl_construct (perl);
425
426       if (perl_parse (perl, xs_init, 3, argv, (char **)NULL)
427           || perl_run (perl))
428         {
429           rxvt_warn ("unable to initialize perl-interpreter, continuing without.\n");
430
431           perl_destruct (perl);
432           perl_free (perl);
433           perl = 0;
434         }
435
436       swap (perl_environ, environ);
437     }
438 }
439
440 static void
441 ungrab (rxvt_term *THIS)
442 {
443   if (THIS->perl.grabtime)
444     {
445       XUngrabKeyboard (THIS->display->display, THIS->perl.grabtime);
446       XUngrabPointer  (THIS->display->display, THIS->perl.grabtime);
447       THIS->perl.grabtime = 0;
448     }
449 }
450
451 bool
452 rxvt_perl_interp::invoke (rxvt_term *term, hook_type htype, ...)
453 {
454   if (!perl)
455     return false;
456
457   if (htype == HOOK_INIT) // first hook ever called
458     {
459       term->perl.self = (void *)newSVptr ((void *)term, "urxvt::term");
460       hv_store ((HV *)SvRV ((SV *)term->perl.self), "_overlay", 8, newRV_noinc ((SV *)newHV ()), 0);
461     }
462   else if (!term->perl.self)
463     return false; // perl not initialized for this instance
464   else if (htype == HOOK_DESTROY)
465     {
466       // handled later
467     }
468   else
469     {
470       if (htype == HOOK_REFRESH_BEGIN || htype == HOOK_REFRESH_END)
471         {
472           HV *hv = (HV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)term->perl.self), "_overlay", 8, 0));
473
474           if (HvKEYS (hv))
475             {
476               hv_iterinit (hv);
477
478               while (HE *he = hv_iternext (hv))
479                 ((overlay *)SvIV (hv_iterval (hv, he)))->swap ();
480             }
481
482         }
483
484       if (!should_invoke [htype])
485         return false;
486     }
487
488   swap (perl_environ, environ);
489
490   try
491     {
492       dSP;
493       va_list ap;
494
495       va_start (ap, htype);
496
497       ENTER;
498       SAVETMPS;
499
500       PUSHMARK (SP);
501
502       XPUSHs (sv_2mortal (newSVterm (term)));
503       XPUSHs (sv_2mortal (newSViv (htype)));
504
505       for (;;) {
506         data_type dt = (data_type)va_arg (ap, int);
507
508         switch (dt)
509           {
510             case DT_INT:
511               XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
512               break;
513
514             case DT_LONG:
515               XPUSHs (sv_2mortal (newSViv (va_arg (ap, long))));
516               break;
517
518             case DT_STR:
519               XPUSHs (taint (sv_2mortal (newSVpv (va_arg (ap, char *), 0))));
520               break;
521
522             case DT_STR_LEN:
523               {
524                 char *str = va_arg (ap, char *);
525                 int len = va_arg (ap, int);
526
527                 XPUSHs (taint (sv_2mortal (newSVpvn (str, len))));
528               }
529               break;
530
531             case DT_WCS_LEN:
532               {
533                 wchar_t *wstr = va_arg (ap, wchar_t *);
534                 int wlen = va_arg (ap, int);
535
536                 XPUSHs (taint (sv_2mortal (wcs2sv (wstr, wlen))));
537               }
538              break;
539
540             case DT_XEVENT:
541               {
542                 XEvent *xe = va_arg (ap, XEvent *);
543                 HV *hv = newHV ();
544
545 #           define set(name, sv) hv_store (hv, # name,  sizeof (# name) - 1, sv, 0)
546 #           define setiv(name, val) hv_store (hv, # name,  sizeof (# name) - 1, newSViv (val), 0)
547 #           undef set
548
549                 setiv (type,       xe->type);
550                 setiv (send_event, xe->xany.send_event);
551                 setiv (serial,     xe->xany.serial);
552
553                 switch (xe->type)
554                   {
555                     case KeyPress:
556                     case KeyRelease:
557                     case ButtonPress:
558                     case ButtonRelease:
559                     case MotionNotify:
560                       setiv (time,   xe->xmotion.time);
561                       setiv (x,      xe->xmotion.x);
562                       setiv (y,      xe->xmotion.y);
563                       setiv (row,    xe->xmotion.y / term->fheight);
564                       setiv (col,    xe->xmotion.x / term->fwidth);
565                       setiv (x_root, xe->xmotion.x_root);
566                       setiv (y_root, xe->xmotion.y_root);
567                       setiv (state,  xe->xmotion.state);
568                       break;
569                   }
570
571                 switch (xe->type)
572                   {
573                     case KeyPress:
574                     case KeyRelease:
575                       setiv (keycode, xe->xkey.keycode);
576                       break;
577
578                     case ButtonPress:
579                     case ButtonRelease:
580                       setiv (button,  xe->xbutton.button);
581                       break;
582
583                     case MotionNotify:
584                       setiv (is_hint, xe->xmotion.is_hint);
585                       break;
586                   }
587
588                 XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
589               }
590               break;
591
592             case DT_END:
593               {
594                 va_end (ap);
595
596                 PUTBACK;
597                 int count = call_pv ("urxvt::invoke", G_ARRAY | G_EVAL);
598                 SPAGAIN;
599
600                 if (count)
601                   {
602                     SV *status = POPs;
603                     count = SvTRUE (status);
604                   }
605
606                 PUTBACK;
607                 FREETMPS;
608                 LEAVE;
609
610                 if (SvTRUE (ERRSV))
611                   {
612                     rxvt_warn ("perl hook %d evaluation error: %s", htype, SvPV_nolen (ERRSV));
613                     ungrab (term); // better lose the grab than the session
614                   }
615
616                 if (htype == HOOK_DESTROY)
617                   {
618                     clearSVptr ((SV *)term->perl.self);
619                     SvREFCNT_dec ((SV *)term->perl.self);
620                   }
621
622                 swap (perl_environ, environ);
623                 return count;
624               }
625
626             default:
627               rxvt_fatal ("FATAL: unable to pass data type %d\n", dt);
628           }
629       }
630     }
631   catch (...)
632     {
633       swap (perl_environ, environ);
634       throw;
635     }
636 }
637
638 /////////////////////////////////////////////////////////////////////////////
639
640 MODULE = urxvt             PACKAGE = urxvt
641
642 PROTOTYPES: ENABLE
643
644 BOOT:
645 {
646   sv_setsv (get_sv ("urxvt::LIBDIR",   1), newSVpvn (LIBDIR,   sizeof (LIBDIR)   - 1));
647   sv_setsv (get_sv ("urxvt::RESNAME",  1), newSVpvn (RESNAME,  sizeof (RESNAME)  - 1));
648   sv_setsv (get_sv ("urxvt::RESCLASS", 1), newSVpvn (RESCLASS, sizeof (RESCLASS) - 1));
649   sv_setsv (get_sv ("urxvt::RXVTNAME", 1), newSVpvn (RXVTNAME, sizeof (RXVTNAME) - 1));
650
651   AV *hookname = get_av ("urxvt::HOOKNAME", 1);
652 # define def(sym) av_store (hookname, HOOK_ ## sym, newSVpv (# sym, 0));
653 # include "hookinc.h"
654 # undef def
655
656   HV *option = get_hv ("urxvt::OPTION", 1);
657 # define def(name,val) hv_store (option, # name, sizeof (# name) - 1, newSVuv (Opt_ ## name), 0);
658 # define nodef(name)
659 # include "optinc.h"
660 # undef nodef
661 # undef def
662
663   HV *stash = gv_stashpv ("urxvt", 1);
664 # define export_const_iv(name) newCONSTSUB (stash, # name, newSViv (name));
665   export_const_iv (DEFAULT_RSTYLE);
666   export_const_iv (OVERLAY_RSTYLE);
667   export_const_iv (RS_Bold);
668   export_const_iv (RS_Italic);
669   export_const_iv (RS_Blink);
670   export_const_iv (RS_RVid);
671   export_const_iv (RS_Uline);
672
673   export_const_iv (CurrentTime);
674   export_const_iv (ShiftMask);
675   export_const_iv (LockMask);
676   export_const_iv (ControlMask);
677   export_const_iv (Mod1Mask);
678   export_const_iv (Mod2Mask);
679   export_const_iv (Mod3Mask);
680   export_const_iv (Mod4Mask);
681   export_const_iv (Mod5Mask);
682   export_const_iv (Button1Mask);
683   export_const_iv (Button2Mask);
684   export_const_iv (Button3Mask);
685   export_const_iv (Button4Mask);
686   export_const_iv (Button5Mask);
687   export_const_iv (AnyModifier);
688
689   export_const_iv (EVENT_NONE);
690   export_const_iv (EVENT_READ);
691   export_const_iv (EVENT_WRITE);
692 }
693
694 void
695 set_should_invoke (int htype, int value)
696         CODE:
697         rxvt_perl.should_invoke [htype] = value;
698
699 void
700 warn (const char *msg)
701         CODE:
702         rxvt_warn ("%s", msg);
703
704 void
705 fatal (const char *msg)
706         CODE:
707         rxvt_fatal ("%s", msg);
708
709 SV *
710 untaint (SV *sv)
711         CODE:
712         RETVAL = newSVsv (sv);
713         SvTAINTED_off (RETVAL);
714         OUTPUT:
715         RETVAL
716
717 void
718 _exit (int status)
719
720 bool
721 safe ()
722         CODE:
723         RETVAL = !rxvt_tainted ();
724         OUTPUT:
725         RETVAL
726
727 NV
728 NOW ()
729         CODE:
730         RETVAL = NOW;
731         OUTPUT:
732         RETVAL
733
734 int
735 GET_BASEFG (int rend)
736         CODE:
737         RETVAL = GET_BASEFG (rend);
738         OUTPUT:
739         RETVAL
740
741 int
742 GET_BASEBG (int rend)
743         CODE:
744         RETVAL = GET_BASEBG (rend);
745         OUTPUT:
746         RETVAL
747
748 int
749 SET_FGCOLOR (int rend, int new_color)
750         CODE:
751         RETVAL = SET_FGCOLOR (rend, new_color);
752         OUTPUT:
753         RETVAL
754
755 int
756 SET_BGCOLOR (int rend, int new_color)
757         CODE:
758         RETVAL = SET_BGCOLOR (rend, new_color);
759         OUTPUT:
760         RETVAL
761
762 int
763 GET_CUSTOM (int rend)
764         CODE:
765         RETVAL = (rend && RS_customMask) >> RS_customShift;
766         OUTPUT:
767         RETVAL
768
769 int
770 SET_CUSTOM (int rend, int new_value)
771         CODE:
772 {
773         if (!IN_RANGE_EXC (new_value, 0, RS_customCount))
774           croak ("custom value out of range, must be 0..%d", RS_customCount - 1);
775
776         RETVAL = (rend & ~RS_customMask)
777                | ((new_value << RS_customShift) & RS_customMask);
778 }
779         OUTPUT:
780         RETVAL
781
782 MODULE = urxvt             PACKAGE = urxvt::term
783
784 SV *
785 _new (...)
786         CODE:
787 {
788         if (items < 1 || !SvROK (ST (0)) || SvTYPE (SvRV (ST (0))) != SVt_PVAV)
789           croak ("first argument to urxvt::term->_new must be arrayref");
790
791         rxvt_term *term = new rxvt_term;
792
793         term->argv = new stringvec;
794         term->envv = new stringvec;
795
796         for (int i = 1; i < items; i++)
797           term->argv->push_back (strdup (SvPVbyte_nolen (ST (i))));
798
799         AV *envv = (AV *)SvRV (ST (0));
800         for (int i = av_len (envv) + 1; i--; )
801           term->envv->push_back (strdup (SvPVbyte_nolen (*av_fetch (envv, i, 1))));
802
803         term->envv->push_back (0);
804
805         bool success;
806
807         try
808           {
809             success = term->init (term->argv->size (), term->argv->begin ());
810           }
811         catch (const class rxvt_failure_exception &e)
812           {
813             success = false;
814           }
815
816         if (!success)
817           {
818             term->destroy ();
819             croak ("error while initializing new terminal instance");
820           }
821
822         RETVAL = term && term->perl.self
823                  ? newSVterm (term) : &PL_sv_undef;
824 }
825         OUTPUT:
826         RETVAL
827
828 void
829 rxvt_term::destroy ()
830
831 void
832 rxvt_term::grab_button (int button, U32 modifiers)
833         CODE:
834         XGrabButton (THIS->display->display, button, modifiers, THIS->vt, 1,
835                      ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
836                      GrabModeSync, GrabModeSync, None, GRAB_CURSOR);
837
838 bool
839 rxvt_term::grab (U32 eventtime, int sync = 0)
840         CODE:
841 {
842         int mode = sync ? GrabModeSync : GrabModeAsync;
843
844         THIS->perl.grabtime = 0;
845
846         if (!XGrabPointer (THIS->display->display, THIS->vt, 0,
847                            ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
848                            mode, mode, None, GRAB_CURSOR, eventtime))
849           if (!XGrabKeyboard (THIS->display->display, THIS->vt, 0, mode, mode, eventtime))
850             THIS->perl.grabtime = eventtime;
851           else
852             XUngrabPointer (THIS->display->display, eventtime);
853
854         RETVAL = !!THIS->perl.grabtime;
855 }
856         OUTPUT:
857         RETVAL
858
859 void
860 rxvt_term::allow_events_async ()
861         CODE:
862         XAllowEvents (THIS->display->display, AsyncBoth,      THIS->perl.grabtime);
863
864 void
865 rxvt_term::allow_events_sync ()
866         CODE:
867         XAllowEvents (THIS->display->display, SyncBoth,       THIS->perl.grabtime);
868
869 void
870 rxvt_term::allow_events_replay ()
871         CODE:
872         XAllowEvents (THIS->display->display, ReplayPointer,  THIS->perl.grabtime);
873         XAllowEvents (THIS->display->display, ReplayKeyboard, THIS->perl.grabtime);
874
875 void
876 rxvt_term::ungrab ()
877         CODE:
878         ungrab (THIS);
879
880 int
881 rxvt_term::strwidth (SV *str)
882         CODE:
883 {
884         wchar_t *wstr = sv2wcs (str);
885
886         rxvt_push_locale (THIS->locale);
887         RETVAL = wcswidth (wstr, wcslen (wstr));
888         rxvt_pop_locale ();
889
890         free (wstr);
891 }
892         OUTPUT:
893         RETVAL
894
895 SV *
896 rxvt_term::locale_encode (SV *str)
897         CODE:
898 {
899         wchar_t *wstr = sv2wcs (str);
900
901         rxvt_push_locale (THIS->locale);
902         char *mbstr = rxvt_wcstombs (wstr);
903         rxvt_pop_locale ();
904
905         free (wstr);
906
907         RETVAL = taint_if (newSVpv (mbstr, 0), str);
908         free (mbstr);
909 }
910         OUTPUT:
911         RETVAL
912
913 SV *
914 rxvt_term::locale_decode (SV *octets)
915         CODE:
916 {
917         STRLEN len;
918         char *data = SvPVbyte (octets, len);
919
920         rxvt_push_locale (THIS->locale);
921         wchar_t *wstr = rxvt_mbstowcs (data, len);
922         rxvt_pop_locale ();
923
924         RETVAL = taint_if (wcs2sv (wstr), octets);
925         free (wstr);
926 }
927         OUTPUT:
928         RETVAL
929
930 #define TERM_OFFSET(sym) offsetof (TermWin_t, sym)
931
932 #define TERM_OFFSET_width      TERM_OFFSET(width)
933 #define TERM_OFFSET_height     TERM_OFFSET(height)
934 #define TERM_OFFSET_fwidth     TERM_OFFSET(fwidth)
935 #define TERM_OFFSET_fheight    TERM_OFFSET(fheight)
936 #define TERM_OFFSET_fbase      TERM_OFFSET(fbase)
937 #define TERM_OFFSET_nrow       TERM_OFFSET(nrow)
938 #define TERM_OFFSET_ncol       TERM_OFFSET(ncol)
939 #define TERM_OFFSET_focus      TERM_OFFSET(focus)
940 #define TERM_OFFSET_mapped     TERM_OFFSET(mapped)
941 #define TERM_OFFSET_saveLines  TERM_OFFSET(saveLines)
942 #define TERM_OFFSET_total_rows TERM_OFFSET(total_rows)
943 #define TERM_OFFSET_nsaved     TERM_OFFSET(nsaved)
944
945 int
946 rxvt_term::width ()
947         ALIAS:
948            width      = TERM_OFFSET_width
949            height     = TERM_OFFSET_height
950            fwidth     = TERM_OFFSET_fwidth
951            fheight    = TERM_OFFSET_fheight
952            fbase      = TERM_OFFSET_fbase
953            nrow       = TERM_OFFSET_nrow
954            ncol       = TERM_OFFSET_ncol
955            focus      = TERM_OFFSET_focus
956            mapped     = TERM_OFFSET_mapped
957            saveLines  = TERM_OFFSET_saveLines
958            total_rows = TERM_OFFSET_total_rows
959            nsaved     = TERM_OFFSET_nsaved
960         CODE:
961         RETVAL = *(int *)((char *)THIS + ix);
962         OUTPUT:
963         RETVAL
964
965 unsigned int
966 rxvt_term::ModLevel3Mask ()
967         ALIAS:
968            ModLevel3Mask  = 0
969            ModMetaMask    = 1
970            ModNumLockMask = 2
971         CODE:
972         switch (ix)
973           {
974            case 0: RETVAL = THIS->ModLevel3Mask;  break;
975            case 1: RETVAL = THIS->ModMetaMask;    break;
976            case 2: RETVAL = THIS->ModNumLockMask; break;
977           }
978         OUTPUT:
979         RETVAL
980
981 char *
982 rxvt_term::display_id ()
983         ALIAS:
984            display_id = 0
985            locale     = 1
986         CODE:
987         switch (ix)
988           {
989             case 0: RETVAL = THIS->display->id; break;
990             case 1: RETVAL = THIS->locale;      break;
991           }
992         OUTPUT:
993         RETVAL
994
995 SV *
996 rxvt_term::_env ()
997         CODE:
998 {
999         if (THIS->envv)
1000           {
1001             AV *av = newAV ();
1002
1003             for (char **i = THIS->envv->begin (); i != THIS->envv->end (); ++i)
1004               if (*i)
1005                 av_push (av, newSVpv (*i, 0));
1006
1007             RETVAL = newRV_noinc ((SV *)av);
1008           }
1009         else
1010           RETVAL = &PL_sv_undef;
1011 }
1012         OUTPUT:
1013         RETVAL
1014
1015 int
1016 rxvt_term::pty_ev_events (int events = EVENT_UNDEF)
1017         CODE:
1018         RETVAL = THIS->pty_ev.events;
1019         if (events != EVENT_UNDEF)
1020           THIS->pty_ev.set (events);
1021         OUTPUT:
1022         RETVAL
1023
1024 U32
1025 rxvt_term::parent ()
1026         CODE:
1027         RETVAL = (U32)THIS->parent [0];
1028         OUTPUT:
1029         RETVAL
1030
1031 U32
1032 rxvt_term::vt ()
1033         CODE:
1034         RETVAL = (U32)THIS->vt;
1035         OUTPUT:
1036         RETVAL
1037
1038 U32
1039 rxvt_term::rstyle (U32 new_rstyle = THIS->rstyle)
1040         CODE:
1041 {
1042         RETVAL = THIS->rstyle;
1043         THIS->rstyle = new_rstyle;
1044 }
1045         OUTPUT:
1046         RETVAL
1047
1048 int
1049 rxvt_term::view_start (int newval = -1)
1050         CODE:
1051 {
1052         RETVAL = THIS->view_start;
1053
1054         if (newval >= 0)
1055           {
1056             THIS->view_start = min (newval, THIS->nsaved);
1057             THIS->scr_changeview (RETVAL);
1058           }
1059 }
1060         OUTPUT:
1061         RETVAL
1062
1063 void
1064 rxvt_term::want_refresh ()
1065         CODE:
1066         THIS->want_refresh = 1;
1067
1068 void
1069 rxvt_term::ROW_t (int row_number, SV *new_text = 0, int start_col = 0, int start_ofs = 0, int max_len = MAX_COLS)
1070         PPCODE:
1071 {
1072         if (!IN_RANGE_EXC (row_number, -THIS->nsaved, THIS->nrow))
1073           XSRETURN_EMPTY;
1074
1075         line_t &l = ROW(row_number);
1076
1077         if (GIMME_V != G_VOID)
1078           {
1079             wchar_t *wstr = new wchar_t [THIS->ncol];
1080
1081             for (int col = 0; col < THIS->ncol; col++)
1082               wstr [col] = l.t [col];
1083
1084             XPUSHs (taint (sv_2mortal (wcs2sv (wstr, THIS->ncol))));
1085
1086             delete [] wstr;
1087           }
1088
1089         if (new_text)
1090           {
1091             wchar_t *wstr = sv2wcs (new_text);
1092
1093             int len = min (wcslen (wstr) - start_ofs, max_len);
1094
1095             if (!IN_RANGE_INC (start_col, 0, THIS->ncol - len))
1096               {
1097                 free (wstr);
1098                 croak ("new_text extends beyond horizontal margins");
1099               }
1100
1101             for (int col = start_col; col < start_col + len; col++)
1102               {
1103                 l.t [col] = wstr [start_ofs + col - start_col];
1104                 l.r [col] = SET_FONT (l.r [col], THIS->fontset [GET_STYLE (l.r [col])]->find_font (l.t [col]));
1105               }
1106
1107             free (wstr);
1108           }
1109 }
1110
1111 void
1112 rxvt_term::ROW_r (int row_number, SV *new_rend = 0, int start_col = 0, int start_ofs = 0, int max_len = MAX_COLS)
1113         PPCODE:
1114 {
1115         if (!IN_RANGE_EXC (row_number, -THIS->nsaved, THIS->nrow))
1116           XSRETURN_EMPTY;
1117
1118         line_t &l = ROW(row_number);
1119
1120         if (GIMME_V != G_VOID)
1121           {
1122             AV *av = newAV ();
1123
1124             av_extend (av, THIS->ncol - 1);
1125             for (int col = 0; col < THIS->ncol; col++)
1126               av_store (av, col, newSViv (l.r [col]));
1127
1128             XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
1129           }
1130
1131         if (new_rend)
1132           {
1133             if (!SvROK (new_rend) || SvTYPE (SvRV (new_rend)) != SVt_PVAV)
1134               croak ("new_rend must be arrayref");
1135
1136             AV *av = (AV *)SvRV (new_rend);
1137             int len = min (av_len (av) + 1 - start_ofs, max_len);
1138
1139             if (!IN_RANGE_INC (start_col, 0, THIS->ncol - len))
1140               croak ("new_rend array extends beyond horizontal margins");
1141
1142             for (int col = start_col; col < start_col + len; col++)
1143               {
1144                 rend_t r = SvIV (*av_fetch (av, start_ofs + col - start_col, 1)) & ~RS_fontMask;
1145
1146                 l.r [col] = SET_FONT (r, THIS->fontset [GET_STYLE (r)]->find_font (l.t [col]));
1147               }
1148           }
1149 }
1150
1151 int
1152 rxvt_term::ROW_l (int row_number, int new_length = -1)
1153         CODE:
1154 {
1155         if (!IN_RANGE_EXC (row_number, -THIS->nsaved, THIS->nrow))
1156           XSRETURN_EMPTY;
1157
1158         line_t &l = ROW(row_number);
1159         RETVAL = l.l;
1160
1161         if (new_length >= 0)
1162           l.l = new_length;
1163 }
1164         OUTPUT:
1165         RETVAL
1166
1167 bool
1168 rxvt_term::ROW_is_longer (int row_number, int new_is_longer = -1)
1169         CODE:
1170 {
1171         if (!IN_RANGE_EXC (row_number, -THIS->nsaved, THIS->nrow))
1172           XSRETURN_EMPTY;
1173
1174         line_t &l = ROW(row_number);
1175         RETVAL = l.is_longer ();
1176
1177         if (new_is_longer >= 0)
1178           l.is_longer (new_is_longer);
1179 }
1180         OUTPUT:
1181         RETVAL
1182
1183 SV *
1184 rxvt_term::special_encode (SV *string)
1185         CODE:
1186 {
1187         wchar_t *wstr = sv2wcs (string);
1188         int wlen = wcslen (wstr);
1189         wchar_t *rstr = new wchar_t [wlen]; // cannot become longer
1190
1191         rxvt_push_locale (THIS->locale);
1192
1193         wchar_t *r = rstr;
1194         for (wchar_t *s = wstr; *s; s++)
1195           if (wcwidth (*s) == 0)
1196             {
1197               if (r == rstr)
1198                 croak ("leading combining character unencodable");
1199
1200               unicode_t n = rxvt_compose (r[-1], *s);
1201               if (n == NOCHAR)
1202                 n = rxvt_composite.compose (r[-1], *s);
1203
1204               r[-1] = n;
1205             }
1206 #if !UNICODE_3
1207           else if (*s >= 0x10000)
1208             *r++ = rxvt_composite.compose (*s);
1209 #endif
1210           else
1211             *r++ = *s;
1212
1213         rxvt_pop_locale ();
1214
1215         RETVAL = taint_if (wcs2sv (rstr, r - rstr), string);
1216
1217         delete [] rstr;
1218 }
1219         OUTPUT:
1220         RETVAL
1221
1222 SV *
1223 rxvt_term::special_decode (SV *text)
1224         CODE:
1225 {
1226         wchar_t *wstr = sv2wcs (text);
1227         int wlen = wcslen (wstr);
1228         int dlen = 0;
1229
1230         // find length
1231         for (wchar_t *s = wstr; *s; s++)
1232           if (*s == NOCHAR)
1233             ;
1234           else if (IS_COMPOSE (*s))
1235             dlen += rxvt_composite.expand (*s, 0);
1236           else
1237             dlen++;
1238
1239         wchar_t *rstr = new wchar_t [dlen];
1240
1241         // decode
1242         wchar_t *r = rstr;
1243         for (wchar_t *s = wstr; *s; s++)
1244           if (*s == NOCHAR)
1245             ;
1246           else if (IS_COMPOSE (*s))
1247             r += rxvt_composite.expand (*s, r);
1248           else
1249             *r++ = *s;
1250
1251         RETVAL = taint_if (wcs2sv (rstr, r - rstr), text);
1252
1253         delete [] rstr;
1254 }
1255         OUTPUT:
1256         RETVAL
1257
1258 void
1259 rxvt_term::_resource (char *name, int index, SV *newval = 0)
1260         PPCODE:
1261 {
1262         struct resval { const char *name; int value; } rslist [] = {
1263 #         define def(name) { # name, Rs_ ## name },
1264 #         define reserve(name,count)
1265 #         include "rsinc.h"
1266 #         undef def
1267 #         undef reserve
1268         };
1269
1270         struct resval *rs = rslist + sizeof (rslist) / sizeof (rslist [0]);
1271
1272         do {
1273           if (rs-- == rslist)
1274             croak ("no such resource '%s', requested", name);
1275         } while (strcmp (name, rs->name));
1276
1277         index += rs->value;
1278
1279         if (!IN_RANGE_EXC (index, 0, NUM_RESOURCES))
1280           croak ("requested out-of-bound resource %s+%d,", name, index - rs->value);
1281
1282         if (GIMME_V != G_VOID)
1283           XPUSHs (THIS->rs [index] ? sv_2mortal (taint (newSVpv (THIS->rs [index], 0))) : &PL_sv_undef);
1284
1285         if (newval)
1286           {
1287             if (SvOK (newval))
1288               {
1289                 char *str = strdup (SvPVbyte_nolen (newval));
1290                 THIS->rs [index] = str;
1291                 THIS->allocated.push_back (str);
1292               }
1293             else
1294               THIS->rs [index] = 0;
1295           }
1296 }
1297
1298 const char *
1299 rxvt_term::x_resource (const char *name)
1300         CLEANUP:
1301         SvTAINTED_on (ST (0));
1302
1303 bool
1304 rxvt_term::option (U32 optval, int set = -1)
1305         CODE:
1306 {
1307         RETVAL = THIS->options & optval;
1308
1309         if (set >= 0)
1310           {
1311             if (set)
1312               THIS->options |= optval;
1313             else
1314               THIS->options &= ~optval;
1315
1316             switch (optval)
1317               {
1318                 case Opt_skipBuiltinGlyphs:
1319                   THIS->set_fonts ();
1320                   THIS->scr_remap_chars ();
1321                   THIS->scr_touch (true);
1322                   THIS->want_refresh = 1;
1323                   break;
1324
1325                 case Opt_cursorUnderline:
1326                   THIS->want_refresh = 1;
1327                   break;
1328
1329 #                  case Opt_scrollBar_floating:
1330 #                  case Opt_scrollBar_right:
1331 #                    THIS->resize_all_windows (THIS->width, THIS->height, 1);
1332 #                    break;
1333               }
1334           }
1335 }
1336         OUTPUT:
1337         RETVAL
1338
1339 bool
1340 rxvt_term::parse_keysym (char *keysym, char *str)
1341         CODE:
1342         RETVAL = 0 < THIS->parse_keysym (keysym, str);
1343         THIS->keyboard->register_done ();
1344         OUTPUT:
1345         RETVAL
1346
1347 void
1348 rxvt_term::screen_cur (...)
1349         PROTOTYPE: $;$$
1350         ALIAS:
1351            screen_cur     = 0
1352            selection_beg  = 1
1353            selection_end  = 2
1354            selection_mark = 3
1355         PPCODE:
1356 {
1357         row_col_t &rc = ix == 0 ? THIS->screen.cur
1358                       : ix == 1 ? THIS->selection.beg
1359                       : ix == 2 ? THIS->selection.end
1360                       :           THIS->selection.mark;
1361
1362         if (GIMME_V != G_VOID)
1363           {
1364             EXTEND (SP, 2);
1365             PUSHs (sv_2mortal (newSViv (rc.row)));
1366             PUSHs (sv_2mortal (newSViv (rc.col)));
1367           }
1368
1369         if (items == 3)
1370           {
1371             rc.row = clamp (SvIV (ST (1)), -THIS->nsaved, THIS->nrow - 1);
1372             rc.col = clamp (SvIV (ST (2)), 0, THIS->ncol - 1);
1373
1374             if (ix)
1375               THIS->want_refresh = 1;
1376           }
1377 }
1378
1379 char
1380 rxvt_term::cur_charset ()
1381         CODE:
1382         RETVAL = THIS->charsets [THIS->screen.charset];
1383         OUTPUT:
1384         RETVAL
1385
1386 #void
1387 #rxvt_term::selection_clear ()
1388
1389 void
1390 rxvt_term::selection_make (U32 eventtime, bool rect = false)
1391         CODE:
1392         THIS->selection.op = SELECTION_CONT;
1393         THIS->selection.rect = rect;
1394         THIS->selection_make (eventtime);
1395
1396 int
1397 rxvt_term::selection_grab (U32 eventtime)
1398
1399 void
1400 rxvt_term::selection (SV *newtext = 0)
1401         PPCODE:
1402 {
1403         if (GIMME_V != G_VOID)
1404           XPUSHs (THIS->selection.text
1405                   ? taint (sv_2mortal (wcs2sv (THIS->selection.text, THIS->selection.len)))
1406                   : &PL_sv_undef);
1407
1408         if (newtext)
1409           {
1410             free (THIS->selection.text);
1411
1412             THIS->selection.text = sv2wcs (newtext);
1413             THIS->selection.len = wcslen (THIS->selection.text);
1414           }
1415 }
1416
1417 void
1418 rxvt_term::scr_xor_rect (int beg_row, int beg_col, int end_row, int end_col, U32 rstyle1 = RS_RVid, U32 rstyle2 = RS_RVid | RS_Uline)
1419
1420 void
1421 rxvt_term::scr_xor_span (int beg_row, int beg_col, int end_row, int end_col, U32 rstyle = RS_RVid)
1422
1423 void
1424 rxvt_term::scr_bell ()
1425
1426 void
1427 rxvt_term::scr_add_lines (SV *string)
1428         CODE:
1429 {
1430         wchar_t *wstr = sv2wcs (string);
1431         THIS->scr_add_lines (wstr, wcslen (wstr));
1432         free (wstr);
1433 }
1434
1435 void
1436 rxvt_term::tt_write (SV *octets)
1437         INIT:
1438           STRLEN len;
1439           char *str = SvPVbyte (octets, len);
1440         C_ARGS:
1441           str, len
1442
1443 void
1444 rxvt_term::cmd_parse (SV *octets)
1445         CODE:
1446 {
1447         STRLEN len;
1448         char *str = SvPVbyte (octets, len);
1449
1450         char *old_cmdbuf_ptr  = THIS->cmdbuf_ptr;
1451         char *old_cmdbuf_endp = THIS->cmdbuf_endp;
1452
1453         THIS->cmdbuf_ptr  = str;
1454         THIS->cmdbuf_endp = str + len;
1455
1456         rxvt_push_locale (THIS->locale);
1457         THIS->cmd_parse ();
1458         rxvt_pop_locale ();
1459
1460         THIS->cmdbuf_ptr  = old_cmdbuf_ptr;
1461         THIS->cmdbuf_endp = old_cmdbuf_endp;
1462 }
1463
1464 SV *
1465 rxvt_term::overlay (int x, int y, int w, int h, int rstyle = OVERLAY_RSTYLE, int border = 2)
1466         CODE:
1467 {
1468         overlay *o = new overlay (THIS, x, y, w, h, rstyle, border);
1469         RETVAL = newSVptr ((void *)o, "urxvt::overlay");
1470         o->self = (HV *)SvRV (RETVAL);
1471 }
1472         OUTPUT:
1473         RETVAL
1474
1475 MODULE = urxvt             PACKAGE = urxvt::overlay
1476
1477 void
1478 overlay::set (int x, int y, SV *text, SV *rend = 0)
1479
1480 void
1481 overlay::show ()
1482
1483 void
1484 overlay::hide ()
1485
1486 void
1487 overlay::DESTROY ()
1488
1489 MODULE = urxvt             PACKAGE = urxvt::timer
1490
1491 SV *
1492 timer::new ()
1493         CODE:
1494         timer *w =  new timer;
1495         w->start (NOW);
1496         RETVAL = newSVptr ((void *)w, "urxvt::timer");
1497         w->self = (HV *)SvRV (RETVAL);
1498         OUTPUT:
1499         RETVAL
1500
1501 timer *
1502 timer::cb (SV *cb)
1503         CODE:
1504         THIS->cb (cb);
1505         RETVAL = THIS;
1506         OUTPUT:
1507         RETVAL
1508
1509 NV
1510 timer::at ()
1511         CODE:
1512         RETVAL = THIS->at;
1513         OUTPUT:
1514         RETVAL
1515
1516 timer *
1517 timer::interval (NV interval)
1518         CODE:
1519         THIS->interval = interval;
1520         RETVAL = THIS;
1521         OUTPUT:
1522         RETVAL
1523
1524 timer *
1525 timer::set (NV tstamp)
1526         CODE:
1527         THIS->set (tstamp);
1528         RETVAL = THIS;
1529         OUTPUT:
1530         RETVAL
1531
1532 timer *
1533 timer::start (NV tstamp = THIS->at)
1534         CODE:
1535         THIS->start (tstamp);
1536         RETVAL = THIS;
1537         OUTPUT:
1538         RETVAL
1539
1540 timer *
1541 timer::stop ()
1542         CODE:
1543         THIS->stop ();
1544         RETVAL = THIS;
1545         OUTPUT:
1546         RETVAL
1547
1548 void
1549 timer::DESTROY ()
1550
1551 MODULE = urxvt             PACKAGE = urxvt::iow
1552
1553 SV *
1554 iow::new ()
1555         CODE:
1556         iow *w =  new iow;
1557         RETVAL = newSVptr ((void *)w, "urxvt::iow");
1558         w->self = (HV *)SvRV (RETVAL);
1559         OUTPUT:
1560         RETVAL
1561
1562 iow *
1563 iow::cb (SV *cb)
1564         CODE:
1565         THIS->cb (cb);
1566         RETVAL = THIS;
1567         OUTPUT:
1568         RETVAL
1569
1570 iow *
1571 iow::fd (int fd)
1572         CODE:
1573         THIS->fd = fd;
1574         RETVAL = THIS;
1575         OUTPUT:
1576         RETVAL
1577
1578 iow *
1579 iow::events (short events)
1580         CODE:
1581         THIS->events = events;
1582         RETVAL = THIS;
1583         OUTPUT:
1584         RETVAL
1585
1586 iow *
1587 iow::start ()
1588         CODE:
1589         THIS->start ();
1590         RETVAL = THIS;
1591         OUTPUT:
1592         RETVAL
1593
1594 iow *
1595 iow::stop ()
1596         CODE:
1597         THIS->stop ();
1598         RETVAL = THIS;
1599         OUTPUT:
1600         RETVAL
1601
1602 void
1603 iow::DESTROY ()
1604
1605