Chapter 17. Timeouts, I/O and Idle Functions
Prev |  | Next

## Chapter 17. Timeouts, I/O and Idle Functions

## Timeouts

You may be wondering how to make gtkmm do useful work while it's idling along (well, sleeping actually) in `Gtk::Main::run()`. Happily, you have several options. Using the following methods you can create a timeout method that will be called every few milliseconds.

    SigC::Connection Glib::SignalTimeout::connect(const SigC::Slot0<bool>& slot, unsigned int interval, int priority = Glib::PRIORITY_DEFAULT);

The first argument is a slot you wish to have called when the timeout occurs. The second argument is the number of milliseconds between calls to your method. You get back a `SigC::Connection` object that can be used to destroy the connection. Use

    MyConnection.disconnect();

to destroy the connection. Another way of destroying the Connection is your signal handler. It has to be of the type `SigC::Slot0<bool>`. As you see from the definition your signal handler has to return a value of the type `bool`. A definition of a sample method might look like this:

    bool MyCallback() { std::cout << "Hello World!\n"; return true; }

You can stop the timeout method by returning `false` from your signal handler. Therefore, if you want your method to be called repeatedly, it should return `true`.

Here's an example of this technique:

Source location: examples/timeout/timeout.cc

    #include <iostream>
    #include <gtkmm/button.h>
    #include <gtkmm/box.h>
    #include <gtkmm/main.h>
    #include <gtkmm/window.h>
    #include <map>

    class TimerExample : public Gtk::Window
    {
      // the usual stuff - nothing exciting
      Gtk::HBox   m_box;
      Gtk::Button m_add_timer, m_del_timer, m_quit;
      int m_t_nr;

      // the start value for our timer
      static const int COUNT_VALUE;

      // the timeout value for the timers in [ms]
      static const int TIMEOUT_VALUE;

      // we need this to store our connections
      std::map<int,SigC::Connection> m_timers;

      // this is for storing our timer values
      // each timer countsa back from COUNT_VALUE to 0 and
      // if removed when it reaches 0
      std::map<int,int> m_counters;

    public:
      TimerExample();

      // the signal handlers for add & remove button
      void add_timer_pressed();
      void del_timer_pressed();

      // the signal handler for the timer
      // note that is not of the type int callback()
      // since we use bind() to add a data value of type int to it
      int timer_callback(int timer_nr);
    };

    const int TimerExample::COUNT_VALUE = 5;
    const int TimerExample::TIMEOUT_VALUE = 1500;

    TimerExample::TimerExample() :
      m_add_timer("add a new timer"),
      m_del_timer("remove timer"),
      m_quit("Quit"),
      m_box(true,10),
      m_t_nr(0)
    {
      // connect the signal handlers
      m_quit.pressed.connect(&Gtk::Main::quit);
      m_add_timer.pressed.connect(slot(this,&TimerExample::add_timer_pressed));
      m_del_timer.pressed.connect(slot(this,&TimerExample::del_timer_pressed));

      // put buttons into container
      m_box.pack_start(m_add_timer);
      m_box.pack_start(m_del_timer);
      m_box.pack_start(m_quit);

      // set border and display all
      set_border_width(10);
      add(m_box);
      show_all();
    }

    void TimerExample::add_timer_pressed()
    {
      // creation of a new object prevents long lines and
      // shows us a little how slots work
      // we have 0 parameters and int as return value after calling bind
      SigC::Slot0<int> my_slot = bind(slot(this,&TimerExample::timer_callback),m_t_nr);

      // now connect the slot to Gtk::Main::timeout
      Gtk::Connection conn = Gtk::Main::timeout.connect(my_slot,TIMEOUT_VALUE);

      // memorize connection
      m_timers[m_t_nr] = conn;

      // initialize timer count
      m_counters[m_t_nr] = COUNT_VALUE + 1;

      // print some information on the console
      cout << "added timeout " << m_t_nr++ << endl;
    }

    void TimerExample::del_timer_pressed()
    {
      // are there any timers ?
      if(m_timers.empty()) {
        // nope
        cout << "sorry, there are no timers left" << endl;
      } else {
        // get the nr of the first timer
        int timer_nr = m_timers.begin()->first;
        // give a little information to the user
        cout << "removing timer " << timer_nr << endl;
        // delete the entry in the counter values
        m_counters.erase(timer_nr);
        // destroy the connection !!!!!
        // this is important since the connection is NOT destroyed when
        // the according Connection-Object is deleted
        // The purpose of the connection object is to give you the
        // possibility to destroy a connection without having to destroy
        // either the sender or the receiver
        // Try it and comment out the following line ....
        m_timers[timer_nr].disconnect();
        // destroy the connection
        m_timers.erase(timer_nr);
      }
    }

    int TimerExample::timer_callback(int timer_nr)
    {
      // print the timernr
      cout << "This is timer " << timer_nr;
      // decrement & check counter value
      if(--m_counters[timer_nr] == 0) {
        cout << " boom" << endl;
        // delete the counter entry
        m_counters.erase(timer_nr);
        // delete the connection entry
        m_timers.erase(timer_nr);
        // note that we do not need to call disconnect on the connection
        // since we Gtk::Main does this for us when we return 0
        return 0;
      }

      // print the timer value
      cout << " - " << m_counters[timer_nr] << "/" << COUNT_VALUE << endl;
      return 1;
    }

    // the intresting stuff ends here

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

      TimerExample example;

      app.run();
      return 0;
    }

Prev | Up | Next
Chapter 16. The Clipboard | Home | Monitoring I/O