Event Propagation

Event propagation means that, when an event is emitted on a particular widget, it can be passed to its parent widget (and that widget can pass it to its parent, and so on) and, if the parent has an event handler, that handler will be called.

The event will propagate until it reaches the top-level widget, or until you stop the propagation by returning true from an event handler.

Notice, that after canceling an event, no other function will be called (even if it is from the same widget).

23.2.1. Example

In this example there are three event handlers, one in the Gtk::Entry, one in the Gtk::Grid and one in the Gtk::Window.

When you write in the entry, a key release event will be emitted first in the Entry and, depending on whether we let it propagate, it can reach the Grid's and the Window's event handlers. If it propagates, the text you're writing will appear in the Label above the Entry.

Figure 23-2Keyboard Events - Event Propagation

Source Code

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

#ifndef GTKMM_EVENT_PROPAGATION_H
#define GTKMM_EVENT_PROPAGATION_H

#include <gtkmm.h>
#include <iostream>

class ExampleWindow : public Gtk::Window
{
public:

  ExampleWindow();
  virtual ~ExampleWindow();


private:

  bool entryKeyRelease(GdkEventKey *event);
  bool gridKeyRelease(GdkEventKey *event);
  bool windowKeyRelease(GdkEventKey *event);

  Gtk::Grid m_container;

  Gtk::Label m_label;
  Gtk::Entry m_entry;
  Gtk::CheckButton m_checkbutton_can_propagate;
};


#endif //GTKMM_EVENT_PROPAGATION_H

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

#include "examplewindow.h"

ExampleWindow::ExampleWindow()
{
  add(m_container);
  set_title("Event Propagation");
  set_border_width(10);
  
  m_label.set_label("A label");
  m_checkbutton_can_propagate.set_label("Can Propagate");
  m_checkbutton_can_propagate.set_active();

  // Main Container
  m_container.set_orientation(Gtk::ORIENTATION_VERTICAL);
  m_container.add(m_label);
  m_container.add(m_entry);
  m_container.add(m_checkbutton_can_propagate);

  // Events
  add_events(Gdk::KEY_RELEASE_MASK);

  m_entry.signal_key_release_event().connect(
    sigc::mem_fun(*this, &ExampleWindow::entryKeyRelease));

  m_container.signal_key_release_event().connect(
    sigc::mem_fun(*this, &ExampleWindow::gridKeyRelease));

  signal_key_release_event().connect(
    sigc::mem_fun(*this, &ExampleWindow::windowKeyRelease));

  show_all_children();
}

//By changing the return value we allow, or don't allow, the event to propagate to other elements.
bool ExampleWindow::entryKeyRelease(GdkEventKey* /* event */ )
{
  std::cout << "Entry" << std::endl;

  if(m_checkbutton_can_propagate.get_active())
  {
    return false;
  }

  return true;
}

bool ExampleWindow::gridKeyRelease(GdkEventKey* /* event */ )
{
  std::cout << "Grid" << std::endl;

  //Let it propagate:
  return false;
}

// This will set the entry's text in the label, every time a key is pressed.
bool ExampleWindow::windowKeyRelease(GdkEventKey* /* event */ )
{
  std::cout << "Window" << std::endl;

  //checking if the entry is on focus, otherwise the label would get changed by pressing keys
  //on the window (when the entry is not on focus), even if canPropagate wasn't active
  if(m_entry.has_focus())
  {
    m_label.set_text(m_entry.get_text());
  }

  return true;
}

ExampleWindow::~ExampleWindow()
{
}

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

#include "examplewindow.h"
#include <gtkmm/main.h>

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  ExampleWindow window;

  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}