Monitoring I/O

TODO: This is now in Glib, not Gdk. A nifty feature of GDK (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::Main::SignalInput::connect(const SlotType& sd, int source,
                                    Glib::InputCondition condition);

The first argument is a slot (SlotType is a typedef to a sigc::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:

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

void input_callback(int source, GdkInputCondition condition);

where source and condition are 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 <gtkmm/main.h>
#include "gtkmmconfig.h" //For HAVE_MKFIFO
#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;
}