*** 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 #ifdef HAVE_SCROLLBARS
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 typedef int CHAINED UNUSED;
56
57 /////////////////////////////////////////////////////////////////////////////
58
59 static wchar_t *
60 sv2wcs (SV *sv)
61 {
62   STRLEN len;
63   char *str = SvPVutf8 (sv, len);
64   return rxvt_utf8towcs (str, len);
65 }
66
67 static SV *
68 wcs2sv (wchar_t *wstr, int len = -1)
69 {
70   char *str = rxvt_wcstoutf8 (wstr, len);
71
72   SV *sv = newSVpv (str, 0);
73   SvUTF8_on (sv);
74   free (str);
75
76   return sv;
77 }
78
79 static SV *
80 new_ref (HV *hv, const char *klass)
81 {
82   return sv_bless (newRV ((SV *)hv), gv_stashpv (klass, 1));
83 }
84
85 static SV *
86 newSVptr (void *ptr, const char *klass)
87 {
88   HV *hv = newHV ();
89   sv_magic ((SV *)hv, 0, PERL_MAGIC_ext, (char *)ptr, 0);
90   return sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1));
91 }
92
93 static void
94 clearSVptr (SV *sv)
95 {
96   if (SvROK (sv))
97     sv = SvRV (sv);
98
99   hv_clear ((HV *)sv);
100   sv_unmagic (sv, PERL_MAGIC_ext);
101 }
102
103 static long
104 SvPTR (SV *sv, const char *klass)
105 {
106   if (!sv_derived_from (sv, klass))
107     croak ("object of type %s expected", klass);
108
109   MAGIC *mg = mg_find (SvRV (sv), PERL_MAGIC_ext);
110
111   if (!mg)
112     croak ("perl code used %s object, but C++ object is already destroyed, caught", klass);
113
114   return (long)mg->mg_ptr;
115 }
116
117 #define newSVterm(term) SvREFCNT_inc ((SV *)(term)->perl.self)
118 #define SvTERM(sv) (rxvt_term *)SvPTR ((sv), "urxvt::term")
119
120 /////////////////////////////////////////////////////////////////////////////
121
122 #define SvWATCHER(sv) (perl_watcher *)SvPTR (sv, "urxvt::watcher")
123
124 struct perl_watcher
125 {
126   SV *cbsv;
127   HV *self;
128
129   perl_watcher ()
130   : cbsv (0)
131   {
132   }
133
134   ~perl_watcher ()
135   {
136     SvREFCNT_dec (cbsv);
137   }
138
139   void cb (SV *cb)
140   {
141     SvREFCNT_dec (cbsv);
142     cbsv = newSVsv (cb);
143   }
144
145   void invoke (const char *type, SV *self, int arg = -1);
146 };
147
148 void
149 perl_watcher::invoke (const char *type, SV *self, int arg)
150 {
151   dSP;
152
153   ENTER;
154   SAVETMPS;
155
156   PUSHMARK (SP);
157
158   XPUSHs (sv_2mortal (self));
159
160   if (arg >= 0)
161     XPUSHs (sv_2mortal (newSViv (arg)));
162
163   PUTBACK;
164   call_sv (cbsv, G_VOID | G_EVAL | G_DISCARD);
165   SPAGAIN;
166
167   PUTBACK;
168   FREETMPS;
169   LEAVE;
170
171   if (SvTRUE (ERRSV))
172     rxvt_warn ("%s callback evaluation error: %s", type, SvPV_nolen (ERRSV));
173 }
174
175 #define newSVtimer(timer) new_ref ((timer)->self, "urxvt::timer")
176 #define SvTIMER(sv) (timer *)(perl_watcher *)SvPTR ((sv), "urxvt::timer")
177
178 struct timer : perl_watcher, time_watcher
179 {
180   tstamp interval;
181
182   timer ()
183   : time_watcher (this, &timer::execute)
184   {
185   }
186
187   void execute (time_watcher &w)
188   {
189     if (interval)
190       start (at + interval);
191
192     invoke ("urxvt::timer", newSVtimer (this));
193   }
194 };
195
196 #define newSViow(iow) new_ref ((iow)->self, "urxvt::iow")
197 #define SvIOW(sv) (iow *)(perl_watcher *)SvPTR ((sv), "urxvt::iow")
198
199 struct iow : perl_watcher, io_watcher
200 {
201   iow ()
202   : io_watcher (this, &iow::execute)
203   {
204   }
205
206   void execute (io_watcher &w, short revents)
207   {
208     invoke ("urxvt::iow", newSViow (this), revents);
209   }
210 };
211
212 #define newSViw(iw) new_ref ((iw)->self, "urxvt::iw")
213 #define SvIW(sv) (iw *)(perl_watcher *)SvPTR ((sv), "urxvt::iw")
214
215 struct iw : perl_watcher, idle_watcher
216 {
217   iw ()
218   : idle_watcher (this, &iw::execute)
219   {
220   }
221
222   void execute (idle_watcher &w)
223   {
224     invoke ("urxvt::iw", newSViw (this));
225   }
226 };
227
228 #define newSVpw(pw) new_ref ((pw)->self, "urxvt::pw")
229 #define SvPW(sv) (pw *)(perl_watcher *)SvPTR ((sv), "urxvt::pw")
230
231 struct pw : perl_watcher, child_watcher
232 {
233   pw ()
234   : child_watcher (this, &pw::execute)
235   {
236   }
237
238   void execute (child_watcher &w, int status)
239   {
240     invoke ("urxvt::pw", newSVpw (this), status);
241   }
242 };
243
244 /////////////////////////////////////////////////////////////////////////////
245
246 #define SvOVERLAY(sv) (overlay *)SvPTR (sv, "urxvt::overlay")
247
248 class overlay {
249   rxvt_term *THIS;
250   AV *overlay_av;
251   int x, y, w, h;
252   int border;
253   text_t **text;
254   rend_t **rend;
255
256 public:
257   HV *self;
258
259   overlay (rxvt_term *THIS, int x_, int y_, int w_, int h_, rend_t rstyle, int border);
260   ~overlay ();
261
262   void show ();
263   void hide ();
264
265   void swap ();
266
267   void set (int x, int y, SV *str, SV *rend);
268 };
269
270 overlay::overlay (rxvt_term *THIS, int x_, int y_, int w_, int h_, rend_t rstyle, int border)
271 : THIS(THIS), x(x_), y(y_), w(w_), h(h_), border(border == 2), overlay_av (0)
272 {
273   if (border == 2)
274     {
275       w += 2;
276       h += 2;
277     }
278
279   text = new text_t *[h];
280   rend = new rend_t *[h];
281
282   for (int y = 0; y < h; y++)
283     {
284       text_t *tp = text[y] = new text_t[w];
285       rend_t *rp = rend[y] = new rend_t[w];
286
287       text_t t0, t1, t2;
288       rend_t r = rstyle;
289
290       if (border == 2)
291         {
292           if (y == 0)
293             t0 = 0x2554, t1 = 0x2550, t2 = 0x2557;
294           else if (y < h - 1)
295             t0 = 0x2551, t1 = 0x0020, t2 = 0x2551;
296           else
297             t0 = 0x255a, t1 = 0x2550, t2 = 0x255d;
298
299           *tp++ = t0;
300           *rp++ = r;
301
302           for (int x = w - 2; x-- > 0; )
303             {
304               *tp++ = t1;
305               *rp++ = r;
306             }
307
308           *tp = t2;
309           *rp = r;
310         }
311       else
312         for (int x = w; x-- > 0; )
313           {
314             *tp++ = 0x0020;
315             *rp++ = r;
316           }
317     }
318
319   show ();
320 }
321
322 overlay::~overlay ()
323 {
324   hide ();
325
326   for (int y = h; y--; )
327     {
328       delete [] text[y];
329       delete [] rend[y];
330     }
331
332   delete [] text;
333   delete [] rend;
334 }
335
336 void
337 overlay::show ()
338 {
339   if (overlay_av)
340     return;
341
342   overlay_av = (AV *)SvREFCNT_inc (SvRV (
343         *hv_fetch ((HV *)SvRV ((SV *)THIS->perl.self), "_overlay", 8, 0)
344      ));
345   av_push (overlay_av, newSViv ((long)this));
346
347   THIS->want_refresh = 1;
348 }
349
350 void
351 overlay::hide ()
352 {
353   if (!overlay_av)
354     return;
355
356   int i;
357
358   for (i = AvFILL (overlay_av); i >= 0; i--)
359     if (SvIV (*av_fetch (overlay_av, i, 1)) == (long)this)
360       {
361         av_delete (overlay_av, i, G_DISCARD);
362         break;
363       }
364
365   for (; i < AvFILL (overlay_av); i++)
366     av_store (overlay_av, i, SvREFCNT_inc (*av_fetch (overlay_av, i + 1, 0)));
367
368   av_pop (overlay_av);
369
370   SvREFCNT_dec (overlay_av);
371   overlay_av = 0;
372
373   THIS->want_refresh = 1;
374 }
375
376 void overlay::swap ()
377 {
378   int ov_x = max (0, min (MOD (x, THIS->ncol), THIS->ncol - w));
379   int ov_y = max (0, min (MOD (y, THIS->nrow), THIS->nrow - h));
380
381   int ov_w = min (w, THIS->ncol - ov_x);
382   int ov_h = min (h, THIS->nrow - ov_y);
383
384   for (int y = ov_h; y--; )
385     {
386       text_t *t1 = text [y];
387       rend_t *r1 = rend [y];
388
389       text_t *t2 = ROW(y + ov_y + THIS->view_start).t + ov_x;
390       rend_t *r2 = ROW(y + ov_y + THIS->view_start).r + ov_x;
391
392       for (int x = ov_w; x--; )
393         {
394           text_t t = *t1; *t1++ = *t2; *t2++ = t;
395           rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, THIS->fontset [GET_STYLE (r)]->find_font (t));
396         }
397     }
398
399 }
400
401 void overlay::set (int x, int y, SV *text, SV *rend)
402 {
403   x += border;
404   y += border;
405
406   if (!IN_RANGE_EXC (y, 0, h - border))
407     return;
408
409   wchar_t *wtext = sv2wcs (text);
410
411   for (int col = min (wcslen (wtext), w - x - border); col--; )
412     this->text [y][x + col] = wtext [col];
413
414   free (wtext);
415
416   if (rend)
417     {
418       if (!SvROK (rend) || SvTYPE (SvRV (rend)) != SVt_PVAV)
419         croak ("rend must be arrayref");
420
421       AV *av = (AV *)SvRV (rend);
422
423       for (int col = min (AvFILL (av) + 1, w - x - border); col--; )
424         this->rend [y][x + col] = SvIV (*av_fetch (av, col, 1));
425     }
426
427   THIS->want_refresh = 1;
428 }
429
430
431 /////////////////////////////////////////////////////////////////////////////
432
433 struct rxvt_perl_interp rxvt_perl;
434
435 static PerlInterpreter *perl;
436
437 rxvt_perl_interp::~rxvt_perl_interp ()
438 {
439   if (perl)
440     {
441       perl_destruct (perl);
442       perl_free (perl);
443     }
444 }
445
446 void
447 rxvt_perl_interp::init (rxvt_term *term)
448 {
449   if (!perl)
450     {
451       rxvt_push_locale (""); // perl init destroys current locale
452
453       perl_environ = rxvt_environ;
454       swap (perl_environ, environ);
455
456       char *argv[] = {
457         "",
458         "-e"
459         "BEGIN {"
460         "   urxvt->bootstrap;"
461         "   unshift @INC, '" LIBDIR "';"
462         "}"
463         ""
464         "use urxvt;"
465       };
466
467       perl = perl_alloc ();
468       perl_construct (perl);
469
470       if (perl_parse (perl, xs_init, 2, argv, (char **)NULL)
471           || perl_run (perl))
472         {
473           rxvt_warn ("unable to initialize perl-interpreter, continuing without.\n");
474
475           perl_destruct (perl);
476           perl_free (perl);
477           perl = 0;
478         }
479
480       swap (perl_environ, environ);
481
482       rxvt_pop_locale ();
483     }
484
485   if (perl)
486     {
487       // runs outside of perls ENV
488       term->perl.self = (void *)newSVptr ((void *)term, "urxvt::term");
489       hv_store ((HV *)SvRV ((SV *)term->perl.self), "_overlay", 8, newRV_noinc ((SV *)newAV ()), 0);
490     }
491 }
492
493 static void
494 ungrab (rxvt_term *THIS)
495 {
496   if (THIS->perl.grabtime)
497     {
498       XUngrabKeyboard (THIS->dpy, THIS->perl.grabtime);
499       XUngrabPointer  (THIS->dpy, THIS->perl.grabtime);
500       THIS->perl.grabtime = 0;
501     }
502 }
503
504 bool
505 rxvt_perl_interp::invoke (rxvt_term *term, hook_type htype, ...)
506 {
507   if (!perl || !term->perl.self)
508     return false;
509
510   // pre-handling of some events
511   if (htype == HOOK_REFRESH_END)
512     {
513       AV *av = (AV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)term->perl.self), "_overlay", 8, 0));
514       
515       for (int i = 0; i <= AvFILL (av); i++)
516         ((overlay *)SvIV (*av_fetch (av, i, 0)))->swap ();
517     }
518
519   swap (perl_environ, environ);
520
521   bool event_consumed;
522
523   if (htype == HOOK_INIT || htype == HOOK_DESTROY // must be called always
524       || term->perl.should_invoke [htype])
525     try
526       {
527         dSP;
528         va_list ap;
529
530         va_start (ap, htype);
531
532         ENTER;
533         SAVETMPS;
534
535         PUSHMARK (SP);
536
537         XPUSHs (sv_2mortal (newSVterm (term)));
538         XPUSHs (sv_2mortal (newSViv (htype)));
539
540         for (;;) {
541           data_type dt = (data_type)va_arg (ap, int);
542
543           switch (dt)
544             {
545               case DT_INT:
546                 XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
547                 break;
548
549               case DT_LONG:
550                 XPUSHs (sv_2mortal (newSViv (va_arg (ap, long))));
551                 break;
552
553               case DT_STR:
554                 XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
555                 break;
556
557               case DT_STR_LEN:
558                 {
559                   char *str = va_arg (ap, char *);
560                   int len   = va_arg (ap, int);
561
562                   XPUSHs (sv_2mortal (newSVpvn (str, len)));
563                 }
564                 break;
565
566               case DT_WCS_LEN:
567                 {
568                   wchar_t *wstr = va_arg (ap, wchar_t *);
569                   int wlen      = va_arg (ap, int);
570
571                   XPUSHs (sv_2mortal (wcs2sv (wstr, wlen)));
572                 }
573                break;
574
575               case DT_LCS_LEN:
576                 {
577                   long *lstr = va_arg (ap, long *);
578                   int llen   = va_arg (ap, int);
579
580                   XPUSHs (sv_2mortal (newSVpvn ((char *)lstr, llen * sizeof (long))));
581                 }
582                break;
583
584               case DT_XEVENT:
585                 {
586                   XEvent *xe = va_arg (ap, XEvent *);
587                   HV *hv = newHV ();
588
589 #                 define set(name, sv) hv_store (hv, # name,  sizeof (# name) - 1, sv, 0)
590 #                 define setiv(name, val) hv_store (hv, # name,  sizeof (# name) - 1, newSViv (val), 0)
591 #                 define setuv(name, val) hv_store (hv, # name,  sizeof (# name) - 1, newSVuv (val), 0)
592 #                 undef set
593
594                   setiv (type,       xe->type);
595                   setiv (send_event, xe->xany.send_event);
596                   setiv (serial,     xe->xany.serial);
597
598                   switch (xe->type)
599                     {
600                       case KeyPress:
601                       case KeyRelease:
602                       case ButtonPress:
603                       case ButtonRelease:
604                       case MotionNotify:
605                         setuv (window,    xe->xmotion.window);
606                         setuv (root,      xe->xmotion.root);
607                         setuv (subwindow, xe->xmotion.subwindow);
608                         setuv (time,      xe->xmotion.time);
609                         setiv (x,         xe->xmotion.x);
610                         setiv (y,         xe->xmotion.y);
611                         setiv (row,       xe->xmotion.y / term->fheight + term->view_start);
612                         setiv (col,       xe->xmotion.x / term->fwidth);
613                         setiv (x_root,    xe->xmotion.x_root);
614                         setiv (y_root,    xe->xmotion.y_root);
615                         setuv (state,     xe->xmotion.state);
616
617                         switch (xe->type)
618                           {
619                             case KeyPress:
620                             case KeyRelease:
621                               setuv (keycode, xe->xkey.keycode);
622                               break;
623
624                             case ButtonPress:
625                             case ButtonRelease:
626                               setuv (button,  xe->xbutton.button);
627                               break;
628
629                             case MotionNotify:
630                               setiv (is_hint, xe->xmotion.is_hint);
631                               break;
632                           }
633
634                         break;
635
636                       case MapNotify:
637                       case UnmapNotify:
638                       case ConfigureNotify:
639                         setuv (event,  xe->xconfigure.event);
640                         setuv (window, xe->xconfigure.window);
641
642                         switch (xe->type)
643                           {
644                             case ConfigureNotify:
645                               setiv (x,      xe->xconfigure.x);
646                               setiv (y,      xe->xconfigure.y);
647                               setiv (width,  xe->xconfigure.width);
648                               setiv (height, xe->xconfigure.height);
649                               setuv (above,  xe->xconfigure.above);
650                               break;
651                           }
652
653                         break;
654
655                       case PropertyNotify:
656                         setuv (window,       xe->xproperty.window);
657                         setuv (atom,         xe->xproperty.atom);
658                         setuv (time,         xe->xproperty.time);
659                         setiv (state,        xe->xproperty.state);
660                         break;
661
662                       case ClientMessage:
663                         setuv (window,       xe->xclient.window);
664                         setuv (message_type, xe->xclient.message_type);
665                         setuv (format,       xe->xclient.format);
666                         setuv (l0,           xe->xclient.data.l[0]);
667                         setuv (l1,           xe->xclient.data.l[1]);
668                         setuv (l2,           xe->xclient.data.l[2]);
669                         setuv (l3,           xe->xclient.data.l[3]);
670                         setuv (l4,           xe->xclient.data.l[4]);
671                         break;
672                     }
673
674                   XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
675                 }
676                 break;
677
678               case DT_END:
679                 goto call;
680
681               default:
682                 rxvt_fatal ("FATAL: unable to pass data type %d\n", dt);
683             }
684         }
685
686       call:
687         va_end (ap);
688
689         PUTBACK;
690         int count = call_pv ("urxvt::invoke", G_ARRAY | G_EVAL);
691         SPAGAIN;
692
693         if (count)
694           {
695             SV *status = POPs;
696             count = SvTRUE (status);
697           }
698
699         PUTBACK;
700         FREETMPS;
701         LEAVE;
702
703         if (SvTRUE (ERRSV))
704           {
705             rxvt_warn ("perl hook %d evaluation error: %s", htype, SvPV_nolen (ERRSV));
706             ungrab (term); // better lose the grab than the session
707           }
708
709         event_consumed = !!count;
710       }
711     catch (...)
712       {
713         swap (perl_environ, environ);
714         throw;
715       }
716   else
717     event_consumed = false;
718
719   // post-handling of some events
720   if (htype == HOOK_REFRESH_BEGIN)
721     {
722       AV *av = (AV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)term->perl.self), "_overlay", 8, 0));
723       
724       for (int i = AvFILL (av); i >= 0; i--)
725         ((overlay *)SvIV (*av_fetch (av, i, 0)))->swap ();
726     }
727   else if (htype == HOOK_DESTROY)
728     {
729       clearSVptr ((SV *)term->perl.self);
730       SvREFCNT_dec ((SV *)term->perl.self);
731       
732       // don't allow further calls
733       term->perl.self = 0;
734     }
735
736   swap (perl_environ, environ);
737
738   return event_consumed;
739 }
740
741 /////////////////////////////////////////////////////////////////////////////
742
743 MODULE = urxvt             PACKAGE = urxvt
744
745 PROTOTYPES: ENABLE
746
747 BOOT:
748 {
749   sv_setsv (get_sv ("urxvt::LIBDIR",   1), newSVpvn (LIBDIR,   sizeof (LIBDIR)   - 1));
750   sv_setsv (get_sv ("urxvt::RESNAME",  1), newSVpvn (RESNAME,  sizeof (RESNAME)  - 1));
751   sv_setsv (get_sv ("urxvt::RESCLASS", 1), newSVpvn (RESCLASS, sizeof (RESCLASS) - 1));
752   sv_setsv (get_sv ("urxvt::RXVTNAME", 1), newSVpvn (RXVTNAME, sizeof (RXVTNAME) - 1));
753
754   AV *hookname = get_av ("urxvt::HOOKNAME", 1);
755 # define def(sym) av_store (hookname, HOOK_ ## sym, newSVpv (# sym, 0));
756 # include "hookinc.h"
757 # undef def
758
759   HV *option = get_hv ("urxvt::OPTION", 1);
760 # define def(name,val) hv_store (option, # name, sizeof (# name) - 1, newSVuv (Opt_ ## name), 0);
761 # define nodef(name)
762 # include "optinc.h"
763 # undef nodef
764 # undef def
765
766   HV *stash = gv_stashpv ("urxvt", 1);
767   static const struct {
768     const char *name;
769     IV iv;
770   } *civ, const_iv[] = {
771 #   define const_iv(name) { # name, (IV)name }
772     const_iv (DEFAULT_RSTYLE),
773     const_iv (OVERLAY_RSTYLE),
774     const_iv (RS_Bold),
775     const_iv (RS_Italic),
776     const_iv (RS_Blink),
777     const_iv (RS_RVid),
778     const_iv (RS_Uline),
779
780     const_iv (CurrentTime),
781     const_iv (ShiftMask),
782     const_iv (LockMask),
783     const_iv (ControlMask),
784     const_iv (Mod1Mask),
785     const_iv (Mod2Mask),
786     const_iv (Mod3Mask),
787     const_iv (Mod4Mask),
788     const_iv (Mod5Mask),
789     const_iv (Button1Mask),
790     const_iv (Button2Mask),
791     const_iv (Button3Mask),
792     const_iv (Button4Mask),
793     const_iv (Button5Mask),
794     const_iv (AnyModifier),
795
796     const_iv (EVENT_NONE),
797     const_iv (EVENT_READ),
798     const_iv (EVENT_WRITE),
799
800     const_iv (NoEventMask),
801     const_iv (KeyPressMask),
802     const_iv (KeyReleaseMask),
803     const_iv (ButtonPressMask),
804     const_iv (ButtonReleaseMask),
805     const_iv (EnterWindowMask),
806     const_iv (LeaveWindowMask),
807     const_iv (PointerMotionMask),
808     const_iv (PointerMotionHintMask),
809     const_iv (Button1MotionMask),
810     const_iv (Button2MotionMask),
811     const_iv (Button3MotionMask),
812     const_iv (Button4MotionMask),
813     const_iv (Button5MotionMask),
814     const_iv (ButtonMotionMask),
815     const_iv (KeymapStateMask),
816     const_iv (ExposureMask),
817     const_iv (VisibilityChangeMask),
818     const_iv (StructureNotifyMask),
819     const_iv (ResizeRedirectMask),
820     const_iv (SubstructureNotifyMask),
821     const_iv (SubstructureRedirectMask),
822     const_iv (FocusChangeMask),
823     const_iv (PropertyChangeMask),
824     const_iv (ColormapChangeMask),
825     const_iv (OwnerGrabButtonMask),
826
827     const_iv (KeyPress),
828     const_iv (KeyRelease),
829     const_iv (ButtonPress),
830     const_iv (ButtonRelease),
831     const_iv (MotionNotify),
832     const_iv (EnterNotify),
833     const_iv (LeaveNotify),
834     const_iv (FocusIn),
835     const_iv (FocusOut),
836     const_iv (KeymapNotify),
837     const_iv (Expose),
838     const_iv (GraphicsExpose),
839     const_iv (NoExpose),
840     const_iv (VisibilityNotify),
841     const_iv (CreateNotify),
842     const_iv (DestroyNotify),
843     const_iv (UnmapNotify),
844     const_iv (MapNotify),
845     const_iv (MapRequest),
846     const_iv (ReparentNotify),
847     const_iv (ConfigureNotify),
848     const_iv (ConfigureRequest),
849     const_iv (GravityNotify),
850     const_iv (ResizeRequest),
851     const_iv (CirculateNotify),
852     const_iv (CirculateRequest),
853     const_iv (PropertyNotify),
854     const_iv (SelectionClear),
855     const_iv (SelectionRequest),
856     const_iv (SelectionNotify),
857     const_iv (ColormapNotify),
858     const_iv (ClientMessage),
859     const_iv (MappingNotify),
860 #   if ENABLE_XIM_ONTHESPOT
861     const_iv (XIMReverse),
862     const_iv (XIMUnderline),
863     const_iv (XIMHighlight),
864     const_iv (XIMPrimary),
865     const_iv (XIMSecondary),
866     const_iv (XIMTertiary),
867     const_iv (XIMVisibleToForward),
868     const_iv (XIMVisibleToBackword),
869     const_iv (XIMVisibleToCenter),
870 #   if 0
871     const_iv (XIMForwardChar),
872     const_iv (XIMBackwardChar),
873     const_iv (XIMForwardWord),
874     const_iv (XIMBackwardWord),
875     const_iv (XIMCaretUp),
876     const_iv (XIMCaretDown),
877     const_iv (XIMNextLine),
878     const_iv (XIMPreviousLine),
879     const_iv (XIMLineStart),
880     const_iv (XIMLineEnd),
881     const_iv (XIMAbsolutePosition),
882     const_iv (XIMDontChange),
883 #   endif
884 #   endif
885   };
886
887   for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
888     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
889 }
890
891 void
892 warn (const char *msg)
893         CODE:
894         rxvt_warn ("%s", msg);
895
896 void
897 fatal (const char *msg)
898         CODE:
899         rxvt_fatal ("%s", msg);
900
901 void
902 _exit (int status)
903
904 NV
905 NOW ()
906         CODE:
907         RETVAL = NOW;
908         OUTPUT:
909         RETVAL
910
911 int
912 GET_BASEFG (int rend)
913         CODE:
914         RETVAL = GET_BASEFG (rend);
915         OUTPUT:
916         RETVAL
917
918 int
919 GET_BASEBG (int rend)
920         CODE:
921         RETVAL = GET_BASEBG (rend);
922         OUTPUT:
923         RETVAL
924
925 int
926 SET_FGCOLOR (int rend, int new_color)
927         CODE:
928         RETVAL = SET_FGCOLOR (rend, clamp (new_color, 0, TOTAL_COLORS - 1));
929         OUTPUT:
930         RETVAL
931
932 int
933 SET_BGCOLOR (int rend, int new_color)
934         CODE:
935         RETVAL = SET_BGCOLOR (rend, clamp (new_color, 0, TOTAL_COLORS - 1));
936         OUTPUT:
937         RETVAL
938
939 int
940 GET_CUSTOM (int rend)
941         CODE:
942         RETVAL = (rend && RS_customMask) >> RS_customShift;
943         OUTPUT:
944         RETVAL
945
946 int
947 SET_CUSTOM (int rend, int new_value)
948         CODE:
949 {
950         if (!IN_RANGE_EXC (new_value, 0, RS_customCount))
951           croak ("custom value out of range, must be 0..%d", RS_customCount - 1);
952
953         RETVAL = (rend & ~RS_customMask)
954                | ((new_value << RS_customShift) & RS_customMask);
955 }
956         OUTPUT:
957         RETVAL
958
959 void
960 termlist ()
961         PPCODE:
962 {
963         EXTEND (SP, rxvt_term::termlist.size ());
964
965         for (rxvt_term **t = rxvt_term::termlist.begin (); t < rxvt_term::termlist.end (); t++)
966           if ((*t)->perl.self)
967             PUSHs (sv_2mortal (newSVterm (*t)));
968 }
969
970 MODULE = urxvt             PACKAGE = urxvt::term
971
972 SV *
973 _new (AV *env, AV *arg)
974         CODE:
975 {
976         rxvt_term *term = new rxvt_term;
977
978         stringvec *argv = new stringvec;
979         stringvec *envv = new stringvec;
980
981         for (int i = 0; i <= AvFILL (arg); i++)
982           argv->push_back (strdup (SvPVbyte_nolen (*av_fetch (arg, i, 1))));
983
984         for (int i = AvFILL (env) + 1; i--; )
985           envv->push_back (strdup (SvPVbyte_nolen (*av_fetch (env, i, 1))));
986
987         envv->push_back (0);
988
989         bool success;
990
991         try
992           {
993             success = term->init (argv, envv);
994           }
995         catch (const class rxvt_failure_exception &e)
996           {
997             success = false;
998           }
999
1000         if (!success)
1001           {
1002             term->destroy ();
1003             croak ("error while initializing new terminal instance");
1004           }
1005
1006         RETVAL = term && term->perl.self
1007                  ? newSVterm (term) : &PL_sv_undef;
1008 }
1009         OUTPUT:
1010         RETVAL
1011
1012 void
1013 rxvt_term::destroy ()
1014
1015 void
1016 rxvt_term::set_should_invoke (int htype, int inc)
1017         CODE:
1018         THIS->perl.should_invoke [htype] += inc;
1019
1020 void
1021 rxvt_term::grab_button (int button, U32 modifiers, Window window = THIS->vt)
1022         CODE:
1023         XGrabButton (THIS->dpy, button, modifiers, window, 1,
1024                      ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
1025                      GrabModeSync, GrabModeSync, None, GRAB_CURSOR);
1026
1027 void
1028 rxvt_term::ungrab_button (int button, U32 modifiers, Window window = THIS->vt)
1029         CODE:
1030         XUngrabButton (THIS->dpy, button, modifiers, window);
1031
1032 #if 0
1033
1034 void
1035 XGrabKey (rxvt_term *THIS, int keycode, U32 modifiers, Window window = THIS->vt)
1036         C_ARGS:
1037         THIS->dpy, keycode, modifiers, window, 1,
1038         GrabModeSync, GrabModeSync
1039
1040 void
1041 XUngrabKey (rxvt_term *THIS, int keycode, U32 modifiers, Window window = THIS->vt)
1042         C_ARGS: THIS->dpy, keycode, modifiers, window
1043
1044 #endif
1045
1046 bool
1047 rxvt_term::grab (Time eventtime, int sync = 0)
1048         CODE:
1049 {
1050         int mode = sync ? GrabModeSync : GrabModeAsync;
1051
1052         THIS->perl.grabtime = 0;
1053
1054         if (!XGrabPointer (THIS->dpy, THIS->vt, 0,
1055                            ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
1056                            mode, mode, None, GRAB_CURSOR, eventtime))
1057           if (!XGrabKeyboard (THIS->dpy, THIS->vt, 0, mode, mode, eventtime))
1058             THIS->perl.grabtime = eventtime;
1059           else
1060             XUngrabPointer (THIS->dpy, eventtime);
1061
1062         RETVAL = !!THIS->perl.grabtime;
1063 }
1064         OUTPUT:
1065         RETVAL
1066
1067 void
1068 rxvt_term::allow_events_async ()
1069         CODE:
1070         XAllowEvents (THIS->dpy, AsyncBoth,      THIS->perl.grabtime);
1071
1072 void
1073 rxvt_term::allow_events_sync ()
1074         CODE:
1075         XAllowEvents (THIS->dpy, SyncBoth,       THIS->perl.grabtime);
1076
1077 void
1078 rxvt_term::allow_events_replay ()
1079         CODE:
1080         XAllowEvents (THIS->dpy, ReplayPointer,  THIS->perl.grabtime);
1081         XAllowEvents (THIS->dpy, ReplayKeyboard, THIS->perl.grabtime);
1082
1083 void
1084 rxvt_term::ungrab ()
1085         CODE:
1086         ungrab (THIS);
1087
1088 int
1089 rxvt_term::strwidth (SV *str)
1090         CODE:
1091 {
1092         wchar_t *wstr = sv2wcs (str);
1093
1094         rxvt_push_locale (THIS->locale);
1095         RETVAL = wcswidth (wstr, wcslen (wstr));
1096         rxvt_pop_locale ();
1097
1098         free (wstr);
1099 }
1100         OUTPUT:
1101         RETVAL
1102
1103 SV *
1104 rxvt_term::locale_encode (SV *str)
1105         CODE:
1106 {
1107         wchar_t *wstr = sv2wcs (str);
1108
1109         rxvt_push_locale (THIS->locale);
1110         char *mbstr = rxvt_wcstombs (wstr);
1111         rxvt_pop_locale ();
1112
1113         free (wstr);
1114
1115         RETVAL = newSVpv (mbstr, 0);
1116         free (mbstr);
1117 }
1118         OUTPUT:
1119         RETVAL
1120
1121 SV *
1122 rxvt_term::locale_decode (SV *octets)
1123         CODE:
1124 {
1125         STRLEN len;
1126         char *data = SvPVbyte (octets, len);
1127
1128         rxvt_push_locale (THIS->locale);
1129         wchar_t *wstr = rxvt_mbstowcs (data, len);
1130         rxvt_pop_locale ();
1131
1132         RETVAL = wcs2sv (wstr);
1133         free (wstr);
1134 }
1135         OUTPUT:
1136         RETVAL
1137
1138 #define TERM_OFFSET(sym) offsetof (TermWin_t, sym)
1139
1140 #define TERM_OFFSET_width      TERM_OFFSET(width)
1141 #define TERM_OFFSET_height     TERM_OFFSET(height)
1142 #define TERM_OFFSET_fwidth     TERM_OFFSET(fwidth)
1143 #define TERM_OFFSET_fheight    TERM_OFFSET(fheight)
1144 #define TERM_OFFSET_fbase      TERM_OFFSET(fbase)
1145 #define TERM_OFFSET_nrow       TERM_OFFSET(nrow)
1146 #define TERM_OFFSET_ncol       TERM_OFFSET(ncol)
1147 #define TERM_OFFSET_focus      TERM_OFFSET(focus)
1148 #define TERM_OFFSET_mapped     TERM_OFFSET(mapped)
1149 #define TERM_OFFSET_int_bwidth TERM_OFFSET(int_bwidth)
1150 #define TERM_OFFSET_ext_bwidth TERM_OFFSET(ext_bwidth)
1151 #define TERM_OFFSET_lineSpace  TERM_OFFSET(lineSpace)
1152 #define TERM_OFFSET_saveLines  TERM_OFFSET(saveLines)
1153 #define TERM_OFFSET_total_rows TERM_OFFSET(total_rows)
1154 #define TERM_OFFSET_top_row    TERM_OFFSET(top_row)
1155
1156 int
1157 rxvt_term::width ()
1158         ALIAS:
1159            width      = TERM_OFFSET_width
1160            height     = TERM_OFFSET_height
1161            fwidth     = TERM_OFFSET_fwidth
1162            fheight    = TERM_OFFSET_fheight
1163            fbase      = TERM_OFFSET_fbase
1164            nrow       = TERM_OFFSET_nrow
1165            ncol       = TERM_OFFSET_ncol
1166            focus      = TERM_OFFSET_focus
1167            mapped     = TERM_OFFSET_mapped
1168            int_bwidth = TERM_OFFSET_int_bwidth
1169            ext_bwidth = TERM_OFFSET_ext_bwidth
1170            lineSpace  = TERM_OFFSET_lineSpace
1171            saveLines  = TERM_OFFSET_saveLines
1172            total_rows = TERM_OFFSET_total_rows
1173            top_row    = TERM_OFFSET_top_row
1174         CODE:
1175         RETVAL = *(int *)((char *)THIS + ix);
1176         OUTPUT:
1177         RETVAL
1178
1179 unsigned int
1180 rxvt_term::ModLevel3Mask ()
1181         ALIAS:
1182            ModLevel3Mask  = 0
1183            ModMetaMask    = 1
1184            ModNumLockMask = 2
1185            current_screen = 3
1186            hidden_cursor  = 4
1187         CODE:
1188         switch (ix)
1189           {
1190             case 0: RETVAL = THIS->ModLevel3Mask;  break;
1191             case 1: RETVAL = THIS->ModMetaMask;    break;
1192             case 2: RETVAL = THIS->ModNumLockMask; break;
1193             case 3: RETVAL = THIS->current_screen; break;
1194             case 4: RETVAL = THIS->hidden_cursor;  break;
1195           }
1196         OUTPUT:
1197         RETVAL
1198
1199 char *
1200 rxvt_term::display_id ()
1201         ALIAS:
1202            display_id = 0
1203            locale     = 1
1204         CODE:
1205         switch (ix)
1206           {
1207             case 0: RETVAL = THIS->display->id; break;
1208             case 1: RETVAL = THIS->locale;      break;
1209           }
1210         OUTPUT:
1211         RETVAL
1212
1213 SV *
1214 rxvt_term::_env ()
1215         CODE:
1216 {
1217         if (THIS->envv)
1218           {
1219             AV *av = newAV ();
1220
1221             for (char **i = THIS->envv->begin (); i != THIS->envv->end (); ++i)
1222               if (*i)
1223                 av_push (av, newSVpv (*i, 0));
1224
1225             RETVAL = newRV_noinc ((SV *)av);
1226           }
1227         else
1228           RETVAL = &PL_sv_undef;
1229 }
1230         OUTPUT:
1231         RETVAL
1232
1233 int
1234 rxvt_term::pty_ev_events (int events = EVENT_UNDEF)
1235         CODE:
1236         RETVAL = THIS->pty_ev.events;
1237         if (events != EVENT_UNDEF)
1238           THIS->pty_ev.set (events);
1239         OUTPUT:
1240         RETVAL
1241
1242 int
1243 rxvt_term::pty_fd ()
1244         CODE:
1245         RETVAL = THIS->pty->pty;
1246         OUTPUT:
1247         RETVAL
1248
1249 Window
1250 rxvt_term::parent ()
1251         CODE:
1252         RETVAL = THIS->parent [0];
1253         OUTPUT:
1254         RETVAL
1255
1256 Window
1257 rxvt_term::vt ()
1258         CODE:
1259         RETVAL = THIS->vt;
1260         OUTPUT:
1261         RETVAL
1262
1263 void
1264 rxvt_term::vt_emask_add (U32 emask)
1265         CODE:
1266         THIS->vt_emask_perl |= emask;
1267         THIS->vt_select_input ();
1268
1269 U32
1270 rxvt_term::rstyle (U32 new_rstyle = THIS->rstyle)
1271         CODE:
1272         RETVAL = THIS->rstyle;
1273         THIS->rstyle = new_rstyle;
1274         OUTPUT:
1275         RETVAL
1276
1277 int
1278 rxvt_term::view_start (int newval = 1)
1279         PROTOTYPE: $;$
1280         CODE:
1281 {
1282         RETVAL = THIS->view_start;
1283
1284         if (newval <= 0)
1285           THIS->scr_changeview (max (newval, THIS->top_row));
1286 }
1287         OUTPUT:
1288         RETVAL
1289
1290 void
1291 rxvt_term::focus_in ()
1292
1293 void
1294 rxvt_term::focus_out ()
1295
1296 void
1297 rxvt_term::key_press (unsigned int state, unsigned int keycode, Time time = CurrentTime)
1298         ALIAS:
1299            key_release = 1
1300         CODE:
1301 {
1302         XKeyEvent xkey;
1303
1304         memset (&xkey, 0, sizeof (xkey));
1305
1306         xkey.time      = time;
1307         xkey.state     = state;
1308         xkey.keycode   = keycode;
1309
1310         xkey.type      = ix ? KeyRelease : KeyPress;
1311         xkey.display   = THIS->dpy;
1312         xkey.window    = THIS->vt;
1313         xkey.root      = THIS->display->root;
1314         xkey.subwindow = THIS->vt;
1315
1316         if (ix)
1317           THIS->key_release (xkey);
1318         else
1319           THIS->key_press (xkey);
1320 }
1321
1322 void
1323 rxvt_term::want_refresh ()
1324         CODE:
1325         THIS->want_refresh = 1;
1326
1327 void
1328 rxvt_term::ROW_t (int row_number, SV *new_text = 0, int start_col = 0, int start_ofs = 0, int max_len = MAX_COLS)
1329         PPCODE:
1330 {
1331         if (!IN_RANGE_EXC (row_number, THIS->top_row, THIS->nrow))
1332           XSRETURN_EMPTY;
1333
1334         line_t &l = ROW(row_number);
1335
1336         if (GIMME_V != G_VOID)
1337           {
1338             wchar_t *wstr = rxvt_temp_buf<wchar_t> (THIS->ncol);
1339
1340             for (int col = 0; col < THIS->ncol; col++)
1341               wstr [col] = l.t [col];
1342
1343             XPUSHs (sv_2mortal (wcs2sv (wstr, THIS->ncol)));
1344           }
1345
1346         if (new_text)
1347           {
1348             wchar_t *wstr = sv2wcs (new_text);
1349
1350             int len = min (wcslen (wstr) - start_ofs, max_len);
1351
1352             if (start_col < 0 || start_col + len > THIS->ncol)
1353               {
1354                 free (wstr);
1355                 croak ("new_text extends beyond horizontal margins");
1356               }
1357
1358             for (int col = start_col; col < start_col + len; col++)
1359               {
1360                 l.t [col] = wstr [start_ofs + col - start_col];
1361                 l.r [col] = SET_FONT (l.r [col], THIS->fontset [GET_STYLE (l.r [col])]->find_font (l.t [col]));
1362               }
1363
1364             free (wstr);
1365           }
1366 }
1367
1368 void
1369 rxvt_term::ROW_r (int row_number, SV *new_rend = 0, int start_col = 0, int start_ofs = 0, int max_len = MAX_COLS)
1370         PPCODE:
1371 {
1372         if (!IN_RANGE_EXC (row_number, THIS->top_row, THIS->nrow))
1373           XSRETURN_EMPTY;
1374
1375         line_t &l = ROW(row_number);
1376
1377         if (GIMME_V != G_VOID)
1378           {
1379             AV *av = newAV ();
1380
1381             av_extend (av, THIS->ncol - 1);
1382             for (int col = 0; col < THIS->ncol; col++)
1383               av_store (av, col, newSViv (l.r [col]));
1384
1385             XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
1386           }
1387
1388         if (new_rend)
1389           {
1390             if (!SvROK (new_rend) || SvTYPE (SvRV (new_rend)) != SVt_PVAV)
1391               croak ("new_rend must be arrayref");
1392
1393             AV *av = (AV *)SvRV (new_rend);
1394             int len = min (AvFILL (av) + 1 - start_ofs, max_len);
1395
1396             if (start_col < 0 || start_col + len > THIS->ncol)
1397               croak ("new_rend array extends beyond horizontal margins");
1398
1399             for (int col = start_col; col < start_col + len; col++)
1400               {
1401                 rend_t r = SvIV (*av_fetch (av, start_ofs + col - start_col, 1)) & ~RS_fontMask;
1402
1403                 l.r [col] = SET_FONT (r, THIS->fontset [GET_STYLE (r)]->find_font (l.t [col]));
1404               }
1405           }
1406 }
1407
1408 int
1409 rxvt_term::ROW_l (int row_number, int new_length = -1)
1410         CODE:
1411 {
1412         if (!IN_RANGE_EXC (row_number, THIS->top_row, THIS->nrow))
1413           XSRETURN_EMPTY;
1414
1415         line_t &l = ROW(row_number);
1416         RETVAL = l.l;
1417
1418         if (new_length >= 0)
1419           l.l = new_length;
1420 }
1421         OUTPUT:
1422         RETVAL
1423
1424 bool
1425 rxvt_term::ROW_is_longer (int row_number, int new_is_longer = -1)
1426         CODE:
1427 {
1428         if (!IN_RANGE_EXC (row_number, THIS->top_row, THIS->nrow))
1429           XSRETURN_EMPTY;
1430
1431         line_t &l = ROW(row_number);
1432         RETVAL = l.is_longer ();
1433
1434         if (new_is_longer >= 0)
1435           l.is_longer (new_is_longer);
1436 }
1437         OUTPUT:
1438         RETVAL
1439
1440 SV *
1441 rxvt_term::special_encode (SV *string)
1442         CODE:
1443 {
1444         wchar_t *wstr = sv2wcs (string);
1445         int wlen = wcslen (wstr);
1446         wchar_t *rstr = rxvt_temp_buf<wchar_t> (wlen * 2); // cannot become longer
1447
1448         rxvt_push_locale (THIS->locale);
1449
1450         wchar_t *r = rstr;
1451         for (wchar_t *s = wstr; *s; s++)
1452           {
1453             int w = WCWIDTH (*s);
1454
1455             if (w == 0)
1456               {
1457                 if (r == rstr)
1458                   croak ("leading combining character unencodable");
1459
1460                 unicode_t n = rxvt_compose (r[-1], *s);
1461                 if (n == NOCHAR)
1462                   n = rxvt_composite.compose (r[-1], *s);
1463
1464                 r[-1] = n;
1465               }
1466 #if !UNICODE_3
1467             else if (*s >= 0x10000)
1468               *r++ = rxvt_composite.compose (*s);
1469 #endif
1470             else
1471               *r++ = *s;
1472
1473             // the *2 above only allows wcwidth <= 2
1474             if (w > 1)
1475               *r++ = NOCHAR;
1476           }
1477
1478         rxvt_pop_locale ();
1479
1480         RETVAL = wcs2sv (rstr, r - rstr);
1481 }
1482         OUTPUT:
1483         RETVAL
1484
1485 SV *
1486 rxvt_term::special_decode (SV *text)
1487         CODE:
1488 {
1489         wchar_t *wstr = sv2wcs (text);
1490         int wlen = wcslen (wstr);
1491         int dlen = 0;
1492
1493         // find length
1494         for (wchar_t *s = wstr; *s; s++)
1495           if (*s == NOCHAR)
1496             ;
1497           else if (IS_COMPOSE (*s))
1498             dlen += rxvt_composite.expand (*s, 0);
1499           else
1500             dlen++;
1501
1502         wchar_t *rstr = rxvt_temp_buf<wchar_t> (dlen);
1503
1504         // decode
1505         wchar_t *r = rstr;
1506         for (wchar_t *s = wstr; *s; s++)
1507           if (*s == NOCHAR)
1508             ;
1509           else if (IS_COMPOSE (*s))
1510             r += rxvt_composite.expand (*s, r);
1511           else
1512             *r++ = *s;
1513
1514         RETVAL = wcs2sv (rstr, r - rstr);
1515 }
1516         OUTPUT:
1517         RETVAL
1518
1519 void
1520 rxvt_term::_resource (char *name, int index, SV *newval = 0)
1521         PPCODE:
1522 {
1523         static const struct resval { const char *name; int value; } *rs, rslist [] = {
1524 #         define def(name) { # name, Rs_ ## name },
1525 #         define reserve(name,count)
1526 #         include "rsinc.h"
1527 #         undef def
1528 #         undef reserve
1529         };
1530
1531         rs = rslist + sizeof (rslist) / sizeof (rslist [0]);
1532
1533         do {
1534           if (rs-- == rslist)
1535             croak ("no such resource '%s', requested", name);
1536         } while (strcmp (name, rs->name));
1537
1538         index += rs->value;
1539
1540         if (!IN_RANGE_EXC (index, 0, NUM_RESOURCES))
1541           croak ("requested out-of-bound resource %s+%d,", name, index - rs->value);
1542
1543         if (GIMME_V != G_VOID)
1544           XPUSHs (THIS->rs [index] ? sv_2mortal (newSVpv (THIS->rs [index], 0)) : &PL_sv_undef);
1545
1546         if (newval)
1547           {
1548             if (SvOK (newval))
1549               {
1550                 char *str = strdup (SvPVbyte_nolen (newval));
1551                 THIS->rs [index] = str;
1552                 THIS->allocated.push_back (str);
1553               }
1554             else
1555               THIS->rs [index] = 0;
1556           }
1557 }
1558
1559 const char *
1560 rxvt_term::x_resource (const char *name)
1561
1562 bool
1563 rxvt_term::option (U32 optval, int set = -1)
1564         CODE:
1565 {
1566         RETVAL = THIS->options & optval;
1567
1568         if (set >= 0)
1569           {
1570             if (set)
1571               THIS->options |= optval;
1572             else
1573               THIS->options &= ~optval;
1574
1575             if (THIS->check_ev.is_active ()) // avoid doing this before START
1576               switch (optval)
1577                 {
1578                   case Opt_skipBuiltinGlyphs:
1579                     THIS->set_fonts ();
1580                     THIS->scr_remap_chars ();
1581                     THIS->scr_touch (true);
1582                     THIS->want_refresh = 1;
1583                     break;
1584
1585                   case Opt_cursorUnderline:
1586                     THIS->want_refresh = 1;
1587                     break;
1588
1589 #                  case Opt_scrollBar_floating:
1590 #                  case Opt_scrollBar_right:
1591 #                    THIS->resize_all_windows (THIS->width, THIS->height, 1);
1592 #                    break;
1593                 }
1594           }
1595 }
1596         OUTPUT:
1597         RETVAL
1598
1599 bool
1600 rxvt_term::parse_keysym (char *keysym, char *str)
1601         CODE:
1602         RETVAL = 0 < THIS->parse_keysym (keysym, str);
1603         THIS->keyboard->register_done ();
1604         OUTPUT:
1605         RETVAL
1606
1607 void
1608 rxvt_term::screen_cur (...)
1609         PROTOTYPE: $;$$
1610         ALIAS:
1611            screen_cur     = 0
1612            selection_beg  = 1
1613            selection_end  = 2
1614            selection_mark = 3
1615         PPCODE:
1616 {
1617         row_col_t &rc = ix == 0 ? THIS->screen.cur
1618                       : ix == 1 ? THIS->selection.beg
1619                       : ix == 2 ? THIS->selection.end
1620                       :           THIS->selection.mark;
1621
1622         if (GIMME_V != G_VOID)
1623           {
1624             EXTEND (SP, 2);
1625             PUSHs (sv_2mortal (newSViv (rc.row)));
1626             PUSHs (sv_2mortal (newSViv (rc.col)));
1627           }
1628
1629         if (items == 3)
1630           {
1631             rc.row = SvIV (ST (1));
1632             rc.col = SvIV (ST (2));
1633
1634             if (ix == 2)
1635               {
1636                 if (rc.col == 0)
1637                   {
1638                     // col == 0 means end of previous line
1639                     rc.row--;
1640                     rc.col = THIS->ncol;
1641                   }
1642                 else if (IN_RANGE_EXC (rc.row, THIS->top_row, THIS->nrow)
1643                          && rc.col > ROW(rc.row).l)
1644                   {
1645                     // col >= length means while line and add newline
1646                     rc.col = THIS->ncol;
1647                   }
1648               }
1649
1650             clamp_it (rc.col, 0, THIS->ncol);
1651             clamp_it (rc.row, THIS->top_row, THIS->nrow - 1);
1652
1653             if (ix)
1654               THIS->want_refresh = 1;
1655           }
1656 }
1657
1658 char
1659 rxvt_term::cur_charset ()
1660         CODE:
1661         RETVAL = THIS->charsets [THIS->screen.charset];
1662         OUTPUT:
1663         RETVAL
1664
1665 void
1666 rxvt_term::selection_clear ()
1667
1668 void
1669 rxvt_term::selection_make (Time eventtime, bool rect = false)
1670         CODE:
1671         THIS->selection.op = SELECTION_CONT;
1672         THIS->selection.rect = rect;
1673         THIS->selection_make (eventtime);
1674
1675 int
1676 rxvt_term::selection_grab (Time eventtime)
1677
1678 void
1679 rxvt_term::selection (SV *newtext = 0)
1680         PPCODE:
1681 {
1682         if (GIMME_V != G_VOID)
1683           XPUSHs (THIS->selection.text
1684                   ? sv_2mortal (wcs2sv (THIS->selection.text, THIS->selection.len))
1685                   : &PL_sv_undef);
1686
1687         if (newtext)
1688           {
1689             free (THIS->selection.text);
1690
1691             THIS->selection.text = sv2wcs (newtext);
1692             THIS->selection.len = wcslen (THIS->selection.text);
1693           }
1694 }
1695
1696 void
1697 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)
1698
1699 void
1700 rxvt_term::scr_xor_span (int beg_row, int beg_col, int end_row, int end_col, U32 rstyle = RS_RVid)
1701
1702 void
1703 rxvt_term::scr_bell ()
1704
1705 void
1706 rxvt_term::scr_change_screen (int screen)
1707
1708 void
1709 rxvt_term::scr_add_lines (SV *string)
1710         CODE:
1711 {
1712         wchar_t *wstr = sv2wcs (string);
1713         THIS->scr_add_lines (wstr, wcslen (wstr));
1714         free (wstr);
1715 }
1716
1717 void
1718 rxvt_term::tt_write (SV *octets)
1719         INIT:
1720           STRLEN len;
1721           char *str = SvPVbyte (octets, len);
1722         C_ARGS:
1723           str, len
1724
1725 void
1726 rxvt_term::cmd_parse (SV *octets)
1727         CODE:
1728 {
1729         STRLEN len;
1730         char *str = SvPVbyte (octets, len);
1731
1732         char *old_cmdbuf_ptr  = THIS->cmdbuf_ptr;
1733         char *old_cmdbuf_endp = THIS->cmdbuf_endp;
1734
1735         THIS->cmdbuf_ptr  = str;
1736         THIS->cmdbuf_endp = str + len;
1737
1738         rxvt_push_locale (THIS->locale);
1739         THIS->cmd_parse ();
1740         rxvt_pop_locale ();
1741
1742         THIS->cmdbuf_ptr  = old_cmdbuf_ptr;
1743         THIS->cmdbuf_endp = old_cmdbuf_endp;
1744 }
1745
1746 SV *
1747 rxvt_term::overlay (int x, int y, int w, int h, int rstyle = OVERLAY_RSTYLE, int border = 2)
1748         CODE:
1749 {
1750         overlay *o = new overlay (THIS, x, y, w, h, rstyle, border);
1751         RETVAL = newSVptr ((void *)o, "urxvt::overlay");
1752         o->self = (HV *)SvRV (RETVAL);
1753 }
1754         OUTPUT:
1755         RETVAL
1756
1757 #############################################################################
1758 # Various X Utility Functions
1759 #############################################################################
1760
1761 void
1762 rxvt_term::XListProperties (Window window)
1763         PPCODE:
1764 {
1765         int count;
1766         Atom *props = XListProperties (THIS->dpy, window, &count);
1767
1768         EXTEND (SP, count);
1769         while (count--)
1770           PUSHs (newSVuv ((U32)props [count]));
1771         
1772         XFree (props);
1773 }
1774
1775 void
1776 rxvt_term::XGetWindowProperty (Window window, Atom property)
1777         PPCODE:
1778 {
1779         Atom type;
1780         int format;
1781         unsigned long nitems;
1782         unsigned long bytes_after;
1783         unsigned char *prop;
1784
1785         XGetWindowProperty (THIS->dpy, window, property,
1786                             0, 1<<24, 0, AnyPropertyType,
1787                             &type, &format, &nitems, &bytes_after, &prop);
1788
1789         if (type != None)
1790           {
1791             int elemsize = format == 16 ? sizeof (short)
1792                          : format == 32 ? sizeof (long)
1793                          :                1;
1794
1795             EXTEND (SP, 3);
1796             PUSHs (newSVuv ((U32)type));
1797             PUSHs (newSViv (format));
1798             PUSHs (newSVpvn ((char *)prop, nitems * elemsize));
1799             XFree (prop);
1800           }
1801 }
1802
1803 void
1804 rxvt_term::XChangeWindowProperty (Window window, Atom property, Atom type, int format, SV *data)
1805         CODE:
1806 {
1807         STRLEN len;
1808         char *data_ = SvPVbyte (data, len);
1809
1810         int elemsize = format == 16 ? sizeof (short)
1811                      : format == 32 ? sizeof (long)
1812                      :                1;
1813
1814         XChangeProperty (THIS->dpy, window, property,
1815                          type, format, PropModeReplace,
1816                          (unsigned char *)data_, len / elemsize);
1817 }
1818
1819 Atom
1820 XInternAtom (rxvt_term *term, char *atom_name, int only_if_exists = FALSE)
1821         C_ARGS: term->dpy, atom_name, only_if_exists
1822
1823 char *
1824 XGetAtomName (rxvt_term *term, Atom atom)
1825         C_ARGS: term->dpy, atom
1826         CLEANUP:
1827         XFree (RETVAL);
1828
1829 void
1830 XDeleteProperty (rxvt_term *term, Window window, Atom property)
1831         C_ARGS: term->dpy, window, property
1832
1833 Window
1834 rxvt_term::DefaultRootWindow ()
1835         CODE:
1836         RETVAL = THIS->display->root;
1837         OUTPUT:
1838         RETVAL
1839
1840 #if 0
1841
1842 Window
1843 XCreateSimpleWindow (rxvt_term *term, Window parent, int x, int y, unsigned int width, unsigned int height)
1844         C_ARGS: term->dpy, (Window)parent,
1845                 x, y, width, height, 0,
1846                 term->pix_colors_focused[Color_border],
1847                 term->pix_colors_focused[Color_border]
1848
1849 #endif
1850
1851 void
1852 XReparentWindow (rxvt_term *term, Window window, Window parent, int x = 0, int y = 0)
1853         C_ARGS: term->dpy, window, parent, x, y
1854
1855 void
1856 XMapWindow (rxvt_term *term, Window window)
1857         C_ARGS: term->dpy, window
1858
1859 void
1860 XUnmapWindow (rxvt_term *term, Window window)
1861         C_ARGS: term->dpy, window
1862
1863 void
1864 XMoveResizeWindow (rxvt_term *term, Window window, int x, int y, unsigned int width, unsigned int height)
1865         C_ARGS: term->dpy, window, x, y, width, height
1866
1867 void
1868 rxvt_term::XChangeInput (Window window, U32 add_events, U32 del_events = 0)
1869         CODE:
1870 {
1871         XWindowAttributes attr;
1872         XGetWindowAttributes (THIS->dpy, window, &attr);
1873         XSelectInput (THIS->dpy, window, attr.your_event_mask | add_events & ~del_events);
1874 }
1875
1876 void
1877 rxvt_term::XTranslateCoordinates (Window src, Window dst, int x, int y)
1878         PPCODE:
1879 {
1880         int dx, dy;
1881         Window child;
1882
1883         if (XTranslateCoordinates (THIS->dpy, src, dst, x, y, &dx, &dy, &child))
1884           {
1885             EXTEND (SP, 3);
1886             PUSHs (newSViv (dx));
1887             PUSHs (newSViv (dy));
1888             PUSHs (newSVuv (child));
1889           }
1890 }
1891
1892 #############################################################################
1893 # urxvt::overlay
1894 #############################################################################
1895
1896 MODULE = urxvt             PACKAGE = urxvt::overlay
1897
1898 void
1899 overlay::set (int x, int y, SV *text, SV *rend = 0)
1900
1901 void
1902 overlay::show ()
1903
1904 void
1905 overlay::hide ()
1906
1907 void
1908 overlay::DESTROY ()
1909
1910 #############################################################################
1911 # urxvt::watcher
1912 #############################################################################
1913
1914 MODULE = urxvt             PACKAGE = urxvt::watcher
1915
1916 CHAINED
1917 perl_watcher::cb (SV *cb)
1918         CODE:
1919         THIS->cb (cb);
1920         OUTPUT:
1921         RETVAL
1922
1923 #############################################################################
1924 # urxvt::timer
1925 #############################################################################
1926
1927 MODULE = urxvt             PACKAGE = urxvt::timer
1928
1929 SV *
1930 timer::new ()
1931         CODE:
1932         timer *w =  new timer;
1933         w->start (NOW);
1934         RETVAL = newSVptr ((void *)(perl_watcher *)w, "urxvt::timer");
1935         w->self = (HV *)SvRV (RETVAL);
1936         OUTPUT:
1937         RETVAL
1938
1939 NV
1940 timer::at ()
1941         CODE:
1942         RETVAL = THIS->at;
1943         OUTPUT:
1944         RETVAL
1945
1946 CHAINED
1947 timer::interval (NV interval)
1948         CODE:
1949         THIS->interval = interval;
1950         OUTPUT:
1951         RETVAL
1952
1953 CHAINED
1954 timer::set (NV tstamp)
1955         CODE:
1956         THIS->set (tstamp);
1957         OUTPUT:
1958         RETVAL
1959
1960 CHAINED
1961 timer::start (NV tstamp = THIS->at)
1962         CODE:
1963         THIS->start (tstamp);
1964         OUTPUT:
1965         RETVAL
1966
1967 CHAINED
1968 timer::after (NV delay)
1969         CODE:
1970         THIS->start (NOW + delay);
1971         OUTPUT:
1972         RETVAL
1973
1974 CHAINED
1975 timer::stop ()
1976         CODE:
1977         THIS->stop ();
1978         OUTPUT:
1979         RETVAL
1980
1981 void
1982 timer::DESTROY ()
1983
1984 #############################################################################
1985 # urxvt::iow
1986 #############################################################################
1987
1988 MODULE = urxvt             PACKAGE = urxvt::iow
1989
1990 SV *
1991 iow::new ()
1992         CODE:
1993         iow *w =  new iow;
1994         RETVAL = newSVptr ((void *)(perl_watcher *)w, "urxvt::iow");
1995         w->self = (HV *)SvRV (RETVAL);
1996         OUTPUT:
1997         RETVAL
1998
1999 CHAINED
2000 iow::fd (int fd)
2001         CODE:
2002         THIS->fd = fd;
2003         OUTPUT:
2004         RETVAL
2005
2006 CHAINED
2007 iow::events (short events)
2008         CODE:
2009         THIS->events = events;
2010         OUTPUT:
2011         RETVAL
2012
2013 CHAINED
2014 iow::start ()
2015         CODE:
2016         THIS->start ();
2017         OUTPUT:
2018         RETVAL
2019
2020 CHAINED
2021 iow::stop ()
2022         CODE:
2023         THIS->stop ();
2024         OUTPUT:
2025         RETVAL
2026
2027 void
2028 iow::DESTROY ()
2029
2030 #############################################################################
2031 # urxvt::iw
2032 #############################################################################
2033
2034 MODULE = urxvt             PACKAGE = urxvt::iw
2035
2036 SV *
2037 iw::new ()
2038         CODE:
2039         iw *w =  new iw;
2040         RETVAL = newSVptr ((void *)(perl_watcher *)w, "urxvt::iw");
2041         w->self = (HV *)SvRV (RETVAL);
2042         OUTPUT:
2043         RETVAL
2044
2045 CHAINED
2046 iw::start ()
2047         CODE:
2048         THIS->start ();
2049         OUTPUT:
2050         RETVAL
2051
2052 CHAINED
2053 iw::stop ()
2054         CODE:
2055         THIS->stop ();
2056         OUTPUT:
2057         RETVAL
2058
2059 void
2060 iw::DESTROY ()
2061
2062 #############################################################################
2063 # urxvt::pw
2064 #############################################################################
2065
2066 MODULE = urxvt             PACKAGE = urxvt::pw
2067
2068 SV *
2069 pw::new ()
2070         CODE:
2071         pw *w =  new pw;
2072         RETVAL = newSVptr ((void *)(perl_watcher *)w, "urxvt::pw");
2073         w->self = (HV *)SvRV (RETVAL);
2074         OUTPUT:
2075         RETVAL
2076
2077 CHAINED
2078 pw::start (int pid)
2079         CODE:
2080         THIS->start (pid);
2081         OUTPUT:
2082         RETVAL
2083
2084 CHAINED
2085 pw::stop ()
2086         CODE:
2087         THIS->stop ();
2088         OUTPUT:
2089         RETVAL
2090
2091 void
2092 pw::DESTROY ()
2093
2094