Plugs and Sockets Example

The following is a simple example of using sockets and plugs. The method of communication between processes is deliberately kept very simple: The Plug writes its ID out to a text file named plug.id and the process with the socket reads the ID from this file. In a real program, you may want to use a more sophisticated method of inter-process communication.

Source Code

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

#include <iostream>
#include <fstream>
#include <gtkmm.h>
#include <gtkmm/socket.h>

using namespace std;

const char* id_filename = "plug.id";

void plug_added()
{
  cout << "A plug was added" << endl;
}

bool plug_removed()
{
  cout << "A Plug was removed" << endl;
  return true;
}

class MySocketWindow : public Gtk::Window
{
  public:
    MySocketWindow()
    {
      ifstream infile(id_filename);
      if (infile)
      {
        auto socket = Gtk::make_managed<Gtk::Socket>();
        add(*socket);
        socket->signal_plug_added().connect(sigc::ptr_fun(plug_added));
        socket->signal_plug_removed().connect(sigc::ptr_fun(plug_removed));
        ::Window plug_id = 0;
        infile >> plug_id;
        infile.close();
        socket->add_id(plug_id);
      }
      else
      {
        auto label = Gtk::make_managed<Gtk::Label>(
              "Plug id file not found.\n Make sure plug is running.");
        add(*label);
        set_size_request(150, 50);
      }
      show_all();
    }
};

int main(int argc, char** argv)
{
  // The plug and the socket have different application ids, so they can run
  // simultaneously.
  auto app =
    Gtk::Application::create(argc, argv, "org.gtkmm.example.socket");
  MySocketWindow win;
  app->run(win);
  return 0;
}

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

#include <iostream>
#include <fstream>
#include <gtkmm.h>
#include <gtkmm/plug.h>
#include <glib/gstdio.h>

using namespace std;

const char* id_filename = "plug.id";

void on_embed()
{
  cout << "I've been embedded." << endl;
}

class MyPlug : public Gtk::Plug
{
  public:
    MyPlug() :
      m_label("I am the plug")
  {
    set_size_request(150, 100);
    add(m_label);
    signal_embedded().connect(sigc::ptr_fun(on_embed));
    show_all_children();
  }

  private:
    Gtk::Label m_label;
};


int main(int argc, char** argv)
{
  // The plug and the socket have different application ids, so they can run
  // simultaneously.
  auto app =
    Gtk::Application::create(argc, argv, "org.gtkmm.example.plug");
  MyPlug plug;
  plug.show();

  ofstream out(id_filename);
  out << plug.get_id();
  out.close();
  cout << "The window ID is: " << plug.get_id() << endl;

  app->run(plug);

  // remove the ID file when the program exits
  g_remove(id_filename);
  return 0;
}

This example creates two executable programs: socket and plug. The idea is that socket has an application window that will embed a widget from the plug program. The way this example is designed, plug must be running first before starting socket. To see the example in action, execute the following commands in order from within the example directory:

Start the plug program and send it to the background (or just use a different terminal).

$ ./plug &

After which you should see something like the following:

The window ID is: 69206019

Then start the socket program:

$ ./socket

After starting socket, you should see the following output in the terminal:

I've been embedded.
A plug was added

The first line of output is from plug, after it has been notified that it has been embedded inside of a Socket. The second line was emitted by socket in response to its plug_added signal. If everything was done as described above, the socket window should look roughly like the following:

If for some reason the Socket couldn't attach the Plug, the window would look something like this: