[beast: 7/31] BSE: introduce Bse::Object IDL type, tied to BseObject



commit d2d16a64097f934453abf425acdf3cc266ba635e
Author: Tim Janik <timj gnu org>
Date:   Fri Jun 12 03:43:28 2015 +0200

    BSE: introduce Bse::Object IDL type, tied to BseObject

 beast-gtk/bstmain.cc |    5 +++-
 bse/bseapi.idl       |    9 ++++++-
 bse/bseobject.cc     |   63 +++++++++++++++++++++++++++++++++++++++++++++++--
 bse/bseobject.hh     |   49 +++++++++++++++++++++++++++++++++++---
 bse/bseserver.cc     |   21 +++++++++++++---
 bse/bseserver.hh     |    7 +++--
 6 files changed, 138 insertions(+), 16 deletions(-)
---
diff --git a/beast-gtk/bstmain.cc b/beast-gtk/bstmain.cc
index eec1c84..737dfcf 100644
--- a/beast-gtk/bstmain.cc
+++ b/beast-gtk/bstmain.cc
@@ -440,14 +440,17 @@ bst_init_aida_idl()
   // connect to BSE thread and fetch server handle
   bse_server = Rapicorn::Aida::ObjectBroker::connect<Bse::ServerH> ("inproc://BSE-" BST_VERSION);
   assert (bse_server != NULL);
+  assert (bse_server.proxy_id() == BSE_SERVER);
+  assert (bse_server.from_proxy (BSE_SERVER) == bse_server);
   // hook Aida connection into our main loop
   Bse::AidaGlibSource *source = Bse::AidaGlibSource::create (Bse::ServerH::__aida_connection__());
   g_source_set_priority (source, G_PRIORITY_DEFAULT);
   g_source_attach (source, g_main_context_default());
 
-  // performa Bse Aida test
+  // perform Bse Aida tests
   if (0)
     {
+      Rapicorn::printerr ("bse_server: %s\n", bse_server.debug_name());
       Bse::TestObjectH test = bse_server.get_test_object();
       test.sig_echo_reply() += echo_test_handler;
       const int test_result = test.echo_test ("foo");
diff --git a/bse/bseapi.idl b/bse/bseapi.idl
index 0206d4a..0f508bf 100644
--- a/bse/bseapi.idl
+++ b/bse/bseapi.idl
@@ -6,6 +6,12 @@
 
 namespace Bse {
 
+/// Basic object type for all BSE objects.
+interface Object {
+  String debug_name () = 0;     ///< Object name useful for debugging output.
+  int64  proxy_id   () = 0;     ///< Retrieve the BseObject proxy ID for an Object.
+};
+
 /// Object to carry out IDL, API, signal, etc tests.
 interface TestObject {
   int32         echo_test       (String msg) = 0;       ///< Echo custom message to stdout.
@@ -33,9 +39,10 @@ record UserMessage {
  * The Bse::Server object controls the main BSE thread and keeps track of all objects
  * used in the BSE context.
  */
-interface Server {
+interface Server : Object {
   signal void   user_message    (UserMessage umsg);     ///< Notification signal for user messages from BSE.
   TestObject    get_test_object () = 0;                 ///< Retrieve object for API, signal, etc tests.
+  Object        from_proxy      (int64 proxyid) = 0;    ///< Find an Object from its associated BseObject 
proxy id.
 };
 
 } // Bse
diff --git a/bse/bseobject.cc b/bse/bseobject.cc
index 6fdc414..28a3d14 100644
--- a/bse/bseobject.cc
+++ b/bse/bseobject.cc
@@ -11,6 +11,40 @@
 
 #define LDEBUG(...)     BSE_KEY_DEBUG ("leaks", __VA_ARGS__)
 
+namespace Bse {
+ObjectImpl::ObjectImpl (BseObject *bobj) :
+  gobject_ (bobj)
+{
+  assert (gobject_);
+  assert (gobject_->cxxobject_ == NULL);
+  g_object_ref (gobject_);
+  gobject_->cxxobject_ = this;
+}
+
+ObjectImpl::~ObjectImpl ()
+{
+  assert (gobject_->cxxobject_ == this);
+  gobject_->cxxobject_ = NULL;
+  g_object_unref (gobject_);
+  // ObjectImpl keeps BseObject alive until it is destroyed
+  // BseObject keeps ObjectImpl alive until dispose()
+}
+
+std::string
+ObjectImpl::debug_name ()
+{
+  return bse_object_debug_name (this->as<BseObject*>());
+}
+
+int64_t
+ObjectImpl::proxy_id ()
+{
+  BseObject *bo = *this;
+  return bo->unique_id;
+}
+
+} // Bse
+
 enum
 {
   PROP_0,
@@ -126,6 +160,8 @@ static void
 bse_object_init (BseObject *object)
 {
   assert (in_bse_object_new);
+  object->cxxobject_ = NULL;
+  object->cxxobjref_ = NULL;
   object->flags = 0;
   object->lock_count = 0;
   object->unique_id = bse_id_alloc ();
@@ -165,6 +201,13 @@ bse_object_do_dispose (GObject *gobject)
   G_OBJECT_CLASS (parent_class)->dispose (gobject);
 
   BSE_OBJECT_UNSET_FLAGS (object, BSE_OBJECT_FLAG_DISPOSING);
+
+  if (object->cxxobjref_)
+    {
+      object->cxxobjref_->reset();
+      delete object->cxxobjref_;
+      object->cxxobjref_ = NULL;
+    }
 }
 
 static void
@@ -447,10 +490,10 @@ bse_object_unlock (gpointer _object)
     }
 }
 
-gpointer
+BseObject*
 bse_object_from_id (guint unique_id)
 {
-  return sfi_ustore_lookup (object_id_ustore, unique_id);
+  return (BseObject*) sfi_ustore_lookup (object_id_ustore, unique_id);
 }
 
 GList*
@@ -872,11 +915,25 @@ bse_object_new (GType object_type, const gchar *first_property_name, ...)
   return object;
 }
 
+#include "bseserver.hh"
+
 GObject*
 bse_object_new_valist (GType object_type, const gchar *first_property_name, va_list var_args)
 {
   in_bse_object_new++;
-  GObject *object = g_object_new_valist (object_type, first_property_name, var_args);
+  BseObject *object = (BseObject*) g_object_new_valist (object_type, first_property_name, var_args);
   in_bse_object_new--;
+  assert (object->cxxobject_ == NULL);
+  assert (object->cxxobjref_ == NULL);
+  Bse::ObjectImpl *cxxo;
+  if      (object_type == BSE_TYPE_SERVER)
+    cxxo = new Bse::ServerImpl (object);
+  else //  object_type == BSE_TYPE_OBJECT
+    cxxo = new Bse::ObjectImpl (object);
+  assert (object->cxxobject_ == cxxo);
+  assert (object->cxxobjref_ == NULL);
+  object->cxxobjref_ = new Bse::ObjectImplP (cxxo); // shared_ptr that allows enable_shared_from_this
+  assert (cxxo == *object);
+  assert (object == *cxxo);
   return object;
 }
diff --git a/bse/bseobject.hh b/bse/bseobject.hh
index 80c79d2..dbfaf6f 100644
--- a/bse/bseobject.hh
+++ b/bse/bseobject.hh
@@ -4,6 +4,30 @@
 
 #include       <bse/bseparam.hh>
 
+namespace Bse {
+
+class ObjectImpl : public virtual ObjectIface {
+  BseObject             *gobject_;
+public:
+  explicit               ObjectImpl (BseObject*);
+  virtual               ~ObjectImpl ();
+  virtual std::string    debug_name () override;
+  virtual int64_t        proxy_id   () override;
+  operator               BseObject* ()          { return gobject_; }
+  template<class BseObjectPtr>
+  BseObjectPtr           as ()
+  {
+    static_assert (std::is_pointer<BseObjectPtr>::value, "");
+    typedef typename std::remove_pointer<BseObjectPtr>::type BseObjectT;
+    static_assert (std::is_base_of<GObject, BseObjectT>::value, "");
+    return (BseObjectPtr) gobject_;
+  }
+};
+typedef std::shared_ptr<ObjectImpl> ObjectImplP;
+
+} // Bse
+
+
 G_BEGIN_DECLS
 
 /* --- BSE type macros --- */
@@ -35,12 +59,29 @@ typedef enum                                /*< skip >*/
 } BseObjectFlags;
 #define BSE_OBJECT_FLAGS_USHIFT            (3)
 #define BSE_OBJECT_FLAGS_MAX_SHIFT  (16)
+
+G_END_DECLS // BseObject templates need C++ linkage
+
 /* --- typedefs & structures --- */
 struct BseObject : GObject {
-  guint16               flags;
-  guint16               lock_count;
-  guint                         unique_id;
+  Bse::ObjectImpl       *cxxobject_;
+  Bse::ObjectImplP      *cxxobjref_; // shared_ptr that keeps a reference on cxxobject_ until dispose()
+  guint16               flags;
+  guint16               lock_count;
+  guint                         unique_id;
+  operator               Bse::ObjectImpl* ()          { return cxxobject_; }
+  template<class ObjectImplPtr>
+  ObjectImplPtr          as ()
+  {
+    static_assert (std::is_pointer<ObjectImplPtr>::value, "");
+    typedef typename std::remove_pointer<ObjectImplPtr>::type ObjectImplT;
+    static_assert (std::is_base_of<Rapicorn::Aida::ImplicitBase, ObjectImplT>::value, "");
+    return dynamic_cast<ObjectImplPtr> (cxxobject_);
+  }
 };
+
+G_BEGIN_DECLS // BseObject templates need C++ linkage
+
 struct BseObjectClass : GObjectClass {
   gboolean              (*editable_property)    (BseObject      *object, /* for set_property/get_property 
implementations */
                                                  guint           param_id,
@@ -100,7 +141,7 @@ gboolean        bse_object_editable_property        (gpointer        object,
                                                  const gchar    *property);
 BseIcon*       bse_object_get_icon             (BseObject      *object);
 void           bse_object_notify_icon_changed  (BseObject      *object);
-gpointer       bse_object_from_id              (guint           unique_id);
+BseObject*     bse_object_from_id              (guint           unique_id);
 GList*         bse_objects_list                (GType           type);
 GList*         bse_objects_list_by_uname       (GType           type,
                                                 const gchar    *uname);
diff --git a/bse/bseserver.cc b/bse/bseserver.cc
index 4590f10..49b4234 100644
--- a/bse/bseserver.cc
+++ b/bse/bseserver.cc
@@ -350,8 +350,12 @@ bse_server_get (void)
 
   if (!server)
     {
-      server = (BseServer*) bse_object_new (BSE_TYPE_SERVER, NULL);
+      server = (BseServer*) bse_object_new (BSE_TYPE_SERVER, "uname", "ServerImpl", NULL);
       g_object_ref (server);
+      assert (server);
+      assert (server->cxxobject_);
+      assert (dynamic_cast<Bse::ObjectImpl*> (server->cxxobject_));
+      assert (dynamic_cast<Bse::ServerImpl*> (server->cxxobject_));
     }
 
   return server;
@@ -1123,7 +1127,8 @@ engine_shutdown (BseServer *server)
 
 namespace Bse {
 
-ServerImpl::ServerImpl ()
+ServerImpl::ServerImpl (BseObject *bobj) :
+  ObjectImpl (bobj)
 {}
 
 ServerImpl::~ServerImpl ()
@@ -1137,11 +1142,19 @@ ServerImpl::get_test_object ()
   return test_object_;
 }
 
+ObjectIfaceP
+ServerImpl::from_proxy (int64_t proxyid)
+{
+  BseObject *bo = bse_object_from_id (proxyid);
+  if (!bo)
+    return ObjectIfaceP();
+  return shared_ptr_cast<ObjectIface> (bo->as<ObjectIface*>());
+}
+
 ServerImpl&
 ServerImpl::instance()
 {
-  static std::shared_ptr<ServerImpl> singleton = Rapicorn::FriendAllocator<ServerImpl>::make_shared();
-  return *singleton;
+  return *bse_server_get()->as<ServerImpl*>();
 }
 
 void
diff --git a/bse/bseserver.hh b/bse/bseserver.hh
index ceb6819..5a6be2c 100644
--- a/bse/bseserver.hh
+++ b/bse/bseserver.hh
@@ -98,16 +98,17 @@ G_END_DECLS
 
 namespace Bse {
 
-class ServerImpl : public ServerIface {
+class ServerImpl : public virtual ServerIface, public virtual ObjectImpl {
   TestObjectImplP    test_object_;
   friend class FriendAllocator<ServerImpl>;     // provide make_shared for non-public ctor
 protected:
-  explicit           ServerImpl ();
   virtual           ~ServerImpl ();
 public:
-  virtual TestObjectIfaceP get_test_object ();
+  explicit                 ServerImpl      (BseObject*);
+  virtual TestObjectIfaceP get_test_object () override;
   static ServerImpl&       instance        ();
   void                     send_user_message (const UserMessage &umsg);
+  virtual ObjectIfaceP     from_proxy      (int64_t proxyid) override;
 };
 
 } // Bse


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]