Monitoring I/O
| Chapter 22. Timeouts, I/O and Idle Functions |

## Monitoring I/O

A nifty feature of Glib (one of the libraries underlying gtkmm) is the ability to have it check for data on a file descriptor for you. This is especially useful for networking applications. The following method is used to do this:

    sigc::connection Glib::SignalInput::connect(const sigc::slot<bool,Glib::IOCondition>& slot,
                                        int fd, Glib::IOCondition condition,
                                        int priority = Glib::PRIORITY_DEFAULT);

The first argument is a slot you wish to have called when then the specified event (see argument 3) occurs on the file descriptor you specify using argument two. Argument three may be one or more (using `|`) of:

- Glib::IO_IN - Call your method when there is data ready for reading on your file descriptor.

- Glib::IO_OUT - Call your method when the file descriptor is ready for writing.

- Glib::IO_PRI - Call your method when the file descriptor has urgent data to be read.

- Glib::IO_ERR - Call your method when an error has occurred on the file descriptor.

- Glib::IO_HUP - Call your method when hung up (the connection has been broken usually for pipes and sockets).

The return value is a `sigc::connection` that may be used to stop monitoring this file descriptor using its `disconnect()` method. The `slot` signal handler should be declared as follows:

    bool input_callback(Glib::IOCondition condition);

where `condition` is as specified above. As usual the slot is created with `sigc::mem_fun()` (for a member method of an object.), or `sigc::ptr_fun()` (for a function).

A little example follows. To use the example just execute it from a terminal; it doesn't create a window. It will create a pipe named `testfifo` in the current directory. Then start another shell and execute `echo "Hello" > testfifo`. The example will print each line you enter until you execute `echo "Q" > testfifo`.

Source Code

File: `main.cc`

    #include <build/config.h>
    #include <gtkmm/main.h>
    #include <fcntl.h>
    #include <iostream>

    #include <unistd.h> //The SUN Forte compiler puts F_OK here.

    //The SUN Forte compiler needs these for mkfifo:
    #include <sys/types.h>
    #include <sys/stat.h>

    int read_fd;
    Glib::RefPtr<Glib::IOChannel> iochannel;

    /*
      send to the fifo with:
      echo "Hello" > testfifo

      quit the program with:
      echo "Q" > testfifo
    */

    // this will be our signal handler for read operations
    // it will print out the message sent to the fifo
    // and quit the program if the message was 'Q'.
    bool MyCallback(Glib::IOCondition io_condition)
    {

      if ((io_condition & Glib::IO_IN) == 0) {
        std::cerr << "Invalid fifo response" << std::endl;
      }
      else {
       Glib::ustring buf;

       #ifdef GLIBMM_EXCEPTIONS_ENABLED
       iochannel->read_line(buf);
       #else
       std::auto_ptr<Glib::Error> ex;
       iochannel->read_line(buf, ex);
       if(ex.get())
         std::cerr << "Error: " << ex->what() << std::endl;
       #endif //GLIBMM_EXCEPTIONS_ENABLED
       std::cout << buf;
       if (buf == "Q\n")
           Gtk::Main::quit ();

      }
      return true;
    }

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

      if (access("testfifo", F_OK) == -1) {
        // fifo doesn't exit - create it
        #ifdef HAVE_MKFIFO
        if (mkfifo("testfifo", 0666) != 0) {
          std::cerr << "error creating fifo" << std::endl;
          return -1;
        }
        #else
          std::cerr << "error creating fifo: This platform does not have mkfifo()"
              << std::endl;
        #endif //HAVE_MKFIFO
      }

      read_fd = open("testfifo", O_RDONLY);
      if (read_fd == -1)
      {
        std::cerr << "error opening fifo" << std::endl;
        return -1;
      }

      // connect the signal handler
      Glib::signal_io().connect(sigc::ptr_fun(MyCallback), read_fd, Glib::IO_IN);

      // Creates a iochannel from the file descriptor
      iochannel = Glib::IOChannel::create_from_fd(read_fd);

      // and last but not least - run the application main loop
      app.run();

      // now remove the temporary fifo
      if(unlink("testfifo"))
        std::cerr << "error removing fifo" << std::endl;

      return 0;
    }

Chapter 22. Timeouts, I/O and Idle Functions |  | Idle Functions