Appendix C. Creating your own signals

Table of Contents

Now that you've seen signals and signal handlers in gtkmm, you might like to use the same technique to allow interaction between your own classes. That's actually very simple by using the libsigc++ library directly.

This isn't purely a gtkmm or GUI issue. gtkmm uses libsigc++ to implement its proxy wrappers for the GTK+ signal system, but for new, non-GTK+ signals, you can create pure C++ signals, using the sigc::signal<> template.

For instance, to create a signal that sends 2 parameters, a bool and an int, just declare a sigc::signal, like so:

sigc::signal<void, bool, int> signal_something;

You could just declare that signal as a public member variable, but some people find that distasteful and prefer to make it available via an accessor method, like so:

class Server
{
public:
  //signal accessor:
  typedef sigc::signal<void, bool, int> type_signal_something;
  type_signal_something signal_something();

protected:
  type_signal_something m_signal_something;
};

Server::type_signal_something Server::signal_something()
{
  return m_signal_something;
}

You can then connect to the signal using the same syntax used when connecting to gtkmm signals. For instance,

server.signal_something().connect(
  sigc::mem_fun(client, &Client::on_server_something) );

Example

This is a full working example that defines and uses custom signals.

Source Code

File: server.h (For use with gtkmm 3, not gtkmm 2)

#ifndef GTKMM_EXAMPLE_SERVER_H
#define GTKMM_EXAMPLE_SERVER_H

#include <sigc++/sigc++.h>

class Server
{
public:
  Server();
  virtual ~Server();

  void do_something();

  //signal accessor:
  typedef sigc::signal<void, bool, int> type_signal_something;
  type_signal_something signal_something();

protected:
  type_signal_something m_signal_something;
};

#endif //GTKMM_EXAMPLE_SERVER_H

File: client.h (For use with gtkmm 3, not gtkmm 2)

#ifndef GTKMM_EXAMPLE_CLIENT_H
#define GTKMM_EXAMPLE_CLIENT_H

#include <sigc++/sigc++.h>

//Client must inherit from sigc::trackable.
//because libsigc++ needs to keep track of the lifetime of signal handlers.
class Client : public sigc::trackable
{
public:
  Client();
  virtual ~Client();

  //Signal handler:
  void on_server_something(bool a, int b);
};

#endif //GTKMM_EXAMPLE_CLIENT_H

File: server.cc (For use with gtkmm 3, not gtkmm 2)

#include "server.h"
#include <iostream>

Server::Server()
{
}

Server::~Server()
{
}

Server::type_signal_something Server::signal_something()
{
  return m_signal_something;
}

void Server::do_something()
{
  m_signal_something.emit(false, 5);
}

File: main.cc (For use with gtkmm 3, not gtkmm 2)

#include "server.h"
#include "client.h"
#include <iostream>

int main(int, char**)
{
  Server server;
  Client client;

  //Connect a Server signal to the signal handler in Client.
  server.signal_something().connect(sigc::mem_fun(client,
              &Client::on_server_something) );

  std::cout << "Before Server::do_something()" << std::endl;

  //Tell the server to do something that will eventually cause it to emit the
  //"something" signal.
  server.do_something();    // Client::on_server_something() will run before
                            // Server::do_something() has completed.

  std::cout << "After Server::do_something()" << std::endl;

  return 0;
}

File: client.cc (For use with gtkmm 3, not gtkmm 2)

#include "client.h"
#include <iostream>

Client::Client()
{
}

Client::~Client()
{
}

void Client::on_server_something(bool a, int b)
{
  std::cout << "Client::on_server_something() called with these parameters: "
      << a << ", " << b << std::endl;
}