Re: libglademm and signal autoconnect



Hello.

Murray Cumming пишет:
In this POC hack, only the void handlers are
supported. It might be easy to add anything
else though.
No, I don't think this is generically easy at all.
You knew it. :)

But I could be wrong
so don't let me stop you from exploring the idea further.
You actually tried to stop me in a much
more brutal way than this. :) Namely, you
(or someone else, nevermind) have not made
the dtor of sigc::slot_base virtual. So
most of the time I spent recompiling everything
(the trivial change of adding the "virtual"
keyword is binary-incompatible), but the
rest was easy. I simply templatized my
current code, and it now supports the
handlers of different types.
The example is hacked to demonstrate the
handler that takes the string as the
parameter.

I also find the current way (manually connecting a slot to a signal) not
much harder than your suggested way (manually registering a slot in a
My opinion is that the difference is by
an order of magnitude. Right now I have
to write the wrappers around every form.
I have to recall all the widgets that
emit the signal, I then have to recall
their corresponding slots, and write the
wrapper from here.
That's the first time I am trying out the
gtkmm-related stuff. What attracted me the
most (from the descriptions) is the fact
that it loads the GUI from XML dynamically,
and now, again, I faced with the need of
writing a static wrapper. In what way then
it is better than the systems that use
the C++ code generation? Except than it
is worse, as here I have to "generate"
the code by hands. :)
Well, it may just be me, but I dislike
the need of writing the wrappers. Registering
slots is not exactly a task of that kind.
To do that, I don't have to deal with an
XML object, with widgets, etc. And besides,
the old way of connecting the slots won't
disappear, so I think the autoconnection
functionality can be in some use.

"slots" object and providing that to an autoconnect function, even if it
could work).
I aim the autoconnect() functions for
compatibility only. Personally, I want
Gnome::Glade::Xml::create() to be overloaded
so to take the slots object as a parameter,
and autoconnect right away, without me even
asking to.

Note also that you'd still need to get the widget instance in order to
create a mem_fun() slot for a signal handler of that widget instance.
That's what I actually want to avoid.
Could you please clarify why would I still
need to get the widget instance? Right now
I am using mem_fun() and am passing a slots
object to it, not a widget object. Why
would I still need a widget object?

Attached are the 2 patches. Once you apply
the sigc++ patch, you'll need to recompile
everything... :(

So, any other remained showstoppers before
the autoconnection can be implemented?
Could you please suggest where should I
start looking into it? Should I iterate
the widget tree? If so - how?
--- sigc++/functors/slot_base.h	2008-02-26 22:44:34.000000000 +0300
+++ sigc++/functors/slot_base.h	2009-02-27 14:14:38.000000000 +0300
@@ -232,7 +232,7 @@
    */
   slot_base(const slot_base& src);
 
-  ~slot_base();
+  virtual ~slot_base();
 
   /** Tests whether a slot is null, because the default constructor was used.
    * Test a slot for null like so:
Index: libglade/src/xml.hg
===================================================================
--- libglade/src/xml.hg	(revision 2071)
+++ libglade/src/xml.hg	(working copy)
@@ -44,6 +44,116 @@
 };
 
 
+#define _STR(x) #x
+#define STR(x) _STR(x)
+#define GLADEMM_SLOT(n, s) __register_slot(STR(s), &n::s)
+#define GLADEMM_DECLARE_SLOTS(...) \
+virtual void __init_slots(void) \
+{ \
+    __VA_ARGS__; \
+}
+
+class NoSlotException : public Glib::Exception
+{
+public:
+  NoSlotException(const Glib::ustring& name) { str = name; }
+  virtual ~NoSlotException(void) throw() {}
+  virtual Glib::ustring what() const
+  {
+    return str;
+  }
+
+protected:
+  Glib::ustring str;
+};
+
+class Slots : public Glib::Object
+{
+public:
+
+  virtual ~Slots(void)
+  {
+    for (std::map<Glib::ustring, sigc::slot_base*>::iterator it =
+	    slot_map.begin(); it != slot_map.end(); it++) {
+	delete it->second;
+    }
+    slot_map.clear();
+  }
+
+  template <class T_class>
+  void get_slot(const Glib::ustring name, T_class *slotret)
+  {
+    if (slot_map.empty())
+	__init_slots();
+    std::map<Glib::ustring, sigc::slot_base*>::iterator it =
+	    slot_map.find(name);
+    if (it == slot_map.end())
+	throw NoSlotException(name);
+    T_class *sl = dynamic_cast<T_class*>(it->second);
+    if (!sl)
+	throw Glib::Error(g_quark_from_static_string("wrong_handler_type"), 0,
+		"Wrong handler type");
+    *slotret = *sl;
+  }
+
+protected:
+  virtual void __init_slots(void) = 0;
+  template <typename T_ret, class T_class>
+  void __register_slot(const Glib::ustring& name,
+	T_ret(T_class::*handler)(void))
+  {
+    T_class *self = dynamic_cast<T_class*>(this);
+    g_assert(self);
+    slot_map[name] = new sigc::slot<T_ret>(sigc::mem_fun(*self, handler));
+  }
+  template <typename T_ret, class T_class, typename T_arg>
+  void __register_slot(const Glib::ustring& name,
+	T_ret(T_class::*handler)(T_arg))
+  {
+    T_class *self = dynamic_cast<T_class*>(this);
+    g_assert(self);
+    slot_map[name] = new sigc::slot<T_ret, T_arg>(sigc::mem_fun(*self, handler));
+  }
+  std::map<Glib::ustring, sigc::slot_base*> slot_map;
+};
+
+/* getter templates, for convenience */
+class get_slot_void
+{
+public:
+  get_slot_void(Slots& slots_)
+  {
+    slots = &slots_;
+  }
+  sigc::slot<void> operator()(const Glib::ustring& name)
+  {
+    sigc::slot<void> slot;
+    slots->get_slot(name, &slot);
+    return slot;
+  }
+
+private:
+  Slots *slots;
+};
+template <typename T_ret, typename T_arg>
+class get_slot
+{
+public:
+  get_slot(Slots& slots_)
+  {
+    slots = &slots_;
+  }
+  sigc::slot<T_ret, T_arg> operator()(const Glib::ustring& name)
+  {
+    sigc::slot<T_ret, T_arg> slot;
+    slots->get_slot(name, &slot);
+    return slot;
+  }
+
+private:
+  Slots *slots;
+};
+
 class Xml : public Glib::Object
 {
   _CLASS_GOBJECT(Xml, GladeXML, GLADE_XML, Glib::Object, GObject)
Index: examples/basic/basic.cc
===================================================================
--- examples/basic/basic.cc	(revision 2071)
+++ examples/basic/basic.cc	(working copy)
@@ -4,15 +4,31 @@
 
 Gtk::Dialog* pDialog = 0;
 
+class MySlots : public Gnome::Glade::Slots
+{
+private:
+GLADEMM_DECLARE_SLOTS(
+  GLADEMM_SLOT(MySlots, on_button_clicked),
+  GLADEMM_SLOT(MySlots, test_slot)
+);
+
 void on_button_clicked()
 {
   if(pDialog)
     pDialog->hide(); //hide() will cause main::run() to end.
 }
 
+void test_slot(const Glib::ustring& msg)
+{
+  std::cout << msg << std::endl;
+}
+
+};
+
 int main (int argc, char **argv)
 {
   Gtk::Main kit(argc, argv);
+  MySlots slots;
 
   //Load the Glade file and instiate its widgets:
   Glib::RefPtr<Gnome::Glade::Xml> refXml;
@@ -37,18 +53,15 @@
 #endif
 
   //Get the Glade-instantiated Dialog:
-  
   refXml->get_widget("DialogBasic", pDialog);
   if(pDialog)
   {
-    //Get the Glade-instantiated Button, and connect a signal handler:
-    Gtk::Button* pButton = 0;
-    refXml->get_widget("quit_button", pButton);
-    if(pButton)
-    {
-      pButton->signal_clicked().connect( sigc::ptr_fun(on_button_clicked) );
-    }
+    refXml->connect_clicked("quit_button",
+	    Gnome::Glade::get_slot_void(slots)("on_button_clicked"));
 
+    (Gnome::Glade::get_slot<void, const Glib::ustring&>
+	(slots)("test_slot"))("Works!!!");
+
     kit.run(*pDialog);
   }
 


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