Add-ons: small fixes to Nasal/addons.nas and Docs/README.add-ons
+ After discussion with Henning: - orig_setlistener() and orig_maketimer() were not intended to be public -> prefix the function names with an underscore; - clear the add-on's lists of tracked listeners and timers in remove() (load() does that too, but it's a bit late). + Little rewording in Docs/README.add-ons.
This commit is contained in:
parent
f3548c561e
commit
02b01af19e
2 changed files with 28 additions and 23 deletions
|
@ -840,13 +840,15 @@ Read-only data members (attributes) of addons.Maintainer objects:
|
|||
!!! We really don't want users to send bug reports due to reload going wrong.
|
||||
|
||||
To make development of add-ons less time consuming, you can reload the
|
||||
Nasal part of your add-on without having to restart FlightGear. The
|
||||
addons.nas module will track setlistener() and maketimer() calls for
|
||||
your add-on and remove listeners and stop timers on reload for you (the
|
||||
add-on's own namespace, has setlistener() and maketimer() wrappers that
|
||||
shadow and call themselves the standard setlistener() and maketimer()
|
||||
functions).
|
||||
|
||||
Nasal part of your add-on without having to restart FlightGear. When an
|
||||
add-on is loaded, setlistener() and maketimer() wrappers are installed
|
||||
in the add-on's own namespace; these wrappers shadow and call themselves
|
||||
the standard setlistener() and maketimer() functions. The setlistener()
|
||||
and maketimer() wrapper functions keep track of every listener and timer
|
||||
they create. When the add-on is removed (e.g., as part of its reload
|
||||
sequence), removelistener() is called for each of these listeners, and
|
||||
each timer has its stop() method called.
|
||||
_
|
||||
For the time being, you have to track any other resources outside the
|
||||
namespace of your add-on by yourself and clean them up in the unload()
|
||||
function, e.g. delete canvas or close any files you opened.
|
||||
|
@ -855,14 +857,15 @@ You can define this unload() function in the addon-main.nas file. When
|
|||
your add-on is reloaded, its unload() function, if defined, will be
|
||||
called with one argument: the addons.Addon object (a Nasal ghost)
|
||||
corresponding to your add-on. unload() is run in the add-on's own
|
||||
namespace, therefore it sees the aforementioned setlistener() and
|
||||
maketimer() wrapper functions.
|
||||
namespace.
|
||||
|
||||
The reload is triggered by setting /addon/by-id/yourAddonIDhere/reload
|
||||
to true. A listener will react to that property, reset it to false and
|
||||
attempt to reload the Nasal file (doing the cleanup before). You can add
|
||||
a menu item to trigger the reload easily, but this should be removed
|
||||
before publishing your add-on to users.
|
||||
The reload is triggered by setting the property
|
||||
/addon/by-id/ADDON_ID/reload to true (replace ADDON_ID with your
|
||||
particular add-on identifier). A listener will react to that property,
|
||||
reset it to false and attempt to reload the addon-main.nas file for your
|
||||
add-on (doing the aforementioned cleanup before). You can add a menu
|
||||
item to trigger the reload easily, but it should be removed before
|
||||
publishing your add-on to users (see the above warning).
|
||||
|
||||
Please have a look at the skeleton add-on at
|
||||
https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Addons/Skeleton/
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
# hashes to store listeners and timers per addon ID
|
||||
var _listeners = {};
|
||||
var _timers = {};
|
||||
var orig_setlistener = nil;
|
||||
var orig_maketimer = nil;
|
||||
var _orig_setlistener = nil;
|
||||
var _orig_maketimer = nil;
|
||||
|
||||
var getNamespaceName = func(a) {
|
||||
return "__addon[" ~ a.id ~ "]__";
|
||||
|
@ -61,16 +61,16 @@ var load = func(a) {
|
|||
p = p.getAliasTarget();
|
||||
}
|
||||
}
|
||||
append(_listeners[a.id], orig_setlistener(p, f, start, runtime));
|
||||
append(_listeners[a.id], _orig_setlistener(p, f, start, runtime));
|
||||
print("#listeners for " ~ a.id ~ " " ~ size(_listeners[a.id]));
|
||||
}
|
||||
|
||||
# redirect maketimer for addon
|
||||
globals[namespace].maketimer = func() {
|
||||
if (size(arg) == 2) {
|
||||
append(_timers[a.id], orig_maketimer(arg[0], arg[1]));
|
||||
append(_timers[a.id], _orig_maketimer(arg[0], arg[1]));
|
||||
} elsif (size(arg) == 3) {
|
||||
append(_timers[a.id], orig_maketimer(arg[0], arg[1], arg[2]));
|
||||
append(_timers[a.id], _orig_maketimer(arg[0], arg[1], arg[2]));
|
||||
} else {
|
||||
print("Invalid number of arguments to maketimer()");
|
||||
return;
|
||||
|
@ -107,17 +107,19 @@ var remove = func(a) {
|
|||
print("- Removing ", a.id);
|
||||
var namespace = getNamespaceName(a);
|
||||
foreach (var id; _listeners[a.id]) {
|
||||
print(" Remove listener " ~ id);
|
||||
print(" Removing listener " ~ id);
|
||||
removelistener(id);
|
||||
}
|
||||
_listeners[a.id] = [];
|
||||
|
||||
print(" Stopping timers ");
|
||||
foreach (var t; _timers[a.id]) {
|
||||
if (typeof(t.stop) == "func") {
|
||||
t.stop();
|
||||
print(".");
|
||||
print(" .");
|
||||
}
|
||||
}
|
||||
_timers[a.id] = [];
|
||||
|
||||
# call clean up method if available
|
||||
# addon shall release resources not handled by addon framework
|
||||
|
@ -154,7 +156,7 @@ var init = func {
|
|||
|
||||
var id = _setlistener("/sim/signals/fdm-initialized", func {
|
||||
removelistener(id);
|
||||
orig_setlistener = setlistener;
|
||||
orig_maketimer = maketimer;
|
||||
_orig_setlistener = setlistener;
|
||||
_orig_maketimer = maketimer;
|
||||
addons.init();
|
||||
})
|
||||
|
|
Loading…
Add table
Reference in a new issue