]> git.mxchange.org Git - flightgear.git/commitdiff
add _setlistener() function, so that slow property polling loops can be
authormfranz <mfranz>
Fri, 16 Dec 2005 19:11:03 +0000 (19:11 +0000)
committermfranz <mfranz>
Fri, 16 Dec 2005 19:11:03 +0000 (19:11 +0000)
replaced with efficient listener callbacks. One use is the new FPS display.
This is reviewed and OK'ed by Andy, relatively trivial and separated from
the rest of Nasal, so problems are quite unlikely and confined to users of
this function.

The callback is executed whenever the property is written to -- even if
the value didn't change. The triggering Node is available via cmdarg().

Examples:  _setlistener("/sim/crashed", func {print("haha!")});
           _setlistener("/foo/bar", func { print(cmdarg().getPath() ~ " changed")})

src/Scripting/NasalSys.cxx
src/Scripting/NasalSys.hxx

index 870d6def1455f0831e095243af62223d333bb799..53b9f835728aa058df89fb51b76ea2a004a72ce3 100644 (file)
@@ -234,6 +234,15 @@ static naRef f_settimer(naContext c, naRef me, int argc, naRef* args)
     return naNil();
 }
 
+// setlistener(func, property) extension function.  Falls through to
+// FGNasalSys::setListener().  See there for docs.
+static naRef f_setlistener(naContext c, naRef me, int argc, naRef* args)
+{
+    FGNasalSys* nasal = (FGNasalSys*)globals->get_subsystem("nasal");
+    nasal->setListener(argc, args);
+    return naNil();
+}
+
 // Returns a ghost handle to the argument to the currently executing
 // command
 static naRef f_cmdarg(naContext c, naRef me, int argc, naRef* args)
@@ -285,6 +294,7 @@ static struct { char* name; naCFunction func; } funcs[] = {
     { "print",     f_print },
     { "_fgcommand", f_fgcommand },
     { "settimer",  f_settimer },
+    { "_setlistener", f_setlistener },
     { "_cmdarg",  f_cmdarg },
     { "_interpolate",  f_interpolate },
     { "rand",  f_rand },
@@ -553,3 +563,22 @@ void FGNasalSys::NasalTimer::timerExpired()
     nasal->handleTimer(this);
     delete this;
 }
+
+// setlistener(property, func) extension function.  The first argument
+// is either a ghost (SGPropertyNode_ptr*) or a string (global property
+// path), the second is a Nasal function.
+void FGNasalSys::setListener(int argc, naRef* args)
+{
+    SGPropertyNode* node;
+    naRef prop = argc > 0 ? args[0] : naNil();
+    if(naIsString(prop)) node = fgGetNode(naStr_data(prop), true);
+    else if(naIsGhost(prop)) node = *(SGPropertyNode_ptr*)naGhost_ptr(prop);
+    else return;
+
+    naRef handler = argc > 1 ? args[1] : naNil();
+    if(!(naIsCode(handler) || naIsCCode(handler) || naIsFunc(handler)))
+        return;
+
+    node->addChangeListener(new FGNasalListener(handler, this, gcSave(handler)));
+}
+
index 4d59b8b2c8aa2908813dcbf14c610719affdd7dc..f3e756b5914cf03fe24c2421e46b9a0cd7f36fdd 100644 (file)
@@ -36,6 +36,9 @@ public:
     // Implementation of the settimer extension function
     void setTimer(int argc, naRef* args);
 
+    // Implementation of the setlistener extension function
+    void setListener(int argc, naRef* args);
+
     // Returns a ghost wrapper for the current _cmdArg
     naRef cmdArgGhost();
     
@@ -47,6 +50,7 @@ public:
 
 private:
     friend class FGNasalScript;
+    friend class FGNasalListener;
 
     //
     // FGTimer subclass for handling Nasal timer callbacks.
@@ -103,4 +107,23 @@ private:
     FGNasalSys* _nas;
 };
 
+class FGNasalListener : public SGPropertyChangeListener {
+public:
+    FGNasalListener(naRef handler, FGNasalSys* nasal, int gcKey)
+            : _handler(handler), _gcKey(gcKey), _nas(nasal) {}
+
+    void valueChanged(SGPropertyNode* node) {
+        _nas->_cmdArg = node;
+        naCall(_nas->_context, _handler, 0, 0, naNil(), naNil());
+        if(naGetError(_nas->_context))
+            _nas->logError();
+    }
+
+private:
+    friend class FGNasalSys;
+    naRef _handler;
+    int _gcKey;
+    FGNasalSys* _nas;
+};
+
 #endif // __NASALSYS_HXX