/*----------------------------------------------------------------------* * File: rxvtperl.xs *----------------------------------------------------------------------* * * All portions of code are copyright by their respective author/s. * Copyright (c) 2005-2014 Marc Lehmann * * 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 #include #include #undef line_t #undef bool // perl defines it's own bool type, except with g++... what a trap #include "../config.h" #include #include #include #include // support old includes (https://bugs.freedesktop.org/show_bug.cgi?id=2799, https://lists.x.org/archives/xorg-arch/2005-March/000004.html) #ifndef ShapeInput # define ShapeInput 2 #endif #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 (SvNV (*av_fetch (av, 0, 0))); if (len >= 3) { c.g = float_to_component (SvNV (*av_fetch (av, 1, 0))); c.b = float_to_component (SvNV (*av_fetch (av, 2, 0))); if (len >= 4) c.a = float_to_component (SvNV (*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; #if 0 /* we are not a library anymore, so doing this is just not worth it */ /*THINK/TODO: this has the side effect of, of course, not calling destructors. */ /* but these are not guaranteed anyway... */ rxvt_perl_interp::~rxvt_perl_interp () { if (perl) { localise_env set_environ (perl_environ); perl_destruct (perl); perl_free (perl); PERL_SYS_TERM (); } } #endif void rxvt_perl_interp::init () { if (!perl) { rxvt_push_locale ("C"); // perl init destroys current locale { perl_environ = rxvt_environ; localise_env set_environ (perl_environ); const char *args[] = { "", "-e" "BEGIN {" " urxvt->bootstrap;" " unshift @INC, '" LIBDIR "';" "}" "" "use urxvt;", 0 }; int argc = ecb_array_length (args) - 1; char **argv = (char **)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, int 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 (HOOK_OSC_SEQ), const_iv (HOOK_OSC_SEQ_PERL), 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 (None), 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), // shape extension const_iv (ShapeSet), const_iv (ShapeUnion), const_iv (ShapeIntersect), const_iv (ShapeSubtract), const_iv (ShapeInvert), const_iv (ShapeBounding), const_iv (ShapeClip), const_iv (ShapeInput), // XIM # 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), # endif # 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 /* 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_ExtMouseUTF8), const_iv (PrivMode_ExtMouseUrxvt), 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..%lu", 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; Region XCreateRegion () int XUnionRectWithRegion (int x, int y, int w, int h, Region src, Region dst) CODE: XRectangle rect; rect.x = x; rect.y = y; rect.width = w; rect.height = h; RETVAL = XUnionRectWithRegion (&rect, src, dst); OUTPUT: RETVAL int XIntersectRegion (Region src1, Region src2, Region res) int XUnionRegion (Region src1, Region src2, Region res) int XSubtractRegion (Region src1, Region src2, Region res) int XXorRegion (Region src1, Region src2, Region res) int XOffsetRegion (Region r, int dx, int dy) int XShrinkRegion (Region r, int dx, int dy) int XDestroyRegion (Region r) 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 void rxvt_term::destroy () void rxvt_term::set_should_invoke (int htype, int inc) CODE: uint8_t &count = THIS->perl.should_invoke [htype]; uint8_t prev = count; count += inc; if (!prev != !count) { // hook status changed, react switch (htype) { case HOOK_POSITION_CHANGE: if (count) THIS->get_window_origin (THIS->parent_x, THIS->parent_y); } } void rxvt_term::put_option_db (octet_string specifier, octet_string value) CODE: XrmPutStringResource (&THIS->option_db, specifier, value); void rxvt_term::_keysym_resources () PPCODE: PUTBACK; _keysym_resources (THIS); SPAGAIN; int rxvt_term::grab_button (int button, U32 modifiers, Window window = THIS->vt) CODE: RETVAL = XGrabButton (THIS->dpy, button, modifiers, window, 1, ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, GrabModeSync, GrabModeSync, None, GRAB_CURSOR); OUTPUT: RETVAL int rxvt_term::ungrab_button (int button, U32 modifiers, Window window = THIS->vt) CODE: RETVAL = XUngrabButton (THIS->dpy, button, modifiers, window); OUTPUT: RETVAL void rxvt_term::XGrabKey (int keycode, U32 modifiers, Window window = THIS->vt, \ int owner_events = 1, int pointer_mode = GrabModeAsync, int keyboard_mode = GrabModeAsync) CODE: XGrabKey (THIS->dpy, keycode, modifiers, window, owner_events, pointer_mode, keyboard_mode); void rxvt_term::XUngrabKey (int keycode, U32 modifiers, Window window = THIS->vt) CODE: XUngrabKey (THIS->dpy, keycode, modifiers, window); bool rxvt_term::grab (Time eventtime, int sync = 0) CODE: { int mode = sync ? GrabModeSync : GrabModeAsync; THIS->perl.grabtime = 0; if (!XGrabPointer (THIS->dpy, THIS->vt, 0, ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, mode, mode, None, GRAB_CURSOR, eventtime)) if (!XGrabKeyboard (THIS->dpy, THIS->vt, 0, mode, mode, eventtime)) THIS->perl.grabtime = eventtime; else XUngrabPointer (THIS->dpy, eventtime); RETVAL = !!THIS->perl.grabtime; } OUTPUT: RETVAL void rxvt_term::allow_events_async () CODE: XAllowEvents (THIS->dpy, AsyncBoth, THIS->perl.grabtime); void rxvt_term::allow_events_sync () CODE: XAllowEvents (THIS->dpy, SyncBoth, THIS->perl.grabtime); void rxvt_term::allow_events_replay () CODE: XAllowEvents (THIS->dpy, ReplayPointer, THIS->perl.grabtime); XAllowEvents (THIS->dpy, ReplayKeyboard, THIS->perl.grabtime); void rxvt_term::ungrab () CODE: ungrab (THIS); int rxvt_term::XStringToKeysym (octet_string string) CODE: RETVAL = XStringToKeysym (string); OUTPUT: RETVAL char * rxvt_term::XKeysymToString (int sym) CODE: RETVAL = XKeysymToString (sym); OUTPUT: RETVAL int rxvt_term::XKeysymToKeycode (int sym) CODE: RETVAL = XKeysymToKeycode (THIS->dpy, sym); OUTPUT: RETVAL int rxvt_term::XKeycodeToKeysym (int code, int index) CODE: RETVAL = rxvt_XKeycodeToKeysym (THIS->dpy, code, index); OUTPUT: RETVAL int rxvt_term::strwidth (SV *str) CODE: { wchar_t *wstr = sv2wcs (str); rxvt_push_locale (THIS->locale); RETVAL = 0; for (wchar_t *wc = wstr; *wc; wc++) { int w = WCWIDTH (*wc); if (w) RETVAL += max (w, 1); } rxvt_pop_locale (); free (wstr); } OUTPUT: RETVAL SV * rxvt_term::locale_encode (SV *str) CODE: { if (!SvOK (str)) XSRETURN_UNDEF; wchar_t *wstr = sv2wcs (str); rxvt_push_locale (THIS->locale); char *mbstr = rxvt_wcstombs (wstr); rxvt_pop_locale (); free (wstr); RETVAL = newSVpv (mbstr, 0); free (mbstr); } OUTPUT: RETVAL SV * rxvt_term::locale_decode (SV *octets) CODE: { if (!SvOK (octets)) XSRETURN_UNDEF; STRLEN len; char *data = SvPVbyte (octets, len); rxvt_push_locale (THIS->locale); wchar_t *wstr = rxvt_mbstowcs (data, len); rxvt_pop_locale (); RETVAL = wcs2sv (wstr); free (wstr); } OUTPUT: RETVAL #define TERM_OFFSET(sym) offsetof (TermWin_t, sym) #define TERM_OFFSET_width TERM_OFFSET(width) #define TERM_OFFSET_height TERM_OFFSET(height) #define TERM_OFFSET_fwidth TERM_OFFSET(fwidth) #define TERM_OFFSET_fheight TERM_OFFSET(fheight) #define TERM_OFFSET_fbase TERM_OFFSET(fbase) #define TERM_OFFSET_nrow TERM_OFFSET(nrow) #define TERM_OFFSET_ncol TERM_OFFSET(ncol) #define TERM_OFFSET_focus TERM_OFFSET(focus) #define TERM_OFFSET_mapped TERM_OFFSET(mapped) #define TERM_OFFSET_int_bwidth TERM_OFFSET(int_bwidth) #define TERM_OFFSET_ext_bwidth TERM_OFFSET(ext_bwidth) #define TERM_OFFSET_lineSpace TERM_OFFSET(lineSpace) #define TERM_OFFSET_letterSpace TERM_OFFSET(letterSpace) #define TERM_OFFSET_saveLines TERM_OFFSET(saveLines) #define TERM_OFFSET_total_rows TERM_OFFSET(total_rows) #define TERM_OFFSET_top_row TERM_OFFSET(top_row) int rxvt_term::width (int new_value = NO_INIT) ALIAS: width = TERM_OFFSET_width height = TERM_OFFSET_height fwidth = TERM_OFFSET_fwidth fheight = TERM_OFFSET_fheight fbase = TERM_OFFSET_fbase nrow = TERM_OFFSET_nrow ncol = TERM_OFFSET_ncol focus = TERM_OFFSET_focus mapped = TERM_OFFSET_mapped int_bwidth = TERM_OFFSET_int_bwidth ext_bwidth = TERM_OFFSET_ext_bwidth lineSpace = TERM_OFFSET_lineSpace letterSpace = TERM_OFFSET_letterSpace saveLines = TERM_OFFSET_saveLines total_rows = TERM_OFFSET_total_rows top_row = TERM_OFFSET_top_row CODE: RETVAL = *(int *)((char *)THIS + ix); if (items > 1) *(int *)((char *)THIS + ix) = new_value; OUTPUT: RETVAL unsigned int rxvt_term::ModLevel3Mask () ALIAS: ModLevel3Mask = 0 ModMetaMask = 1 ModNumLockMask = 2 current_screen = 3 hidden_cursor = 4 priv_modes = 5 CODE: switch (ix) { case 0: RETVAL = THIS->ModLevel3Mask; break; case 1: RETVAL = THIS->ModMetaMask; break; case 2: RETVAL = THIS->ModNumLockMask; break; case 3: RETVAL = THIS->current_screen; break; #ifdef CURSOR_BLINK case 4: RETVAL = THIS->hidden_cursor; break; #else case 4: RETVAL = 0; break; #endif case 5: RETVAL = THIS->priv_modes; break; } OUTPUT: RETVAL char * rxvt_term::display_id () ALIAS: display_id = 0 locale = 1 CODE: switch (ix) { case 0: RETVAL = THIS->display->id; break; case 1: RETVAL = THIS->locale; break; } OUTPUT: RETVAL SV * rxvt_term::envv () ALIAS: argv = 1 PPCODE: { stringvec *vec = ix ? THIS->argv : THIS->envv; EXTEND (SP, vec->size ()); for (char **i = vec->begin (); i != vec->end (); ++i) if (*i) PUSHs (sv_2mortal (newSVpv (*i, 0))); } int rxvt_term::pty_ev_events (int events = ev::UNDEF) CODE: RETVAL = THIS->pty_ev.events; if (events != ev::UNDEF) THIS->pty_ev.set (events); OUTPUT: RETVAL int rxvt_term::pty_fd () CODE: RETVAL = THIS->pty->pty; OUTPUT: RETVAL Window rxvt_term::parent () CODE: RETVAL = THIS->parent; OUTPUT: RETVAL int rxvt_term::parent_x () CODE: RETVAL = THIS->parent_x; OUTPUT: RETVAL int rxvt_term::parent_y () CODE: RETVAL = THIS->parent_y; OUTPUT: RETVAL Window rxvt_term::vt () CODE: RETVAL = THIS->vt; OUTPUT: RETVAL void rxvt_term::vt_emask_add (U32 emask) CODE: THIS->vt_emask_perl |= emask; THIS->vt_select_input (); U32 rxvt_term::rstyle (U32 new_rstyle = THIS->rstyle) CODE: RETVAL = THIS->rstyle; THIS->rstyle = new_rstyle; OUTPUT: RETVAL int rxvt_term::view_start (int newval = 0) PROTOTYPE: $;$ CODE: { RETVAL = THIS->view_start; if (items > 1) THIS->scr_changeview (newval); } OUTPUT: RETVAL void rxvt_term::set_urgency (bool enable) void rxvt_term::focus_in () void rxvt_term::focus_out () void rxvt_term::key_press (unsigned int state, unsigned int keycode, Time time = CurrentTime) ALIAS: key_release = 1 CODE: { XKeyEvent xkey; memset (&xkey, 0, sizeof (xkey)); xkey.time = time; xkey.state = state; xkey.keycode = keycode; xkey.type = ix ? KeyRelease : KeyPress; xkey.display = THIS->dpy; xkey.window = THIS->vt; xkey.root = THIS->display->root; xkey.subwindow = THIS->vt; if (ix) THIS->key_release (xkey); else THIS->key_press (xkey); } void rxvt_term::want_refresh () CODE: THIS->want_refresh = 1; THIS->refresh_check (); void rxvt_term::refresh_check () void rxvt_term::ROW_t (int row_number, SV *new_text = 0, int start_col = 0, int start_ofs = 0, int max_len = MAX_COLS) PPCODE: { if (!IN_RANGE_EXC (row_number, THIS->top_row, THIS->nrow)) XSRETURN_EMPTY; line_t &l = ROW(row_number); if (GIMME_V != G_VOID) { wchar_t *wstr = rxvt_temp_buf (THIS->ncol); for (int col = 0; col < THIS->ncol; col++) wstr [col] = l.t [col]; XPUSHs (sv_2mortal (wcs2sv (wstr, THIS->ncol))); } if (new_text) { wchar_t *wstr = sv2wcs (new_text); int len = min (wcslen (wstr) - start_ofs, max_len); if (start_col < 0 || start_col + len > THIS->ncol) { free (wstr); croak ("new_text extends beyond horizontal margins"); } for (int col = start_col; col < start_col + len; col++) { l.t [col] = wstr [start_ofs + col - start_col]; l.r [col] = SET_FONT (l.r [col], THIS->fontset [GET_STYLE (l.r [col])]->find_font (l.t [col])); } free (wstr); } } void rxvt_term::ROW_r (int row_number, SV *new_rend = 0, int start_col = 0, int start_ofs = 0, int max_len = MAX_COLS) PPCODE: { if (!IN_RANGE_EXC (row_number, THIS->top_row, THIS->nrow)) XSRETURN_EMPTY; line_t &l = ROW(row_number); if (GIMME_V != G_VOID) { AV *av = newAV (); av_extend (av, THIS->ncol - 1); for (int col = 0; col < THIS->ncol; col++) av_store (av, col, newSViv (l.r [col])); XPUSHs (sv_2mortal (newRV_noinc ((SV *)av))); } if (new_rend) { if (!SvROK (new_rend) || SvTYPE (SvRV (new_rend)) != SVt_PVAV) croak ("new_rend must be arrayref"); AV *av = (AV *)SvRV (new_rend); int len = min (AvFILL (av) + 1 - start_ofs, max_len); if (start_col < 0 || start_col + len > THIS->ncol) croak ("new_rend array extends beyond horizontal margins"); for (int col = start_col; col < start_col + len; col++) { rend_t r = SvIV (*av_fetch (av, start_ofs + col - start_col, 1)) & ~RS_fontMask; l.r [col] = SET_FONT (r, THIS->fontset [GET_STYLE (r)]->find_font (l.t [col])); } } } int rxvt_term::ROW_l (int row_number, int new_length = -1) CODE: { if (!IN_RANGE_EXC (row_number, THIS->top_row, THIS->nrow)) XSRETURN_EMPTY; line_t &l = ROW(row_number); RETVAL = l.l; if (new_length >= 0) l.l = new_length; } OUTPUT: RETVAL bool rxvt_term::ROW_is_longer (int row_number, int new_is_longer = -1) CODE: { if (!IN_RANGE_EXC (row_number, THIS->top_row, THIS->nrow)) XSRETURN_EMPTY; line_t &l = ROW(row_number); RETVAL = l.is_longer (); if (new_is_longer >= 0) l.is_longer (new_is_longer); } OUTPUT: RETVAL SV * rxvt_term::special_encode (SV *string) CODE: { wchar_t *wstr = sv2wcs (string); int wlen = wcslen (wstr); wchar_t *rstr = rxvt_temp_buf (wlen * 2); // cannot become longer rxvt_push_locale (THIS->locale); wchar_t *r = rstr; for (wchar_t *s = wstr; *s; s++) { int w = WCWIDTH (*s); if (w == 0) { if (r == rstr) croak ("leading combining character unencodable"); unicode_t n = rxvt_compose (r[-1], *s); if (n == NOCHAR) n = rxvt_composite.compose (r[-1], *s); r[-1] = n; } #if !UNICODE_3 else if (*s >= 0x10000) *r++ = rxvt_composite.compose (*s); #endif else *r++ = *s; // the *2 above only allows wcwidth <= 2 if (w > 1) *r++ = NOCHAR; } rxvt_pop_locale (); free (wstr); RETVAL = wcs2sv (rstr, r - rstr); } OUTPUT: RETVAL SV * rxvt_term::special_decode (SV *text) CODE: { wchar_t *wstr = sv2wcs (text); int dlen = 0; // find length for (wchar_t *s = wstr; *s; s++) if (*s == NOCHAR) ; else if (IS_COMPOSE (*s)) dlen += rxvt_composite.expand (*s); else dlen++; wchar_t *rstr = rxvt_temp_buf (dlen); // decode wchar_t *r = rstr; for (wchar_t *s = wstr; *s; s++) if (*s == NOCHAR) ; else if (IS_COMPOSE (*s)) r += rxvt_composite.expand (*s, r); else *r++ = *s; free (wstr); RETVAL = wcs2sv (rstr, r - rstr); } OUTPUT: RETVAL void rxvt_term::_resource (octet_string name, int index, SV *newval = 0) PPCODE: { static const struct resval { const char *name; int value; } *rs, rslist [] = { # define def(name) { # name, Rs_ ## name }, # define reserve(name,count) # include "rsinc.h" # undef def # undef reserve }; rs = rslist + ecb_array_length (rslist); if (*name) { do { if (rs-- == rslist) croak ("no such resource '%s', requested", name); } while (strcmp (name, rs->name)); index += rs->value; } else { --rs; name = (octet_string)""; } if (!IN_RANGE_EXC (index, 0, NUM_RESOURCES)) croak ("requested out-of-bound resource %s+%d,", name, index - rs->value); if (GIMME_V != G_VOID) XPUSHs (THIS->rs [index] ? sv_2mortal (newSVpv (THIS->rs [index], 0)) : &PL_sv_undef); if (newval) { if (SvOK (newval)) { char *str = strdup (SvPVbyte_nolen (newval)); THIS->rs [index] = str; THIS->allocated.push_back (str); } else THIS->rs [index] = 0; } } const char * rxvt_term::x_resource (octet_string name) bool rxvt_term::option (U8 optval, int set = -1) CODE: { RETVAL = THIS->option (optval); if (set >= 0) { THIS->set_option (optval, set); if (THIS->init_done) // avoid doing this before START switch (optval) { case Opt_skipBuiltinGlyphs: THIS->set_fonts (); THIS->scr_remap_chars (); THIS->scr_touch (true); THIS->want_refresh = 1; THIS->refresh_check (); break; #ifdef CURSOR_BLINK case Opt_cursorBlink: THIS->cursor_blink_reset (); break; #endif case Opt_cursorUnderline: THIS->cursor_type = set ? 1 : 0; THIS->want_refresh = 1; THIS->refresh_check (); break; # case Opt_scrollBar_floating: # case Opt_scrollBar_right: # THIS->resize_all_windows (THIS->width, THIS->height, 1); # break; } } } OUTPUT: RETVAL SV * rxvt_term::lookup_keysym (int keysym, unsigned int state) CODE: { keysym_t *key = THIS->keyboard->lookup_keysym (THIS, keysym, state); RETVAL = key ? sv_2mortal (newSVpv (key->str, 0)) : &PL_sv_undef; } OUTPUT: RETVAL bool rxvt_term::bind_action (octet_string keysym, octet_string action) ALIAS: parse_keysym = 1 CODE: RETVAL = 0 < THIS->bind_action (keysym, action); THIS->keyboard->register_done (); OUTPUT: RETVAL void rxvt_term::register_command (int keysym, unsigned int state, SV *str) CODE: wchar_t *wstr = sv2wcs (str); THIS->keyboard->register_action (keysym, state, wstr); free (wstr); void rxvt_term::screen_cur (...) PROTOTYPE: $;$$ ALIAS: screen_cur = 0 selection_beg = 1 selection_end = 2 selection_mark = 3 PPCODE: { row_col_t &rc = ix == 0 ? THIS->screen.cur : ix == 1 ? THIS->selection.beg : ix == 2 ? THIS->selection.end : THIS->selection.mark; if (GIMME_V != G_VOID) { EXTEND (SP, 2); PUSHs (sv_2mortal (newSViv (rc.row))); PUSHs (sv_2mortal (newSViv (rc.col))); } if (items >= 3) { rc.row = SvIV (ST (1)); rc.col = SvIV (ST (2)); if (ix == 2) { if (rc.col == 0) { // col == 0 means end of previous line rc.row--; rc.col = THIS->ncol; } else if (IN_RANGE_EXC (rc.row, THIS->top_row, THIS->nrow) && rc.col > ROW(rc.row).l) { // col >= length means while line and add newline rc.col = THIS->ncol; } } clamp_it (rc.col, 0, THIS->ncol); clamp_it (rc.row, THIS->top_row, THIS->nrow - 1); if (ix) { THIS->selection.screen = THIS->current_screen; THIS->selection_changed (); THIS->refresh_check (); } } } int rxvt_term::selection_screen (int screen = -1) CODE: RETVAL = THIS->selection.screen; if (screen >= 0) THIS->selection.screen = screen; OUTPUT: RETVAL void rxvt_term::selection_request (Time tm, int selnum) void rxvt_term::selection_clear (bool clipboard = false) void rxvt_term::selection_make (Time eventtime, bool rect = false) CODE: THIS->selection.op = SELECTION_CONT; THIS->selection.rect = rect; THIS->selection_make (eventtime); int rxvt_term::selection_grab (Time eventtime, bool clipboard = false) void rxvt_term::selection (SV *newtext = 0, bool clipboard = false) PPCODE: { wchar_t * &text = clipboard ? THIS->selection.clip_text : THIS->selection.text; unsigned int &len = clipboard ? THIS->selection.clip_len : THIS->selection.len; if (GIMME_V != G_VOID) XPUSHs (text ? sv_2mortal (wcs2sv (text, len)) : &PL_sv_undef); if (newtext) { free (text); text = sv2wcs (newtext); len = wcslen (text); } } char rxvt_term::cur_charset () CODE: RETVAL = THIS->charsets [THIS->screen.charset]; OUTPUT: RETVAL void 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) void rxvt_term::scr_xor_span (int beg_row, int beg_col, int end_row, int end_col, U32 rstyle = RS_RVid) void rxvt_term::scr_bell () void rxvt_term::scr_recolor (bool refresh = true); void rxvt_term::scr_change_screen (int screen) void rxvt_term::scr_add_lines (SV *string) CODE: { wchar_t *wstr = sv2wcs (string); THIS->scr_add_lines (wstr, wcslen (wstr)); free (wstr); } void rxvt_term::tt_write_user_input (SV *octets) INIT: STRLEN len; char *str = SvPVbyte (octets, len); C_ARGS: str, len void rxvt_term::tt_write (SV *octets) INIT: STRLEN len; char *str = SvPVbyte (octets, len); C_ARGS: str, len void rxvt_term::tt_paste (SV *octets) INIT: STRLEN len; char *str = SvPVbyte (octets, len); C_ARGS: str, len void rxvt_term::cmd_parse (SV *octets) CODE: { STRLEN len; char *str = SvPVbyte (octets, len); char *old_cmdbuf_ptr = THIS->cmdbuf_ptr; char *old_cmdbuf_endp = THIS->cmdbuf_endp; THIS->cmdbuf_ptr = str; THIS->cmdbuf_endp = str + len; rxvt_push_locale (THIS->locale); THIS->cmd_parse (); rxvt_pop_locale (); THIS->cmdbuf_ptr = old_cmdbuf_ptr; THIS->cmdbuf_endp = old_cmdbuf_endp; } SV * rxvt_term::overlay (int x, int y, int w, int h, int rstyle = OVERLAY_RSTYLE, int border = 2) CODE: { overlay *o = new overlay (THIS, x, y, w, h, rstyle, border); RETVAL = newSVptr ((void *)o, "urxvt::overlay"); o->self = (HV *)SvRV (RETVAL); } OUTPUT: RETVAL ############################################################################# # Various X Utility Functions ############################################################################# void rxvt_term::XListProperties (Window window) PPCODE: { int count; Atom *props = XListProperties (THIS->dpy, window, &count); EXTEND (SP, count); while (count--) PUSHs (sv_2mortal (newSVuv ((U32)props [count]))); XFree (props); } void rxvt_term::XGetWindowProperty (Window window, Atom property) PPCODE: { Atom type; int format; unsigned long nitems; unsigned long bytes_after; unsigned char *prop; XGetWindowProperty (THIS->dpy, window, property, 0, 1<<24, 0, AnyPropertyType, &type, &format, &nitems, &bytes_after, &prop); if (type != None) { int elemsize = format == 16 ? sizeof (short) : format == 32 ? sizeof (long) : 1; EXTEND (SP, 3); PUSHs (sv_2mortal (newSVuv ((U32)type))); PUSHs (sv_2mortal (newSViv (format))); PUSHs (sv_2mortal (newSVpvn ((char *)prop, nitems * elemsize))); XFree (prop); } } void rxvt_term::XChangeProperty (Window window, Atom property, Atom type, int format, SV *data) CODE: { STRLEN len; char *data_ = SvPVbyte (data, len); int elemsize = format == 16 ? sizeof (short) : format == 32 ? sizeof (long) : 1; XChangeProperty (THIS->dpy, window, property, type, format, PropModeReplace, (unsigned char *)data_, len / elemsize); } Atom XInternAtom (rxvt_term *term, octet_string atom_name, int only_if_exists = FALSE) C_ARGS: term->dpy, atom_name, only_if_exists char * XGetAtomName (rxvt_term *term, Atom atom) C_ARGS: term->dpy, atom CLEANUP: XFree (RETVAL); void XDeleteProperty (rxvt_term *term, Window window, Atom property) C_ARGS: term->dpy, window, property void rxvt_term::XShapeQueryVersion () PPCODE: int major, minor; EXTEND (SP, 2); if (XShapeQueryVersion (THIS->display->dpy, &major, &minor)) { PUSHs (sv_2mortal (newSViv (major))); PUSHs (sv_2mortal (newSViv (minor))); } void XShapeCombineRegion (rxvt_term *term, Window dest, int destKind, int xOff, int yOff, Region r, int op) C_ARGS: term->display->dpy, dest, destKind, xOff, yOff, r, op void XShapeCombineMask (rxvt_term *term, XID dest, int destKind, int xOff, int yOff, Pixmap src, int op) C_ARGS: term->display->dpy, dest, destKind, xOff, yOff, src, op void XShapeCombineShape (rxvt_term *term, XID dest, int destKind, int xOff, int yOff, Pixmap src, int srcKind, int op) C_ARGS: term->display->dpy, dest, destKind, xOff, yOff, src, srcKind, op Window rxvt_term::DefaultRootWindow () CODE: RETVAL = THIS->display->root; OUTPUT: RETVAL #if 0 Window XCreateSimpleWindow (rxvt_term *term, Window parent, int x, int y, unsigned int width, unsigned int height) C_ARGS: term->dpy, (Window)parent, x, y, width, height, 0, term->pix_colors_focused[Color_border], term->pix_colors_focused[Color_border] #endif void XReparentWindow (rxvt_term *term, Window window, Window parent, int x = 0, int y = 0) C_ARGS: term->dpy, window, parent, x, y void XMapWindow (rxvt_term *term, Window window) C_ARGS: term->dpy, window void XUnmapWindow (rxvt_term *term, Window window) C_ARGS: term->dpy, window void XMoveResizeWindow (rxvt_term *term, Window window, int x, int y, unsigned int width, unsigned int height) C_ARGS: term->dpy, window, x, y, width, height void rxvt_term::XChangeInput (Window window, U32 add_events, U32 del_events = 0) CODE: { XWindowAttributes attr; XGetWindowAttributes (THIS->dpy, window, &attr); XSelectInput (THIS->dpy, window, attr.your_event_mask | add_events & ~del_events); } void rxvt_term::XTranslateCoordinates (Window src, Window dst, int x, int y) PPCODE: { int dx, dy; Window child; if (XTranslateCoordinates (THIS->dpy, src, dst, x, y, &dx, &dy, &child)) { EXTEND (SP, 3); PUSHs (sv_2mortal (newSViv (dx))); PUSHs (sv_2mortal (newSViv (dy))); PUSHs (sv_2mortal (newSVuv (child))); } } ############################################################################# # fancy bg bloatstuff (TODO: should be moved up somewhere) bool rxvt_term::has_render () CODE: RETVAL = THIS->display->flags & DISPLAY_HAS_RENDER; OUTPUT: RETVAL void rxvt_term::background_geometry (bool border = false) PPCODE: EXTEND (SP, 4); PUSHs (sv_2mortal (newSViv (THIS->parent_x + (border ? THIS->window_vt_x : 0)))); PUSHs (sv_2mortal (newSViv (THIS->parent_y + (border ? THIS->window_vt_y : 0)))); PUSHs (sv_2mortal (newSViv (border ? THIS->vt_width : THIS->szHint.width ))); PUSHs (sv_2mortal (newSViv (border ? THIS->vt_height : THIS->szHint.height))); #if HAVE_IMG rxvt_img * rxvt_term::new_img (SV *format = &PL_sv_undef, int x = 0, int y = 0, int width = 1, int height = 1) CODE: XRenderPictFormat *f = SvOK (format) ? XRenderFindStandardFormat (THIS->dpy, SvIV (format)) : XRenderFindVisualFormat (THIS->dpy, THIS->visual); RETVAL = new rxvt_img (THIS, f, x, y, width, height); RETVAL->alloc (); OUTPUT: RETVAL #if ENABLE_TRANSPARENCY rxvt_img * rxvt_term::new_img_from_root () CODE: RETVAL = rxvt_img::new_from_root (THIS); OUTPUT: RETVAL #endif #if HAVE_PIXBUF rxvt_img * rxvt_term::new_img_from_file (octet_string filename) CODE: try { RETVAL = rxvt_img::new_from_file (THIS, filename); } catch (const class rxvt_failure_exception &e) { croak ("new_img_from_file failed"); } OUTPUT: RETVAL #endif void rxvt_term::clr_background () CODE: delete THIS->bg_img; THIS->bg_img = 0; THIS->bg_flags = rxvt_term::BG_NEEDS_REFRESH; void rxvt_term::set_background (rxvt_img *img, bool border = false) CODE: delete THIS->bg_img; THIS->bg_img = 0; THIS->bg_flags = rxvt_term::BG_NEEDS_REFRESH; //if (img) // TODO: cannot be false, maybe allow and get rid of clr_background? { img = img->clone (); // own the img if (img->repeat != RepeatNormal) // X11 only supports RepeatNormal as bg pixmap img->sub_rect (0, 0, border ? THIS->vt_width : THIS->szHint.width, border ? THIS->vt_height : THIS->szHint.height) ->replace (img); // just in case, should usually be a nop img->reify () ->replace (img); img->convert_format (XRenderFindVisualFormat (THIS->dpy, THIS->visual), THIS->pix_colors [Color_bg]) ->replace (img); THIS->bg_img = img; if (!border) THIS->bg_flags |= rxvt_term::BG_IS_TRANSPARENT; } #endif ############################################################################# # urxvt::overlay ############################################################################# MODULE = urxvt PACKAGE = urxvt::overlay void overlay::set (int x, int y, SV *text, SV *rend = 0) void overlay::show () void overlay::hide () void overlay::DESTROY () INCLUDE: $PERL x))); PUSHs (sv_2mortal (newSViv (THIS->y))); PUSHs (sv_2mortal (newSViv (THIS->w))); PUSHs (sv_2mortal (newSViv (THIS->h))); int rxvt_img::x () ALIAS: x = 0 y = 1 w = 2 h = 3 CODE: switch (ix) { case 0: RETVAL = THIS->x; break; case 1: RETVAL = THIS->y; break; case 2: RETVAL = THIS->w; break; case 3: RETVAL = THIS->h; break; } OUTPUT: RETVAL Pixmap rxvt_img::pm () CODE: RETVAL = THIS->pm; OUTPUT: RETVAL void rxvt_img::fill (SV *c, int x = 0, int y = 0, int w = THIS->w, int h = THIS->h) PROTOTYPE: $;$$$$ INIT: rxvt_screen screen; screen.set (THIS->d); rgba cc = parse_rgba (c, &screen); C_ARGS: cc, x, y, w, h void rxvt_img::DESTROY () CODE: delete THIS; void rxvt_img::add_alpha () void rxvt_img::unshare () void rxvt_img::repeat_mode (render_repeat_mode repeat = 0) PPCODE: if (items >= 2) THIS->repeat_mode (repeat); if (GIMME_V != G_VOID) XPUSHs (sv_2mortal (newSViv (THIS->repeat))); void rxvt_img::move (int dx, int dy) void rxvt_img::brightness (rxvt_img::nv r, rxvt_img::nv g, rxvt_img::nv b, rxvt_img::nv a = 1.) void rxvt_img::contrast (rxvt_img::nv r, rxvt_img::nv g, rxvt_img::nv b, rxvt_img::nv a = 1.) void rxvt_img::draw (rxvt_img *img, int op = PictOpOver, rxvt_img::nv mask = 1.); rxvt_img * rxvt_img::clone () rxvt_img * rxvt_img::reify () rxvt_img * rxvt_img::sub_rect (int x, int y, int width, int height) rxvt_img * rxvt_img::blur (int rh, int rv) rxvt_img * rxvt_img::muladd (rxvt_img::nv mul, rxvt_img::nv add) rxvt_img * rxvt_img::transform (rxvt_img::nv p11, rxvt_img::nv p12, rxvt_img::nv p13, rxvt_img::nv p21, rxvt_img::nv p22, rxvt_img::nv p23, rxvt_img::nv p31, rxvt_img::nv p32, rxvt_img::nv p33) INIT: rxvt_img::nv matrix[3][3] = { { p11, p12, p13 }, { p21, p22, p23 }, { p31, p32, p33 } }; C_ARGS: matrix rxvt_img * rxvt_img::scale (int new_width, int new_height) rxvt_img * rxvt_img::rotate (int x, int y, rxvt_img::nv phi) rxvt_img * rxvt_img::tint (SV *c) INIT: rxvt_screen screen; screen.set (THIS->d); rgba cc = parse_rgba (c, &screen); C_ARGS: cc rxvt_img * rxvt_img::shade (rxvt_img::nv factor) rxvt_img * rxvt_img::filter (octet_string name, SV *params = &PL_sv_undef) CODE: rxvt_img::nv *vparams = 0; int nparams = 0; if (SvOK (params)) { if (!SvROK (params) || SvTYPE (SvRV (params)) != SVt_PVAV) croak ("rxvt_img::filter: params must be an array reference with parameter values"); nparams = av_len ((AV *)SvRV (params)) + 1; vparams = (rxvt_img::nv *)malloc (nparams * sizeof (rxvt_img::nv)); for (int i = 0; i < nparams; ++i) vparams [i] = SvNV (*av_fetch ((AV *)SvRV (params), i, 1)); } RETVAL = THIS->filter (name, nparams, vparams); free (vparams); OUTPUT: RETVAL #endif