// COMPILE AS:
//
// g++ -DWORKAROUND=0 `pkg-config --cflags gtkmm-3.0` `pkg-config --cflags gtk+-3.0` bug.cpp `pkg-config --libs gtk+-3.0` `pkg-config --libs gtkmm-3.0` -Wl,--export-dynamic
//

// FIX THIS PATH.
char const* glade_path = "/home/carlo/projects/speech/speech/res/speechUI.glade";

#ifndef WORKAROUND
#error Use -DWORKAROUND=0 or -DWORKAROUND=1
#endif

#include <iostream>
#include <gtkmm.h>
#include <cassert>

class UIWindow : public Gtk::Window
{
  private:
    Glib::RefPtr<Gtk::Application> m_refApp;

    static GtkWindow* read_glade(std::string const& glade_path, char const* window_name);

  public:
    UIWindow(Glib::RefPtr<Gtk::Application> const& refApp, std::string const& glade_path, char const* window_name);
    virtual ~UIWindow();

  protected:
    // Signal handlers.
    void on_hide(void);
};

//static
GtkWindow* UIWindow::read_glade(std::string const& glade_path, char const* window_name)
{
  // This block is C code because we need a plain GtkWindow instead of a Gtk::Window.
  // Otherwise we get a warning when wrapping the GtkWindow* in a Gtk::Window below,
  // saying that is already wrapped.

  GtkBuilder* builder = gtk_builder_new_from_file(glade_path.c_str());
  GtkWindow* window = GTK_WINDOW(gtk_builder_get_object(builder, window_name));
  // Do not connect signals C-style though, because we need them to be connected
  // C++-style, which is done in the constructor of UIWindow.
  g_object_unref(G_OBJECT(builder));	// Delete the builder.

  if (!window) std::cerr << "The glade file does not contain a window called '" << window_name << "'." << std::endl;
  assert(window);
  return window;
}

UIWindow::UIWindow(Glib::RefPtr<Gtk::Application> const& refApp, std::string const& glade_path, char const* window_name) :
    Gtk::Window(read_glade(glade_path, window_name)), m_refApp(refApp)
{
  // Do not leave application until the destructor was called.
  refApp->hold();

  // Connect signals.

  // Call the on_hide() method when the UIWindow is hidden.
  signal_hide().connect(sigc::mem_fun(this, &UIWindow::on_hide));
}

UIWindow::~UIWindow()
{
  std::cout << "UIWindow::~UIWindow()" << std::endl;
  // Do not terminate the application immediately because otherwise
  // the window is not removed from the screen and we get an annoying
  // pop-up from kwin saying `You tried to close window "Speech recognition"
  // from application "speech" (Process ID: 27656) but the application is not
  // responding. Do you want to terminate this application?`.
#if WORKAROUND
  m_refApp->set_inactivity_timeout(10);
#endif
  m_refApp->release();
}

void UIWindow::on_hide(void)
{
  std::cout << "UIWindow::on_hide()" << std::endl;
}

int main (void)
{
  Glib::RefPtr<Gtk::Application> refApp = Gtk::Application::create("org.gnome.gtkbugexample");
  // Store refApp in UIWindow in order to Keep the application running (not return from run()), until
  // the window is destructed (as result of the hide signal; ie, when the user clicks the close button).
  UIWindow* pUIWindow = new UIWindow(refApp, glade_path, "window1");

  std::cout << "Entering run()" << std::endl;
  refApp->run(*pUIWindow);
  std::cout << "Returned from run()" << std::endl;

  // Keep application running, do not actually leave main().
  sleep(-1);
  return 0;
}
