diff options
Diffstat (limited to 'src/rxvtperl.xs')
-rw-r--r-- | src/rxvtperl.xs | 2530 |
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: + RETVAL |