# Copyright (c) 2017, Mitchell Cooper
# default event responders
package Evented::API::Events;
use warnings;
use strict;
use 5.010;
use Evented::Object;
use parent 'Evented::Object';
use Scalar::Util qw(blessed weaken);
use Evented::Object::Hax qw(set_symbol);
our $VERSION = '4.13';
sub add_events {
my $mod = shift;
# default initialize handler
$mod->on(init => \&mod_default_init,
name => 'api.engine.initSubroutine',
priority => 100,
with_eo => 1
);
# default void handler
$mod->on(void => \&mod_default_void,
name => 'api.engine.voidSubroutine',
priority => 100,
with_eo => 1
);
# default variable exports
$mod->on(set_variables =>
\&mod_default_set_variables, 'api.engine.setVariables');
# make the module a class monitor of each package
Evented::Object::add_class_monitor($_, $mod) for $mod->packages;
# registered a callback
$mod->on('monitor:register_callback' =>
\&mod_event_registered, 'api.engine.eventTracker.register');
# deleted all callbacks for an event
$mod->on('monitor:delete_event' =>
\&mod_event_deleted, 'api.engine.eventTracker.deleteEvent');
# deleted a specific callback
$mod->on('monitor:delete_callback' =>
\&mod_callback_deleted, 'api.engine.eventTracker.deleteCallback');
# module unloaded
$mod->on(unload => \&mod_unloaded,
'api.engine.eventTracker.unload');
}
# on init, call module's ->init()
sub mod_default_init {
my $mod = shift;
my $init = $mod->package->can('init') or return 1;
return $init->(@_);
}
# on void, call module's ->void()
sub mod_default_void {
my $mod = shift;
my $void = $mod->package->can('void') or return 1;
return $void->(@_);
}
# on variable set, export the API Engine, module, and module version
sub mod_default_set_variables {
my $mod = shift;
set_symbol($mod->package, {
'$api' => $mod->api,
'$mod' => $mod,
'$VERSION' => $mod->{version}
});
}
# on event register, add to managed event list
sub mod_event_registered {
my ($mod, $fire, $eo, $event_name, $cb) = @_;
my $ref = ref $eo;
# permanent (not managed)
if ($cb->{permanent}) {
$mod->Debug("Permanent event: $event_name ($$cb{name}) registered to $ref");
return;
}
# store eo, event, and cb name
# hold weak reference to eo
my $e = [ $eo, $event_name, $cb->{name} ];
weaken($e->[0]);
$mod->list_store_add('managed_events', $e);
$mod->Debug("Event: $event_name ($$cb{name}) registered to $ref");
}
# on event delete, remove from managed event list
sub mod_event_deleted {
my ($mod, $fire, $eo, $event_name) = @_;
my $ref = ref $eo;
$mod->Debug("Event: $event_name (all callbacks) deleted from $ref");
$mod->list_store_remove_matches('managed_events', sub {
my $e = shift;
return 1 if not defined $e->[0]; # disposed, delete
return unless $eo == $e->[0]; # wrong eo
return unless $event_name eq $e->[1]; # wrong event
return 1; # match, delete
});
}
# on callback delete, remove from managed event list
sub mod_callback_deleted {
my ($mod, $fire, $eo, $event_name, $cb_name) = @_;
my $ref = ref $eo;
$mod->Debug("Event: $event_name ($cb_name) deleted from $ref");
$mod->list_store_remove_matches('managed_events', sub {
my $e = shift;
return 1 if !$e->[0]; # disposed, delete
return unless $eo == $e->[0]; # wrong eo
return unless $event_name eq $e->[1]; # wrong event
return unless $cb_name eq $e->[2]; # wrong cb name
return 1; # match, delete
}, 1);
}
# on module unload, delete managed events
sub mod_unloaded {
my $mod = shift;
my $indented;
foreach my $e ($mod->list_store_items('managed_events')) {
my ($eo, $event_name, $name) = @$e;
my $ref = ref $eo;
# this is a weak reference --
# if undefined, it was disposed of
return unless $eo;
# first one
if (!$indented) {
$mod->Debug('Destroying managed event callbacks');
$mod->api->{indent}++;
$indented++;
}
# delete this callback
$eo->delete_callback($event_name, $name);
$mod->Debug("Event: $event_name ($name) deleted from $ref");
}
$mod->api->{indent}-- if $indented;
return 1;
}
1