ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvtperl.xs
Revision: 1.76
Committed: Thu Jan 19 11:56:00 2006 UTC (18 years, 5 months ago) by root
Branch: MAIN
Changes since 1.75: +42 -31 lines
Log Message:
*** empty log message ***

File Contents

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