Appendix B. Signals

Table of Contents

Connecting signal handlers

gtkmm widget classes have signal accessor methods, such as Gtk::Button::signal_clicked(), which allow you to connect your signal handler. Thanks to the flexibility of libsigc++, the callback library used by gtkmm, the signal handler can be almost any kind of function, but you will probably want to use a class method. Among GTK C coders, these signal handlers are often named callbacks.

Here's an example of a signal handler being connected to a signal:

#include <gtkmm/button.h>

void on_button_clicked()
{
  std::cout << "Hello World" << std::endl;
}

class some_class
{
public:
  some_class
  {
    button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked));
  }
private:
  Gtk::Button button {"Hello World"};
};

There's rather a lot to think about in this (non-functional) code. First let's identify the parties involved:

  • The signal handler is on_button_clicked().

  • We're hooking it up to the Gtk::Button object called button.

  • When the Button emits its clicked signal, on_button_clicked() will be called.

Now let's look at the connection again:

    ...
    button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked));
    ...

Note that we don't pass a pointer to on_button_clicked() directly to the signal's connect() method. Instead, we call sigc::ptr_fun(), and pass the result to connect().

sigc::ptr_fun() generates a sigc::slot. A slot is an object which looks and feels like a function, but is actually an object. These are also known as function objects, or functors. sigc::ptr_fun() generates a slot for a standalone function or static method. sigc::mem_fun() generates a slot for a member method of a particular instance.

A C++ lambda expression is a functor which can be implicitly converted to a sigc::slot in the call to connect(). A lambda expression can be used instead of sigc::ptr_fun(). It's also possible to use a lambda expression instead of sigc::mem_fun(), but then you won't get automatic disconnection of the signal handler when a sigc::trackable-derived object goes out of scope.

Here's a slightly larger example of slots in action:

#include <gtkmm/button.h>

void on_button_clicked()
{
  std::cout << "Hello World" << std::endl;
}

class some_class
{
public:
  some_class
  {
    button.signal_clicked().connect(sigc::ptr_fun(&on_button_clicked));
    button.signal_clicked().connect(sigc::mem_fun(*this, &some_class::on_button_clicked));
  }
  void on_button_clicked();
private:
  Gtk::Button button {"Hello World"};
};

The first call to connect() is just like the one we saw last time; nothing new here.

The next is more interesting. sigc::mem_fun() is called with two arguments. The first argument is *this, which is the object that our new slot will be pointing at. The second argument is a pointer to one of its methods. This particular version of sigc::mem_fun() creates a slot which will, when "called", call the pointed-to method of the specified object.

Another thing to note about this example is that we made the call to connect() twice for the same signal object. This is perfectly fine - when the button is clicked, both signal handlers will be called.

We just told you that the button's clicked signal is expecting to call a method with no arguments. All signals have requirements like this - you can't hook a function with two arguments to a signal expecting none (unless you use an adapter, such as sigc::bind(), of course). Therefore, it's important to know what type of signal handler you'll be expected to connect to a given signal.