Connecting the two

It should be clear by now that if you want to react to an action, you must connect its signal to a signal handler that you have written, so that PHP-GTK 2 can call that function whenever the signal is triggered. Let's look into how you can connect signals to signal handlers.

There are 4 main functions that you can use to connect signals to callbacks:

  • connect_simple
  • connect_simple_after
  • connect
  • connect_after

The *_after methods are used if you want your signal handlers to be invoked after the ones connected using connect and connect_simple. We will be discussing only the connect_simple and connect methods. The respective *_after methods behave in the same way except for the fact that the signal handler is guaranteed to be invoked only after those connected via connect or connect_simple have.

Simple connections

First we'll look into how to connect a signal to a signal handler in the most simplest way. We'll be using, you guessed it, the connect_simple method.

Of course, it is vital that you know the names of the signals that you would want to connect to. The PHP-GTK 2 documentation contains a list of all signals that are relevant for a particular widget. Once you know that, and once you have written a function that contains the code you want to be executed when the signal is generated all you have to do is:

${widget}->connect_simple('{signal-name}', '{callback-name}');
 
where, {widget} is the object whose signal you want to connect, {signal-name} is the signal name, which of course must be relevant to {widget}, and {callback-name} is the name of the callback function.

Signal handlers are invoked whenever a signal is generated, by whatever means. Remember that it is possible to generate signals through functions, and hence a signal generation does not guarantee that the user has performed an action.

To make things a little clearer, let's take a full fledged example. Here, we add a button to a window. When a user clicks the button, the application quits:

Example 9.1. A simple connection

<?php

$win = new GtkWindow();
$but = new GtkButton('Click to Quit!');

$win->add($but);
$win->show_all();

$but->connect_simple('clicked', 'quit');

function quit()
{
    echo "You have quit!\n";
    Gtk::main_quit();
}

Gtk::main();

?>

It's quite a simple program. We create a button and a window, add the button to the window and show them. The line we are concerned with is:

$but->connect_simple('clicked', 'quit');
 
As you can see, we have connected the "clicked" signal of a GtkButton widget to the signal handler named quit. Simple, eh? The function quit will be called whenever the clicked signal is emitted from our button, or, whenever the user clicks on our button.

You can see in the quit function definition that we display a message and then call the Gtk::main_quit() function to exit the program.

Multiple Connections

What if I connect the same signal twice to two different callbacks?, I hear you ask. Well, the signal handlers will simply be called in the order in which they were connected.

If any of your signal handlers return true then no more signal handlers will be called for the current signal being handled. This is a useful way of controlling logic when you have multiple signal handlers.

An example to make things crystal clear:

Example 9.2. Multiple signal connections

<?php

$win = new GtkWindow();
$but = new GtkButton('Click to Quit!');

$win->add($but);
$win->show_all();

$but->connect_simple('clicked', 'first');
$but->connect_simple('clicked', 'second');
$but->connect_simple('clicked', 'third');

function first()
{
    echo "I am the first function!\n";
}

function second()
{
    echo "I am the second function!\n";
}

function third()
{
    echo "And I'm the function that's going to stop this program!\n";
    Gtk::main_quit();
}

Gtk::main();

?>
Run the program and you will see that signal handlers are indeed invoked in the order in which they were connected.

OK, but what if I connect the signal to the same callback a hundred times? The callback will be invoked a hundred times. But there's no reason anyone would want to do this.

Can I connect multiple signals to the same callback? Yes, and in fact this is actually very useful. Many applications will have multiple ways of quitting the program: the regular "cross" button, a "quit" button on the file menu etc. You can connect signals for each one of them to a single quit function. You don't have to worry about where the signal came from, you just know that the user wants to quit the application.

Customizing connections

Sometimes, its useful to know which widget had triggered a particular signal. If your application has more than one button, and you've connected all their clicked signals to a single callback, you'd definitely want to know which button the signal came from. It is in fact efficient to write a single signal handler for multiple signals.

Here is where the connect method comes into the picture. This method passes the object of the widget that generated the signal as the first parameter to the signal handler.

$button1 = new GtkButton('First');
$button2 = new GtkButton('Second');

$button1->connect('clicked', 'show');
$button2->connect('clicked', 'show');

function show($whichbutton)
{
    echo $whichbutton->get_label();
}
 
In the above example, you will get an output of "First" or "Second" depending on which button was clicked.

It is also useful at times if you could pass custom parameters to your signal handlers. PHP-GTK 2 provides this functionality in both the connect and connect_after methods. You simply pass your parameters after the second argument to both these methods separated by commas like this:

Example 9.3. Passing custom parameters

<?php

$win = new GtkWindow();
$but = new GtkButton('Move over me!');

$win->add($but);
$win->show_all();

$win->connect_simple('destroy', array('gtk', 'main_quit'));
$but->connect_simple('enter-notify-event', 'showMessage', true, 'You moved the mouse');
$but->connect_simple('leave-notify-event', 'showMessage', false, 'You moved the mouse');

function showMessage($enter, $message)
{
    if ($enter) {
        echo $message." over the button!\n";
    } else {
        echo $message." away from the button!\n";
    }
}

Gtk::main();

?>
In this example, we pass two custom parameters to our signal handler that helps us from differentiating whether the mouse entered the button or left it. Note that your custom parameters can be of any type: string, boolean, integer, an array or even an object, as long as its a valid type in PHP. In fact, it is a very common necessity to pass widget objects as parameters to signal handlers, because a callback connected to a signal triggered by some widget may need to modify some other widget. You may pass as many custom parameters as you want. Just ensure that your signal handler is designed to receive the same number of parameters, or you may raise warnings.

For more information on signals such as enter-notify-event, see the section on events, because there is more to this than meets the eye.

Object-oriented connections

Let us analyze the line that you might have seen frequently:

$window->connect_simple('destroy', array('gtk', 'main_quit'));
 
Why an array as the second argument?

Remember that whenever you connect to callback functions in an object-oriented context, the second argument to the connect_* functions must be an array. The first element of the array should point to the class that contains the callback and the second element must contain the name of the callback itself.

When the callback is static in nature (like Gtk::main_quit()), we generally specify the name of the class as a string. However if the callback is not static in nature, but is a member of your current class instead, the first element should be the special $this variable. Have a look at the tutorial on Object Oriented Programming for examples of usage in such a context. The point is to somehow make the first element of the array point to the class that contains the callback and the second element point to the callback.