Sledování V/V

Šikovnou funkcí knihovny Glib (jedna z knihoven ležících pod gtkmm) je schopnost mít kontrolu nad daty z popisovače souborů pro vaše potřeby. To se hodí hlavně pro síťové aplikace. Následující metoda přesně tohle využívá:

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

První argument je slot, který si přejete mít volaný, když nastane určená událost (viz třetí argument) na popisovači souboru, který jste určili druhým argumentem. Třetí argument může být jedna nebo více (pomocí |) hodnot z:

  • Glib::IO_IN – Zavolat vaši metodu, když jsou připravena data ke čtení na popisovači vašeho souboru.
  • Glib::IO_OUT – Zavolat vaši metodu, když je popisovač souboru připravený k zápisu.
  • Glib::IO_PRI – Zavolat vaši metodu, když má popisovač souboru neodkladná data k přečtení.
  • Glib::IO_ERR – Zavolat vaši metodu, když se na popisovači souboru vyskytla nějaká chyba.
  • Glib::IO_HUP – Zavolat vaši metodu, když došlo k zaseknutí (připojení bylo porušeno, obvykle kvůli rouře nebo soketu).

Vrácená hodnota je sigc::connection, kterou můžete použít k zastavení sledování tohoto popisovače souboru pomocí jeho metody disconnect(). Obsluha signálu slot by měla být deklarovaná následovně:

bool input_callback(Glib::IOCondition condition);

kde argument condition je takový, jak byl určen ve funkci zmíněné výše. Jako obvykle je slot vytvořen pomocí sigc::mem_fun() (pro členské metody objektu), nebo pomocí sigc::ptr_fun() (pro funkce).

Následuje menší příklad. Pokud jej chcete použít, spusťte jej z terminálu – nevytváří žádné okno. Co ale vytvoří, je pojmenovaná roura testfifo v aktuální složce. Pak spusťte další shell a v něm echo "Hello" > testinfo. Příklad bude vypisovat jednotlivé řádky, které takto zadáte, až dokud nespustíte echo "Q" > testfifo.

Source Code

File: main.cc (For use with gtkmm 4)

#include <gtkmm/application.h>
#include <glibmm/main.h>
#include <glibmm/iochannel.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>

Glib::RefPtr<Gtk::Application> app;

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::IOCondition::IO_IN) != Glib::IOCondition::IO_IN) {
    std::cerr << "Invalid fifo response" << std::endl;
  }
  else {
   Glib::ustring buf;

   iochannel->read_line(buf);
   std::cout << buf;
   if (buf == "Q\n")
     app->quit();

  }
  return true;
}


int main(int argc, char *argv[])
{
  app = Gtk::Application::create("org.gtkmm.example");

  if (access("testfifo", F_OK) == -1) {
    // fifo doesn't exist - create it
    #ifndef DONT_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 //DONT_HAVE_MKFIFO
  }

  // Although we will only read from the fifo, we open it in read/write mode.
  // Due to a peculiarity with the poll() system call, used deep down in glib,
  // this small program will use all available CPU time, if the fifo is opened
  // as O_RDONLY. See a discussion on the gtkmm-list, e.g.
  // https://mail.gnome.org/archives/gtkmm-list/2015-September/msg00034.html
  // and the link from there to stackoverflow.
  read_fd = open("testfifo", O_RDWR);
  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::IOCondition::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->hold(); // keep the application running without a window
  app->run(argc, argv);

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

  return 0;
}