summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rxvtperl.xs2530
1 files changed, 2530 insertions, 0 deletions
diff --git a/src/rxvtperl.xs b/src/rxvtperl.xs
new file mode 100644
index 0000000..963a445
--- /dev/null
+++ b/src/rxvtperl.xs
@@ -0,0 +1,2530 @@
+/*----------------------------------------------------------------------*
+ * File: rxvtperl.xs
+ *----------------------------------------------------------------------*
+ *
+ * All portions of code are copyright by their respective author/s.
+ * Copyright (c) 2005-2014 Marc Lehmann <schmorp@schmorp.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------*/
+
+#define line_t perl_line_t
+#include <EXTERN.h>
+#include <perl.h>
+#include <XSUB.h>
+#undef line_t
+#undef bool // perl defines it's own bool type, except with g++... what a trap
+
+#include "../config.h"
+
+#include <stddef.h>
+#include <stdarg.h>
+
+#include "unistd.h"
+
+#include "ev_cpp.h"
+#include "rxvt.h"
+#include "keyboard.h"
+#include "rxvtutil.h"
+#include "rxvtperl.h"
+
+#include "perlxsi.c"
+
+#define GRAB_CURSOR THIS->scrollBar.leftptr_cursor
+
+#undef LINENO
+#define LINENO(n) MOD (THIS->term_start + int(n), THIS->total_rows)
+#undef ROW
+#define ROW(n) THIS->row_buf [LINENO (n)]
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef char * octet_string;
+typedef char * utf8_string;
+
+typedef int render_repeat_mode;
+
+#if HAVE_PIXBUF
+typedef GdkPixbuf * urxvt__pixbuf;
+#endif
+#if HAVE_IMG
+typedef rxvt_img * urxvt__img;
+typedef rxvt_img::nv rxvt_img__nv;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static rgba
+parse_rgba (SV *sv, rxvt_screen *s = 0)
+{
+ rgba c;
+
+ if (SvROK (sv))
+ {
+ AV *av = (AV *)SvRV (sv);
+
+ if (SvTYPE ((SV *)av) != SVt_PVAV)
+ croak ("colour must be either a colour string, or an array,");
+
+ int len = av_len (av) + 1;
+
+ if (len != 1 && len != 3 && len != 4)
+ croak ("component colour array must have 1, 3 or 4 components,");
+
+ c.a = rgba::MAX_CC;
+
+ c.r = c.g = c.b = float_to_component (SvIV (*av_fetch (av, 0, 0)));
+
+ if (len >= 3)
+ {
+ c.g = float_to_component (SvIV (*av_fetch (av, 1, 0)));
+ c.b = float_to_component (SvIV (*av_fetch (av, 2, 0)));
+
+ if (len >= 4)
+ c.a = float_to_component (SvIV (*av_fetch (av, 3, 0)));
+ }
+ }
+ else if (s)
+ {
+ rxvt_color rc;
+ rc.set (s, SvPVbyte_nolen (sv));
+ rc.get (c);
+ }
+ else
+ croak ("unable to parse colour,");
+
+ return c;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+#endif
+
+static wchar_t *
+sv2wcs (SV *sv)
+{
+ STRLEN len;
+ char *str = SvPVutf8 (sv, len);
+ return rxvt_utf8towcs (str, len);
+}
+
+static SV *
+wcs2sv (wchar_t *wstr, int len = -1)
+{
+ char *str = rxvt_wcstoutf8 (wstr, len);
+
+ SV *sv = newSVpv (str, 0);
+ SvUTF8_on (sv);
+ free (str);
+
+ return sv;
+}
+
+static SV *
+newSVptr (void *ptr, const char *klass)
+{
+ HV *hv = newHV ();
+ sv_magic ((SV *)hv, 0, PERL_MAGIC_ext, (char *)ptr, 0);
+ return sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1));
+}
+
+static void
+clearSVptr (SV *sv)
+{
+ if (SvROK (sv))
+ sv = SvRV (sv);
+
+ hv_clear ((HV *)sv);
+ sv_unmagic (sv, PERL_MAGIC_ext);
+}
+
+static long
+SvPTR (SV *sv, const char *klass)
+{
+ if (!sv_derived_from (sv, klass))
+ croak ("object of type %s expected", klass);
+
+ MAGIC *mg = mg_find (SvRV (sv), PERL_MAGIC_ext);
+
+ if (!mg)
+ croak ("perl code used %s object, but C++ object is already destroyed, caught", klass);
+
+ return (long)mg->mg_ptr;
+}
+
+#define newSVterm(term) SvREFCNT_inc ((SV *)(term)->perl.self)
+#define SvTERM(sv) (rxvt_term *)SvPTR ((sv), "urxvt::term")
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define SvOVERLAY(sv) (overlay *)SvPTR (sv, "urxvt::overlay")
+
+class overlay : overlay_base
+{
+ rxvt_term *THIS;
+ AV *overlay_av;
+ int border;
+
+public:
+ HV *self;
+
+ overlay (rxvt_term *THIS, int x_, int y_, int w_, int h_, rend_t rstyle, int border);
+ ~overlay ();
+
+ void show ();
+ void hide ();
+
+ void swap ();
+
+ void set (int x, int y, SV *str, SV *rend);
+};
+
+overlay::overlay (rxvt_term *THIS, int x_, int y_, int w_, int h_, rend_t rstyle, int border)
+: THIS(THIS), border(border == 2), overlay_av (0)
+{
+ x = x_;
+ y = y_;
+ w = w_;
+ h = h_;
+
+ if (w < 0) w = 0;
+ if (h < 0) h = 0;
+
+ if (border == 2)
+ {
+ w += 2;
+ h += 2;
+ }
+
+ text = new text_t *[h];
+ rend = new rend_t *[h];
+
+ for (int y = 0; y < h; y++)
+ {
+ text_t *tp = text[y] = new text_t[w];
+ rend_t *rp = rend[y] = new rend_t[w];
+
+ text_t t0, t1, t2;
+ rend_t r = rstyle;
+
+ if (border == 2)
+ {
+ if (y == 0)
+ t0 = 0x2554, t1 = 0x2550, t2 = 0x2557;
+ else if (y < h - 1)
+ t0 = 0x2551, t1 = 0x0020, t2 = 0x2551;
+ else
+ t0 = 0x255a, t1 = 0x2550, t2 = 0x255d;
+
+ *tp++ = t0;
+ *rp++ = r;
+
+ for (int x = w - 2; x-- > 0; )
+ {
+ *tp++ = t1;
+ *rp++ = r;
+ }
+
+ *tp = t2;
+ *rp = r;
+ }
+ else
+ for (int x = w; x-- > 0; )
+ {
+ *tp++ = 0x0020;
+ *rp++ = r;
+ }
+ }
+
+ show ();
+}
+
+overlay::~overlay ()
+{
+ hide ();
+
+ for (int y = h; y--; )
+ {
+ delete [] text[y];
+ delete [] rend[y];
+ }
+
+ delete [] text;
+ delete [] rend;
+}
+
+void
+overlay::show ()
+{
+ if (overlay_av)
+ return;
+
+ overlay_av = (AV *)SvREFCNT_inc (SvRV (
+ *hv_fetch ((HV *)SvRV ((SV *)THIS->perl.self), "_overlay", 8, 0)
+ ));
+ av_push (overlay_av, newSViv ((long)this));
+
+ THIS->want_refresh = 1;
+ THIS->refresh_check ();
+}
+
+void
+overlay::hide ()
+{
+ if (!overlay_av)
+ return;
+
+ int i;
+
+ for (i = AvFILL (overlay_av); i >= 0; i--)
+ if (SvIV (*av_fetch (overlay_av, i, 1)) == (long)this)
+ break;
+
+ for (; i < AvFILL (overlay_av); i++)
+ av_store (overlay_av, i, SvREFCNT_inc (*av_fetch (overlay_av, i + 1, 0)));
+
+ SvREFCNT_dec (av_pop (overlay_av));
+
+ SvREFCNT_dec (overlay_av);
+ overlay_av = 0;
+
+ THIS->want_refresh = 1;
+ THIS->refresh_check ();
+}
+
+void overlay::swap ()
+{
+ int ov_x = max (0, min (MOD (x, THIS->ncol), THIS->ncol - w));
+ int ov_y = max (0, min (MOD (y, THIS->nrow), THIS->nrow - h));
+
+ int ov_w = min (w, THIS->ncol - ov_x);
+ int ov_h = min (h, THIS->nrow - ov_y);
+
+ // hide cursor if it is within the overlay area
+ if (IN_RANGE_EXC (THIS->screen.cur.col - ov_x, 0, ov_w)
+ && IN_RANGE_EXC (THIS->screen.cur.row - ov_y, 0, ov_h))
+ THIS->screen.flags &= ~Screen_VisibleCursor;
+
+ for (int y = ov_h; y--; )
+ {
+ text_t *t1 = text [y];
+ rend_t *r1 = rend [y];
+
+ text_t *t2 = ROW(y + ov_y + THIS->view_start).t + ov_x;
+ rend_t *r2 = ROW(y + ov_y + THIS->view_start).r + ov_x;
+
+ for (int x = ov_w; x--; )
+ {
+ text_t t = *t1; *t1++ = *t2; *t2++ = t;
+ rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, THIS->fontset [GET_STYLE (r)]->find_font (t));
+ }
+ }
+
+}
+
+void overlay::set (int x, int y, SV *text, SV *rend)
+{
+ x += border;
+ y += border;
+
+ if (!IN_RANGE_EXC (y, 0, h - border))
+ return;
+
+ wchar_t *wtext = sv2wcs (text);
+
+ for (int col = min (wcslen (wtext), w - x - border); col--; )
+ this->text [y][x + col] = wtext [col];
+
+ free (wtext);
+
+ if (rend)
+ {
+ if (!SvROK (rend) || SvTYPE (SvRV (rend)) != SVt_PVAV)
+ croak ("rend must be arrayref");
+
+ AV *av = (AV *)SvRV (rend);
+
+ for (int col = min (AvFILL (av) + 1, w - x - border); col--; )
+ this->rend [y][x + col] = SvIV (*av_fetch (av, col, 1));
+ }
+
+ THIS->want_refresh = 1;
+ THIS->refresh_check ();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+#include "iom_perl.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+struct rxvt_perl_interp rxvt_perl;
+
+static PerlInterpreter *perl;
+
+rxvt_perl_interp::~rxvt_perl_interp ()
+{
+ if (perl)
+ {
+ perl_destruct (perl);
+ perl_free (perl);
+ PERL_SYS_TERM ();
+ }
+}
+
+void
+rxvt_perl_interp::init ()
+{
+ if (!perl)
+ {
+ rxvt_push_locale (""); // perl init destroys current locale
+
+ {
+ perl_environ = rxvt_environ;
+ localise_env set_environ (perl_environ);
+
+ char *args[] = {
+ "",
+ "-e"
+ "BEGIN {"
+ " urxvt->bootstrap;"
+ " unshift @INC, '" LIBDIR "';"
+ "}"
+ ""
+ "use urxvt;",
+ 0
+ };
+ int argc = ecb_array_length (args) - 1;
+ char **argv = args;
+
+ PERL_SYS_INIT3 (&argc, &argv, &environ);
+ perl = perl_alloc ();
+ perl_construct (perl);
+
+ if (perl_parse (perl, xs_init, argc, argv, (char **)NULL)
+ || perl_run (perl))
+ {
+ rxvt_warn ("unable to initialize perl-interpreter, continuing without.\n");
+
+ perl_destruct (perl);
+ perl_free (perl);
+ perl = 0;
+ }
+ }
+
+ rxvt_pop_locale ();
+ }
+}
+
+void
+rxvt_perl_interp::init (rxvt_term *term)
+{
+ init ();
+
+ if (perl && !term->perl.self)
+ {
+ // runs outside of perls ENV
+ term->perl.self = (void *)newSVptr ((void *)term, "urxvt::term");
+ hv_store ((HV *)SvRV ((SV *)term->perl.self), "_overlay", 8, newRV_noinc ((SV *)newAV ()), 0);
+ hv_store ((HV *)SvRV ((SV *)term->perl.self), "_selection", 10, newRV_noinc ((SV *)newAV ()), 0);
+ }
+}
+
+void
+rxvt_perl_interp::eval (const char *str)
+{
+ eval_pv (str, 1);
+}
+
+void
+rxvt_perl_interp::usage (rxvt_term *term, int type)
+{
+ localise_env set_environ (perl_environ);
+
+ ENTER;
+ SAVETMPS;
+
+ dSP;
+ PUSHMARK (SP);
+ EXTEND (SP, 2);
+ PUSHs (sv_2mortal (newSVterm (term)));
+ PUSHs (sv_2mortal (newSViv (type)));
+ PUTBACK;
+ call_pv ("urxvt::usage", G_VOID | G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+}
+
+uint8_t
+rxvt_perl_interp::parse_resource (rxvt_term *term, const char *name, bool arg, bool longopt, bool flag, const char *value)
+{
+ localise_env set_environ (perl_environ);
+
+ ENTER;
+ SAVETMPS;
+
+ dSP;
+ PUSHMARK (SP);
+ EXTEND (SP, 6);
+ PUSHs (sv_2mortal (newSVterm (term)));
+ PUSHs (sv_2mortal (newSVpv (name, 0)));
+ PUSHs (arg ? &PL_sv_yes : &PL_sv_no);
+ PUSHs (longopt ? &PL_sv_yes : &PL_sv_no);
+ PUSHs (flag ? &PL_sv_yes : &PL_sv_no);
+ PUSHs (value ? sv_2mortal (newSVpv (value, 0)) : &PL_sv_undef);
+ PUTBACK;
+ call_pv ("urxvt::parse_resource", G_SCALAR);
+ SPAGAIN;
+
+ uint8_t ret = POPi;
+
+ FREETMPS;
+ LEAVE;
+
+ return ret;
+}
+
+static void
+_keysym_resource_push (rxvt_term *term, const char *k, const char *v)
+{
+ unsigned int state;
+
+ if (term->parse_keysym (k, state) == -1)
+ return;
+
+ dSP;
+ XPUSHs (sv_2mortal (newSVpv (v, 0)));
+ PUTBACK;
+}
+
+static void
+_keysym_resources (rxvt_term *term)
+{
+ term->enumerate_keysym_resources (_keysym_resource_push);
+}
+
+static void
+ungrab (rxvt_term *THIS)
+{
+ if (THIS->perl.grabtime)
+ {
+ XUngrabKeyboard (THIS->dpy, THIS->perl.grabtime);
+ XUngrabPointer (THIS->dpy, THIS->perl.grabtime);
+ THIS->perl.grabtime = 0;
+ }
+}
+
+bool
+rxvt_perl_interp::invoke (rxvt_term *term, hook_type htype, ...)
+{
+ if (!perl || !term->perl.self)
+ return false;
+
+ localise_env set_environ (perl_environ);
+
+ // pre-handling of some events
+ if (htype == HOOK_REFRESH_END)
+ {
+ AV *av = (AV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)term->perl.self), "_overlay", 8, 0));
+
+ for (int i = 0; i <= AvFILL (av); i++)
+ ((overlay *)SvIV (*av_fetch (av, i, 0)))->swap ();
+ }
+ else if (htype == HOOK_DESTROY)
+ {
+ AV *av = (AV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)term->perl.self), "_selection", 10, 0));
+
+ for (int i = AvFILL (av); i >= 0; i--)
+ {
+ rxvt_selection *req = (rxvt_selection *)SvIV (*av_fetch (av, i, 0));
+ delete req;
+ }
+ }
+
+ bool event_consumed;
+
+ if (term->perl.should_invoke [htype])
+ {
+ dSP;
+ va_list ap;
+
+ va_start (ap, htype);
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK (SP);
+
+ EXTEND (SP, 2);
+ PUSHs (sv_2mortal (newSVterm (term)));
+ PUSHs (sv_2mortal (newSViv (htype)));
+
+ for (;;) {
+ data_type dt = (data_type)va_arg (ap, int);
+
+ switch (dt)
+ {
+ case DT_INT:
+ XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
+ break;
+
+ case DT_LONG:
+ XPUSHs (sv_2mortal (newSViv (va_arg (ap, long))));
+ break;
+
+ case DT_STR:
+ XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
+ break;
+
+ case DT_STR_LEN:
+ {
+ char *str = va_arg (ap, char *);
+ int len = va_arg (ap, int);
+
+ XPUSHs (sv_2mortal (newSVpvn (str, len)));
+ }
+ break;
+
+ case DT_WCS_LEN:
+ {
+ wchar_t *wstr = va_arg (ap, wchar_t *);
+ int wlen = va_arg (ap, int);
+
+ XPUSHs (sv_2mortal (wcs2sv (wstr, wlen)));
+ }
+ break;
+
+ case DT_LCS_LEN:
+ {
+ long *lstr = va_arg (ap, long *);
+ int llen = va_arg (ap, int);
+
+ XPUSHs (sv_2mortal (newSVpvn ((char *)lstr, llen * sizeof (long))));
+ }
+ break;
+
+ case DT_XEVENT:
+ {
+ XEvent *xe = va_arg (ap, XEvent *);
+ HV *hv = newHV ();
+
+# define set(name, sv) hv_store (hv, # name, sizeof (# name) - 1, sv, 0)
+# define setiv(name, val) hv_store (hv, # name, sizeof (# name) - 1, newSViv (val), 0)
+# define setuv(name, val) hv_store (hv, # name, sizeof (# name) - 1, newSVuv (val), 0)
+# undef set
+
+ setiv (type, xe->type);
+ setiv (send_event, xe->xany.send_event);
+ setiv (serial, xe->xany.serial);
+
+ switch (xe->type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ setuv (window, xe->xmotion.window);
+ setuv (root, xe->xmotion.root);
+ setuv (subwindow, xe->xmotion.subwindow);
+ setuv (time, xe->xmotion.time);
+ setiv (x, xe->xmotion.x);
+ setiv (y, xe->xmotion.y);
+ setiv (row, xe->xmotion.y / term->fheight + term->view_start);
+ setiv (col, xe->xmotion.x / term->fwidth);
+ setiv (x_root, xe->xmotion.x_root);
+ setiv (y_root, xe->xmotion.y_root);
+ setuv (state, xe->xmotion.state);
+
+ switch (xe->type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ setuv (keycode, xe->xkey.keycode);
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ setuv (button, xe->xbutton.button);
+ break;
+
+ case MotionNotify:
+ setiv (is_hint, xe->xmotion.is_hint);
+ break;
+ }
+
+ break;
+
+ case MapNotify:
+ case UnmapNotify:
+ case ConfigureNotify:
+ setuv (event, xe->xconfigure.event);
+ setuv (window, xe->xconfigure.window);
+
+ switch (xe->type)
+ {
+ case ConfigureNotify:
+ setiv (x, xe->xconfigure.x);
+ setiv (y, xe->xconfigure.y);
+ setiv (width, xe->xconfigure.width);
+ setiv (height, xe->xconfigure.height);
+ setuv (above, xe->xconfigure.above);
+ break;
+ }
+
+ break;
+
+ case PropertyNotify:
+ setuv (window, xe->xproperty.window);
+ setuv (atom, xe->xproperty.atom);
+ setuv (time, xe->xproperty.time);
+ setiv (state, xe->xproperty.state);
+ break;
+
+ case ClientMessage:
+ setuv (window, xe->xclient.window);
+ setuv (message_type, xe->xclient.message_type);
+ setuv (format, xe->xclient.format);
+ setuv (l0, xe->xclient.data.l[0]);
+ setuv (l1, xe->xclient.data.l[1]);
+ setuv (l2, xe->xclient.data.l[2]);
+ setuv (l3, xe->xclient.data.l[3]);
+ setuv (l4, xe->xclient.data.l[4]);
+ break;
+ }
+
+ XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
+ }
+ break;
+
+ case DT_END:
+ goto call;
+
+ default:
+ rxvt_fatal ("FATAL: unable to pass data type %d\n", dt);
+ }
+ }
+
+ call:
+ va_end (ap);
+
+ PUTBACK;
+ int count = call_pv ("urxvt::invoke", G_ARRAY | G_EVAL);
+ SPAGAIN;
+
+ if (count)
+ {
+ SV *status = POPs;
+ count = SvTRUE (status);
+ }
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+
+ if (SvTRUE (ERRSV))
+ {
+ rxvt_warn ("perl hook %d evaluation error: %s", htype, SvPVbyte_nolen (ERRSV));
+ ungrab (term); // better lose the grab than the session
+ }
+
+ event_consumed = !!count;
+ }
+ else
+ event_consumed = false;
+
+ // post-handling of some events
+ if (htype == HOOK_REFRESH_BEGIN)
+ {
+ AV *av = (AV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)term->perl.self), "_overlay", 8, 0));
+
+ for (int i = AvFILL (av); i >= 0; i--)
+ ((overlay *)SvIV (*av_fetch (av, i, 0)))->swap ();
+ }
+ else if (htype == HOOK_DESTROY)
+ {
+ clearSVptr ((SV *)term->perl.self);
+ SvREFCNT_dec ((SV *)term->perl.self);
+
+ // don't allow further calls
+ term->perl.self = 0;
+ }
+
+ return event_consumed;
+}
+
+void
+rxvt_perl_interp::selection_finish (rxvt_selection *sel, char *data, unsigned int len)
+{
+ localise_env set_environ (perl_environ);
+
+ ENTER;
+ SAVETMPS;
+
+ dSP;
+ XPUSHs (sv_2mortal (newSVpvn (data, len)));
+ PUTBACK;
+ call_sv ((SV *)sel->cb_sv, G_VOID | G_DISCARD | G_EVAL);
+
+ if (SvTRUE (ERRSV))
+ rxvt_warn ("perl selection callback evaluation error: %s", SvPVbyte_nolen (ERRSV));
+
+ FREETMPS;
+ LEAVE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+MODULE = urxvt PACKAGE = urxvt
+
+PROTOTYPES: ENABLE
+
+BOOT:
+{
+ sv_setsv (get_sv ("urxvt::LIBDIR", 1), newSVpvn (LIBDIR, sizeof (LIBDIR) - 1));
+ sv_setsv (get_sv ("urxvt::RESNAME", 1), newSVpvn (RESNAME, sizeof (RESNAME) - 1));
+ sv_setsv (get_sv ("urxvt::RESCLASS", 1), newSVpvn (RESCLASS, sizeof (RESCLASS) - 1));
+ sv_setsv (get_sv ("urxvt::RXVTNAME", 1), newSVpvn (RXVTNAME, sizeof (RXVTNAME) - 1));
+
+ AV *hookname = get_av ("urxvt::HOOKNAME", 1);
+# define def(sym) av_store (hookname, HOOK_ ## sym, newSVpv (# sym, 0));
+# include "hookinc.h"
+# undef def
+
+ HV *option = get_hv ("urxvt::OPTION", 1);
+# define def(name) hv_store (option, # name, sizeof (# name) - 1, newSVuv (Opt_ ## name), 0);
+# define nodef(name)
+# include "optinc.h"
+# undef nodef
+# undef def
+
+ HV *stash = gv_stashpv ("urxvt", 1);
+ static const struct {
+ const char *name;
+ IV iv;
+ } *civ, const_iv[] = {
+# define const_iv(name) { # name, (IV)name }
+ const_iv (HOOK_INIT),
+ const_iv (HOOK_DESTROY),
+ const_iv (HOOK_ACTION),
+
+ const_iv (NUM_RESOURCES),
+ const_iv (DEFAULT_RSTYLE),
+ const_iv (OVERLAY_RSTYLE),
+ const_iv (Color_Bits),
+ const_iv (RS_bgShift), const_iv (RS_bgMask),
+ const_iv (RS_fgShift), const_iv (RS_fgMask),
+ const_iv (RS_Careful),
+ const_iv (RS_fontCount),
+ const_iv (RS_fontShift),
+ const_iv (RS_fontMask),
+ const_iv (RS_baseattrMask),
+ const_iv (RS_attrMask),
+ const_iv (RS_redraw),
+ const_iv (RS_Sel),
+ const_iv (RS_Bold),
+ const_iv (RS_Italic),
+ const_iv (RS_Blink),
+ const_iv (RS_RVid),
+ const_iv (RS_Uline),
+
+ // TODO: should support all colour constants, create colorinc.h &c
+ const_iv (Color_fg),
+ const_iv (Color_bg),
+#if OFF_FOCUS_FADING
+ const_iv (Color_fade),
+#endif
+ const_iv (Color_pointer_fg),
+ const_iv (Color_pointer_bg),
+ const_iv (Color_border),
+ const_iv (NRS_COLORS),
+ const_iv (TOTAL_COLORS),
+
+ const_iv (CurrentTime),
+ const_iv (ShiftMask),
+ const_iv (LockMask),
+ const_iv (ControlMask),
+ const_iv (Mod1Mask),
+ const_iv (Mod2Mask),
+ const_iv (Mod3Mask),
+ const_iv (Mod4Mask),
+ const_iv (Mod5Mask),
+ const_iv (Button1Mask),
+ const_iv (Button2Mask),
+ const_iv (Button3Mask),
+ const_iv (Button4Mask),
+ const_iv (Button5Mask),
+ const_iv (AnyModifier),
+
+ const_iv (NoSymbol),
+ const_iv (GrabModeSync),
+ const_iv (GrabModeAsync),
+
+ const_iv (NoEventMask),
+ const_iv (KeyPressMask),
+ const_iv (KeyReleaseMask),
+ const_iv (ButtonPressMask),
+ const_iv (ButtonReleaseMask),
+ const_iv (EnterWindowMask),
+ const_iv (LeaveWindowMask),
+ const_iv (PointerMotionMask),
+ const_iv (PointerMotionHintMask),
+ const_iv (Button1MotionMask),
+ const_iv (Button2MotionMask),
+ const_iv (Button3MotionMask),
+ const_iv (Button4MotionMask),
+ const_iv (Button5MotionMask),
+ const_iv (ButtonMotionMask),
+ const_iv (KeymapStateMask),
+ const_iv (ExposureMask),
+ const_iv (VisibilityChangeMask),
+ const_iv (StructureNotifyMask),
+ const_iv (ResizeRedirectMask),
+ const_iv (SubstructureNotifyMask),
+ const_iv (SubstructureRedirectMask),
+ const_iv (FocusChangeMask),
+ const_iv (PropertyChangeMask),
+ const_iv (ColormapChangeMask),
+ const_iv (OwnerGrabButtonMask),
+
+ const_iv (KeyPress),
+ const_iv (KeyRelease),
+ const_iv (ButtonPress),
+ const_iv (ButtonRelease),
+ const_iv (MotionNotify),
+ const_iv (EnterNotify),
+ const_iv (LeaveNotify),
+ const_iv (FocusIn),
+ const_iv (FocusOut),
+ const_iv (KeymapNotify),
+ const_iv (Expose),
+ const_iv (GraphicsExpose),
+ const_iv (NoExpose),
+ const_iv (VisibilityNotify),
+ const_iv (CreateNotify),
+ const_iv (DestroyNotify),
+ const_iv (UnmapNotify),
+ const_iv (MapNotify),
+ const_iv (MapRequest),
+ const_iv (ReparentNotify),
+ const_iv (ConfigureNotify),
+ const_iv (ConfigureRequest),
+ const_iv (GravityNotify),
+ const_iv (ResizeRequest),
+ const_iv (CirculateNotify),
+ const_iv (CirculateRequest),
+ const_iv (PropertyNotify),
+ const_iv (SelectionClear),
+ const_iv (SelectionRequest),
+ const_iv (SelectionNotify),
+ const_iv (ColormapNotify),
+ const_iv (ClientMessage),
+ const_iv (MappingNotify),
+# if ENABLE_XIM_ONTHESPOT
+ const_iv (XIMReverse),
+ const_iv (XIMUnderline),
+ const_iv (XIMHighlight),
+ const_iv (XIMPrimary),
+ const_iv (XIMSecondary),
+ const_iv (XIMTertiary),
+ const_iv (XIMVisibleToForward),
+ const_iv (XIMVisibleToBackword),
+ const_iv (XIMVisibleToCenter),
+#if XRENDER
+ const_iv (PictStandardARGB32),
+ const_iv (PictStandardRGB24),
+ const_iv (PictStandardA8),
+ const_iv (PictStandardA4),
+ const_iv (PictStandardA1),
+ const_iv (RepeatNone),
+ const_iv (RepeatNormal),
+ const_iv (RepeatPad),
+ const_iv (RepeatReflect),
+ // all versions
+ const_iv (PictOpClear),
+ const_iv (PictOpSrc),
+ const_iv (PictOpDst),
+ const_iv (PictOpOver),
+ const_iv (PictOpOverReverse),
+ const_iv (PictOpIn),
+ const_iv (PictOpInReverse),
+ const_iv (PictOpOut),
+ const_iv (PictOpOutReverse),
+ const_iv (PictOpAtop),
+ const_iv (PictOpAtopReverse),
+ const_iv (PictOpXor),
+ const_iv (PictOpAdd),
+ const_iv (PictOpSaturate),
+ // 0.2+
+ const_iv (PictOpDisjointClear),
+ const_iv (PictOpDisjointSrc),
+ const_iv (PictOpDisjointDst),
+ const_iv (PictOpDisjointOver),
+ const_iv (PictOpDisjointOverReverse),
+ const_iv (PictOpDisjointIn),
+ const_iv (PictOpDisjointInReverse),
+ const_iv (PictOpDisjointOut),
+ const_iv (PictOpDisjointOutReverse),
+ const_iv (PictOpDisjointAtop),
+ const_iv (PictOpDisjointAtopReverse),
+ const_iv (PictOpDisjointXor),
+ const_iv (PictOpConjointClear),
+ const_iv (PictOpConjointSrc),
+ const_iv (PictOpConjointDst),
+ const_iv (PictOpConjointOver),
+ const_iv (PictOpConjointOverReverse),
+ const_iv (PictOpConjointIn),
+ const_iv (PictOpConjointInReverse),
+ const_iv (PictOpConjointOut),
+ const_iv (PictOpConjointOutReverse),
+ const_iv (PictOpConjointAtop),
+ const_iv (PictOpConjointAtopReverse),
+ const_iv (PictOpConjointXor),
+ // 0.11+
+ const_iv (PictOpMultiply),
+ const_iv (PictOpScreen),
+ const_iv (PictOpOverlay),
+ const_iv (PictOpDarken),
+ const_iv (PictOpLighten),
+ const_iv (PictOpColorDodge),
+ const_iv (PictOpColorBurn),
+ const_iv (PictOpHardLight),
+ const_iv (PictOpSoftLight),
+ const_iv (PictOpDifference),
+ const_iv (PictOpExclusion),
+ const_iv (PictOpHSLHue),
+ const_iv (PictOpHSLSaturation),
+ const_iv (PictOpHSLColor),
+ const_iv (PictOpHSLLuminosity),
+#endif
+# if 0
+ const_iv (XIMForwardChar),
+ const_iv (XIMBackwardChar),
+ const_iv (XIMForwardWord),
+ const_iv (XIMBackwardWord),
+ const_iv (XIMCaretUp),
+ const_iv (XIMCaretDown),
+ const_iv (XIMNextLine),
+ const_iv (XIMPreviousLine),
+ const_iv (XIMLineStart),
+ const_iv (XIMLineEnd),
+ const_iv (XIMAbsolutePosition),
+ const_iv (XIMDontChange),
+# endif
+# endif
+
+ /* DEC private modes */
+ const_iv (PrivMode_132),
+ const_iv (PrivMode_132OK),
+ const_iv (PrivMode_rVideo),
+ const_iv (PrivMode_relOrigin),
+ const_iv (PrivMode_Screen),
+ const_iv (PrivMode_Autowrap),
+ const_iv (PrivMode_aplCUR),
+ const_iv (PrivMode_aplKP),
+ const_iv (PrivMode_HaveBackSpace),
+ const_iv (PrivMode_BackSpace),
+ const_iv (PrivMode_ShiftKeys),
+ const_iv (PrivMode_VisibleCursor),
+ const_iv (PrivMode_MouseX10),
+ const_iv (PrivMode_MouseX11),
+ const_iv (PrivMode_scrollBar),
+ const_iv (PrivMode_TtyOutputInh),
+ const_iv (PrivMode_Keypress),
+ const_iv (PrivMode_smoothScroll),
+ const_iv (PrivMode_vt52),
+ const_iv (PrivMode_LFNL),
+ const_iv (PrivMode_MouseBtnEvent),
+ const_iv (PrivMode_MouseAnyEvent),
+ const_iv (PrivMode_BracketPaste),
+ const_iv (PrivMode_ExtModeMouse),
+ const_iv (PrivMode_ExtMouseRight),
+ const_iv (PrivMode_BlinkingCursor),
+ const_iv (PrivMode_mouse_report),
+ const_iv (PrivMode_Default),
+ };
+
+ for (civ = const_iv + ecb_array_length (const_iv); civ > const_iv; civ--)
+ newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
+}
+
+void
+log (utf8_string msg)
+ CODE:
+ rxvt_log ("%s", msg);
+
+void
+warn (utf8_string msg)
+ CODE:
+ rxvt_warn ("%s", msg);
+
+void
+fatal (utf8_string msg)
+ CODE:
+ rxvt_fatal ("%s", msg);
+
+void
+_exit (int status)
+
+void
+catch_fatal (SV *block)
+ PROTOTYPE: &
+ CODE:
+ try
+ {
+ PUSHMARK (SP);
+ PUTBACK;
+ call_sv (block, G_VOID | G_DISCARD);
+ SPAGAIN;
+ }
+ catch (const rxvt_failure_exception &e)
+ {
+ croak ("rxvt_fatal exception caught, trying to continue.");
+ }
+
+NV
+NOW ()
+ CODE:
+ RETVAL = ev::now ();
+ OUTPUT:
+ RETVAL
+
+int
+GET_BASEFG (int rend)
+ CODE:
+ RETVAL = GET_BASEFG (rend);
+ OUTPUT:
+ RETVAL
+
+int
+GET_BASEBG (int rend)
+ CODE:
+ RETVAL = GET_BASEBG (rend);
+ OUTPUT:
+ RETVAL
+
+int
+SET_FGCOLOR (int rend, int new_color)
+ CODE:
+ RETVAL = SET_FGCOLOR (rend, clamp (new_color, 0, TOTAL_COLORS - 1));
+ OUTPUT:
+ RETVAL
+
+int
+SET_BGCOLOR (int rend, int new_color)
+ CODE:
+ RETVAL = SET_BGCOLOR (rend, clamp (new_color, 0, TOTAL_COLORS - 1));
+ OUTPUT:
+ RETVAL
+
+int
+GET_CUSTOM (int rend)
+ CODE:
+ RETVAL = (rend & RS_customMask) >> RS_customShift;
+ OUTPUT:
+ RETVAL
+
+int
+SET_CUSTOM (int rend, int new_value)
+ CODE:
+{
+ if (!IN_RANGE_EXC (new_value, 0, RS_customCount))
+ croak ("custom value out of range, must be 0..%d", RS_customCount - 1);
+
+ RETVAL = (rend & ~RS_customMask)
+ | ((new_value << RS_customShift) & RS_customMask);
+}
+ OUTPUT:
+ RETVAL
+
+void
+termlist ()
+ PPCODE:
+{
+ EXTEND (SP, rxvt_term::termlist.size ());
+
+ for (rxvt_term **t = rxvt_term::termlist.begin (); t < rxvt_term::termlist.end (); t++)
+ if ((*t)->perl.self)
+ PUSHs (sv_2mortal (newSVterm (*t)));
+}
+
+IV
+_new_selection_request (rxvt_term *term, int selnum, Time tm, Window win, Atom prop, SV *cb)
+ CODE:
+ rxvt_selection *req = new rxvt_selection (term->display, selnum, tm, win, prop, term);
+ req->cb_sv = newSVsv (cb);
+ AV *av = (AV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)term->perl.self), "_selection", 10, 0));
+ av_push (av, newSViv ((IV)req));
+ RETVAL = (IV)req;
+ OUTPUT:
+ RETVAL
+
+void
+_delete_selection_request (IV req_)
+ CODE:
+ rxvt_selection *req = (rxvt_selection *)req_;
+ AV *av = (AV *)SvRV (*hv_fetch ((HV *)SvRV ((SV *)req->term->perl.self), "_selection", 10, 0));
+ int i;
+
+ for (i = AvFILL (av); i >= 0; i--)
+ if (SvIV (*av_fetch (av, i, 1)) == req_)
+ break;
+
+ for (; i < AvFILL (av); i++)
+ av_store (av, i, SvREFCNT_inc (*av_fetch (av, i + 1, 0)));
+
+ av_pop (av);
+
+ delete req;
+
+MODULE = urxvt PACKAGE = urxvt::term
+
+SV *
+_new (AV *env, AV *arg)
+ CODE:
+{
+ rxvt_term *term = new rxvt_term;
+
+ stringvec *argv = new stringvec;
+ for (int i = 0; i <= AvFILL (arg); i++)
+ argv->push_back (strdup (SvPVbyte_nolen (*av_fetch (arg, i, 1))));
+
+ stringvec *envv = new stringvec;
+ for (int i = AvFILL (env) + 1; i--; )
+ envv->push_back (strdup (SvPVbyte_nolen (*av_fetch (env, i, 1))));
+
+ try
+ {
+ term->init (argv, envv);
+ }
+ catch (const class rxvt_failure_exception &e)
+ {
+ term->destroy ();
+ croak ("error while initializing new terminal instance");
+ }
+
+ RETVAL = term && term->perl.self
+ ? newSVterm (term) : &PL_sv_undef;
+}
+ OUTPUT:
+