unity-dev team mailing list archive
-
unity-dev team
-
Mailing list archive
-
Message #00234
[Ayatana-dev] [C++] GObject Signals in Unity
Hey,
I've just merged my lp:~njpatel/unity/nicer-glib-signals branch into
Unity trunk. With it comes a nice wrapper to help deal with a annoying
little problem we have at the moment with how our C++ code works with
GObject:
Currently, when we need to connect to a signal on an object inside a
class, we end up doing something like this:
and then MyClass looks like this:
class MyClass
{
// <snip>
MyClass()
{
awesome_happened_id = g_signal_connect (my_object_,
"awesome-happened",
G_CALLBACK
(MyClass::OnMyObjectAwesomeHappened),
this);
// repeat for every signal connection
}
~MyClass()
{
if (G_IS_OBJECT (my_object))
g_signal_handler_disconnect (my_object_, awesome_happened_id_);
}
void MyClass::OnMyObjectAwesomeHappenedReal (int level_of_awesome)
{
//do the real work
}
static void MyClass::OnMyObjectAwesomeHappened (MyObject *my_object,
int level_of_awesome,
MyClass *self)
{
// Static function so we can't access 'this', and need to use the
// passed in parameter instead
self->OnMyObjectAwesomeHappenedReal (level_of_awesome);
}
private:
guint awesome_happened_id;
};
Having to save the connection id, remember to disconnect, only use
static members etc etc is annoying. It also is a great way to cause a
crash if you forgot to disconnect a handler on destruction.
So, to make things easier and hopefully a lot cleaner and safer, we now
have the Signal and SignalManager objects inside UnityCore/GLibSignal.h
The way you use these are as follows:
class MyClass
{
public:
MyClass()
{
// Order of templates is <RETURN, GOBJECT_TYPE, ARGO, ARG1 etc etc>
// ARG0 etc are optional depending on the signal, of course :)
signal_manager_.Add(
new Signal<void, MyObject*, int>(my_object_,
"awesome-happened",
sigc::mem_fun(this,
&MyClass::OnMyObjectAwesomeHappened));
}
// No need to have a destructor just for the signal, signal-manager
// will automatically disconnect all the signals it is managing when
// it destructs
void MyClass::OnMyObjectAwesomeHappened(MyObject *object,
int level_of_awesome)
{
// Non-static, so just do what you want
awesome_happened.emit (level_of_awesome);
}
private:
SignalManager signal_manager_;
}
You can store individual connections as Signal objects inside your class
if your doing some manual management of disconnections etc too, have a
look at tests/test_glib_signals.cpp for a test suite that covers all the
API!
So far, I've only changed UnityCore to use these, but I think we should
start switching over the rest of Unity to use them too, so we can do a
quick review of the existing code as well as delete a whole bunch of code!
NOTE: Further to Tim's email about gboolean/bool, there is no magic in
Signal* to do the conversion, so make sure that if you expect a or
return a gboolean, you use that type and not the C++ bool type (again,
this can be seen in the tests).
--
Neil Jagdish Patel | Technical Lead
Desktop Experience Team
Canonical
27 Floor, Millbank Tower
London SW1P 4QP
Ubuntu - Linux for Human Beings
www.canonical.com