Re: libglademm and signal autoconnect
- From: Stas Sergeev <stsp aknet ru>
- To: Murray Cumming <murrayc murrayc com>
- Cc: gtkmm-list gnome org
- Subject: Re: libglademm and signal autoconnect
- Date: Fri, 27 Feb 2009 23:13:07 +0300
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]