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