Chandra
view release on metacpan or search on metacpan
xs/shortcut.xs view on Meta::CPAN
/* Validate combo */
if (!SvOK(combo_sv)) {
croak("bind() requires a combo string");
}
/* Parse optional %opts */
for (i = 3; i + 1 < items; i += 2) {
const char *key = SvPV_nolen(ST(i));
if (strEQ(key, "prevent_default")) {
prevent_default = SvIV(ST(i + 1));
}
}
/* Normalize combo */
{
dSP;
int count;
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(self);
XPUSHs(combo_sv);
PUTBACK;
count = call_method("_normalize_combo", G_SCALAR);
SPAGAIN;
norm_combo = (count > 0) ? newSVsv(POPs) : newSVsv(combo_sv);
PUTBACK;
FREETMPS; LEAVE;
}
norm_str = SvPV(norm_combo, norm_len);
/* Create entry: { handler, enabled, prevent_default } */
entry_hv = newHV();
(void)hv_stores(entry_hv, "handler", newSVsv(handler));
(void)hv_stores(entry_hv, "enabled", newSViv(1));
(void)hv_stores(entry_hv, "prevent_default", newSViv(prevent_default));
(void)hv_stores(entry_hv, "combo", newSVsv(norm_combo));
/* Store in bindings hash */
bindings_svp = hv_fetchs(hv, "bindings", 0);
if (bindings_svp && SvROK(*bindings_svp)) {
bindings_hv = (HV *)SvRV(*bindings_svp);
} else {
bindings_hv = newHV();
(void)hv_stores(hv, "bindings", newRV_noinc((SV *)bindings_hv));
}
(void)hv_store(bindings_hv, norm_str, norm_len,
newRV_noinc((SV *)entry_hv), 0);
/* Bind __chandra_shortcut dispatch if not already done */
{
SV **db_svp = hv_fetchs(hv, "_dispatch_bound", 0);
if (!db_svp || !SvIV(*db_svp)) {
SV **app_svp = hv_fetchs(hv, "app", 0);
if (app_svp && SvOK(*app_svp)) {
/* Create dispatch callback that references self */
CV *wrapper_cv;
SV *self_ref;
self_ref = newSVsv(self);
sv_rvweaken(self_ref); /* weak ref to avoid circular */
wrapper_cv = newXS(NULL, xs_shortcut_dispatch_callback, __FILE__);
CvXSUBANY(wrapper_cv).any_ptr = (void *)self_ref;
{
dSP;
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(*app_svp);
XPUSHs(sv_2mortal(newSVpvs("__chandra_shortcut")));
XPUSHs(sv_2mortal(newRV_noinc((SV *)wrapper_cv)));
PUTBACK;
call_method("bind", G_DISCARD);
FREETMPS; LEAVE;
}
(void)hv_stores(hv, "_dispatch_bound", newSViv(1));
}
}
}
SvREFCNT_dec(norm_combo);
RETVAL = SvREFCNT_inc(self);
}
OUTPUT:
RETVAL
# ---- unbind($combo) ----
SV *
unbind(self, combo_sv)
SV *self
SV *combo_sv
CODE:
{
HV *hv = (HV *)SvRV(self);
SV **bindings_svp;
SV *norm_combo;
const char *norm_str;
STRLEN norm_len;
/* Normalize combo */
{
dSP;
int count;
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(self);
XPUSHs(combo_sv);
PUTBACK;
count = call_method("_normalize_combo", G_SCALAR);
SPAGAIN;
norm_combo = (count > 0) ? newSVsv(POPs) : newSVsv(combo_sv);
PUTBACK;
FREETMPS; LEAVE;
}
norm_str = SvPV(norm_combo, norm_len);
bindings_svp = hv_fetchs(hv, "bindings", 0);
( run in 1.690 second using v1.01-cache-2.11-cpan-364913b4093 )