From d51499382dc93a8b878e3de795a4471f4ce877ec Mon Sep 17 00:00:00 2001
From: Thomas Geymayer <tomgey@gmail.com>
Date: Sun, 18 Nov 2012 16:38:35 +0100
Subject: [PATCH] Clean up CanvasWidget and more work on Canvas/Nasal bindings

---
 src/GUI/CanvasWidget.cxx      | 104 +++++++++++++++++-----------------
 src/GUI/CanvasWidget.hxx      |   4 +-
 src/Main/CMakeLists.txt       |   2 +-
 src/Scripting/NasalCanvas.cxx |  56 +++++++++++++++++-
 4 files changed, 110 insertions(+), 56 deletions(-)

diff --git a/src/GUI/CanvasWidget.cxx b/src/GUI/CanvasWidget.cxx
index 1db2f9391..624ef1aca 100644
--- a/src/GUI/CanvasWidget.cxx
+++ b/src/GUI/CanvasWidget.cxx
@@ -15,6 +15,8 @@
 #include <Main/fg_os.hxx>      // fgGetKeyModifiers()
 #include <Scripting/NasalSys.hxx>
 
+#include <simgear/canvas/Canvas.hxx>
+
 //------------------------------------------------------------------------------
 CanvasWidget::CanvasWidget( int x, int y,
                             int width, int height,
@@ -31,53 +33,49 @@ CanvasWidget::CanvasWidget( int x, int y,
     return;
   }
 
-  // Get the first unused canvas slot
-  SGPropertyNode* canvas_root = fgGetNode("/canvas/by-index", true);
-  for(int index = 0;; ++index)
+  _canvas = _canvas_mgr->createCanvas
+  (
+    props->getStringValue("name", "gui-anonymous")
+  );
+
+  int view[2] = {
+    // Get canvas viewport size. If not specified use the widget dimensions
+    props->getIntValue("view[0]", width),
+    props->getIntValue("view[1]", height)
+  };
+
+  SGPropertyNode* cprops = _canvas->getProps();
+  cprops->setIntValue("size[0]", view[0] * 2); // use higher resolution
+  cprops->setIntValue("size[1]", view[1] * 2); // for antialias
+  cprops->setIntValue("view[0]", view[0]);
+  cprops->setIntValue("view[1]", view[1]);
+  cprops->setBoolValue("render-always", true);
+  cprops->setStringValue( "name",
+                           props->getStringValue("name", "gui-anonymous") );
+  SGPropertyNode* input = cprops->getChild("input", 0, true);
+  _mouse_x = input->getChild("mouse-x", 0, true);
+  _mouse_y = input->getChild("mouse-y", 0, true);
+  _mouse_down = input->getChild("mouse-down", 0, true);
+  _mouse_drag = input->getChild("mouse-drag", 0, true);
+
+  SGPropertyNode *nasal = props->getNode("nasal");
+  if( !nasal )
+    return;
+
+  FGNasalSys *nas = dynamic_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
+  if( !nas )
+    SG_LOG( SG_GENERAL,
+            SG_ALERT,
+            "CanvasWidget: Failed to get nasal subsystem!" );
+
+  const std::string file = std::string("__canvas:")
+                         + cprops->getStringValue("name");
+
+  SGPropertyNode *load = nasal->getNode("load");
+  if( load )
   {
-    if( !canvas_root->getChild("texture", index) )
-    {
-      int view[2] = {
-        // Get canvas viewport size. If not specified use the widget dimensions
-        props->getIntValue("view[0]", width),
-        props->getIntValue("view[1]", height)
-      };
-      _canvas = canvas_root->getChild("texture", index, true);
-      _canvas->setIntValue("size[0]", view[0] * 2); // use higher resolution
-      _canvas->setIntValue("size[1]", view[1] * 2); // for antialias
-      _canvas->setIntValue("view[0]", view[0]);
-      _canvas->setIntValue("view[1]", view[1]);
-      _canvas->setBoolValue("render-always", true);
-      _canvas->setStringValue( "name",
-                               props->getStringValue("name", "gui-anonymous") );
-      SGPropertyNode* input = _canvas->getChild("input", 0, true);
-      _mouse_x = input->getChild("mouse-x", 0, true);
-      _mouse_y = input->getChild("mouse-y", 0, true);
-      _mouse_down = input->getChild("mouse-down", 0, true);
-      _mouse_drag = input->getChild("mouse-drag", 0, true);
-
-      SGPropertyNode *nasal = props->getNode("nasal");
-      if( !nasal )
-        break;
-
-      FGNasalSys *nas =
-        dynamic_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
-      if( !nas )
-        SG_LOG( SG_GENERAL,
-                SG_ALERT,
-                "CanvasWidget: Failed to get nasal subsystem!" );
-
-      const std::string file = std::string("__canvas:")
-                             + _canvas->getStringValue("name");
-
-      SGPropertyNode *load = nasal->getNode("load");
-      if( load )
-      {
-        const char *s = load->getStringValue();
-        nas->handleCommand(module.c_str(), file.c_str(), s, _canvas);
-      }
-      break;
-    }
+    const char *s = load->getStringValue();
+    nas->handleCommand(module.c_str(), file.c_str(), s, cprops);
   }
 }
 
@@ -85,8 +83,12 @@ CanvasWidget::CanvasWidget( int x, int y,
 CanvasWidget::~CanvasWidget()
 {
   if( _canvas )
-    _canvas->getParent()
-           ->removeChild(_canvas->getName(), _canvas->getIndex(), false);
+    // TODO check if really not in use anymore
+    _canvas->getProps()
+           ->getParent()
+           ->removeChild( _canvas->getProps()->getName(),
+                          _canvas->getProps()->getIndex(),
+                          false );
 }
 
 //------------------------------------------------------------------------------
@@ -126,8 +128,8 @@ void CanvasWidget::setSize(int w, int h)
 {
   puObject::setSize(w, h);
 
-  _canvas->setIntValue("view[0]", w);
-  _canvas->setIntValue("view[1]", h);
+  _canvas->getProps()->setIntValue("view[0]", w);
+  _canvas->getProps()->setIntValue("view[1]", h);
 }
 
 //------------------------------------------------------------------------------
@@ -135,7 +137,7 @@ void CanvasWidget::draw(int dx, int dy)
 {
   if( !_tex_id )
   {
-    _tex_id = _canvas_mgr->getCanvasTexId(_canvas->getIndex());
+    _tex_id = _canvas_mgr->getCanvasTexId( _canvas->getProps()->getIndex() );
 
     // Normally we should be able to get the texture after one frame. I don't
     // know if there are circumstances where it can take longer, so we don't
diff --git a/src/GUI/CanvasWidget.hxx b/src/GUI/CanvasWidget.hxx
index 7f4552cd1..3297eafc1 100644
--- a/src/GUI/CanvasWidget.hxx
+++ b/src/GUI/CanvasWidget.hxx
@@ -11,6 +11,8 @@
 #include <Main/fg_props.hxx>
 #include <plib/pu.h>
 
+#include <simgear/canvas/canvas_fwd.hxx>
+
 class CanvasMgr;
 
 class CanvasWidget:
@@ -37,7 +39,7 @@ class CanvasWidget:
     GLuint              _tex_id;    //<! OpenGL texture id if canvas
     size_t              _no_tex_cnt;//<! Count since how many frames we were not
                                     //   able to get the texture (for debugging)
-    SGPropertyNode_ptr  _canvas;    //<! Canvas root property node
+    simgear::canvas::CanvasPtr _canvas;
     SGPropertyNode     *_mouse_x,
                        *_mouse_y,
                        *_mouse_down,
diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt
index 259b51132..b6e00a208 100644
--- a/src/Main/CMakeLists.txt
+++ b/src/Main/CMakeLists.txt
@@ -91,7 +91,7 @@ if(ENABLE_JSBSIM)
 endif()
 
 if(FG_HAVE_GPERFTOOLS)
-    target_link_libraries(fgfs profiler)
+    target_link_libraries(fgfs profiler tcmalloc)
 endif()
 
 target_link_libraries(fgfs
diff --git a/src/Scripting/NasalCanvas.cxx b/src/Scripting/NasalCanvas.cxx
index 64875370a..204cfa682 100644
--- a/src/Scripting/NasalCanvas.cxx
+++ b/src/Scripting/NasalCanvas.cxx
@@ -25,6 +25,7 @@
 #include "NasalCanvas.hxx"
 #include <Canvas/canvas_mgr.hxx>
 #include <Main/globals.hxx>
+#include <Scripting/NasalSys.hxx>
 
 #include <osgGA/GUIEventAdapter>
 
@@ -86,14 +87,62 @@ class NasalCanvasEvent:
 };
 #endif
 
-static naRef f_createCanvas(naContext c, naRef me, int argc, naRef* args)
+SGPropertyNode& requireArg(naContext c, int argc, naRef* args, int index = 0)
+{
+  if( argc <= index )
+    naRuntimeError(c, "missing argument #%d", index);
+
+  SGPropertyNode* props = ghostToPropNode(args[index]);
+  if( !props )
+    naRuntimeError(c, "arg #%d: not a SGPropertyNode ghost");
+
+  return *props;
+}
+
+CanvasMgr& requireCanvasMgr(naContext c)
 {
   CanvasMgr* canvas_mgr =
     static_cast<CanvasMgr*>(globals->get_subsystem("Canvas"));
   if( !canvas_mgr )
-    return naNil();
+    naRuntimeError(c, "Failed to get Canvas subsystem");
 
-  return NasalCanvas::create(c, canvas_mgr->createCanvas());
+  return *canvas_mgr;
+}
+
+/**
+ * Create new Canvas and get ghost for it.
+ */
+static naRef f_createCanvas(naContext c, naRef me, int argc, naRef* args)
+{
+  return NasalCanvas::create(c, requireCanvasMgr(c).createCanvas());
+}
+
+/**
+ * Get ghost for existing Canvas.
+ */
+static naRef f_getCanvas(naContext c, naRef me, int argc, naRef* args)
+{
+  SGPropertyNode& props = requireArg(c, argc, args);
+  CanvasMgr& canvas_mgr = requireCanvasMgr(c);
+
+  sc::CanvasPtr canvas;
+  if( canvas_mgr.getPropertyRoot() == props.getParent() )
+  {
+    // get a canvas specified by its root node
+    canvas = canvas_mgr.getCanvas( props.getIndex() );
+    if( !canvas || canvas->getProps() != &props )
+      return naNil();
+  }
+  else
+  {
+    // get a canvas by name
+    if( props.hasValue("name") )
+      canvas = canvas_mgr.getCanvas( props.getStringValue("name") );
+    else if( props.hasValue("index") )
+      canvas = canvas_mgr.getCanvas( props.getIntValue("index") );
+  }
+
+  return NasalCanvas::create(c, canvas);
 }
 
 naRef f_canvasCreateGroup( sc::Canvas& canvas,
@@ -124,6 +173,7 @@ naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave)
               canvas_module = globals_module.createHash("canvas");
 
   canvas_module.set("_newCanvasGhost", f_createCanvas);
+  canvas_module.set("_getCanvasGhost", f_getCanvas);
 
   return naNil();
 }