Search code examples
c++c++11gtkgtkmm

Dynamically load gtkmm objects with dlopen


I have to dynamically use my library that uses Gtkmm. Unfortunately, I don't even manage to open a window in that way, and I don't understand why. Due to technical restrictions, the functions I must use are the dl* family. Here is what I have tried so far :

My compile lines:

for the library:

g++ gtkmm.cpp -shared -fPIC -o lib.so `pkg-config gtkmm-3.0 --cflags --libs

for the main:

g++ main.cpp -ldl

file: main.cpp

#include "INibbler.hpp"
#include <dlfcn.h>
#include <cstdlib>
#include <iostream>

typedef INibbler *(*fPtr)(int x, int y);

int main(int ac, char **av)
{
  void  *handle;
  fPtr  ptr;

  handle = dlopen("./lib.so", RTLD_LAZY);
  if (handle != NULL)
    {
      ptr = reinterpret_cast<fPtr>(dlsym(handle, "returnInstance"));
      INibbler *test = reinterpret_cast<INibbler *>((*ptr)(700, 500));
      test->loopGame(ac, av);
    }
}

file: gtkmm.cpp

LibGtkmm::LibGtkmm(int x, int y)
{
  (void)x;
  (void)y;
  this->set_default_size(100, 100);
}

LibGtkmm::~LibGtkmm()
{

}

void LibGtkmm::loopGame(int ac, char **av)
{
  Glib::RefPtr<Gtk::Application> app
    = Gtk::Application::create(ac,av, "org.gtkmm", Gio::APPLICATION_HANDLES_OPEN);

  app->run(*this);
}

extern "C"
{
  INibbler *returnInstance(int x, int y)
  {
    std::cout << "hey" << std::endl;
    return (new LibGtkmm(x, y));
  }
}

file: gtkmm.hpp

#ifndef GTKMM_H_
#define GTKMM_H_

#include <gtkmm.h>
#include "../INibbler.hpp"

class   LibGtkmm : public INibbler, public Gtk::Window
{
private:
public:
  LibGtkmm(int x, int y);
  virtual ~LibGtkmm();
  virtual void loopGame(int ac, char **av);
};

#endif  // !GTKMM_H_

file: INibbler.hpp

#ifndef INIBBLER_HPP_
# define INIBBLER_HPP_

class   INibbler
{
public:
  virtual void  loopGame(int ac, char **av) = 0;
};

#endif /* !INIBBLER_HPP_ */

When I call app->run, the window does not open itself, and I got a lot of GTK fail messages... telling that the pointer is somehow NULL. Here are the most notable:

(process:7556): Gtk-CRITICAL **: gtk_settings_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(process:7556): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:7556): GLib-GObject-CRITICAL **: g_signal_connect_object: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

Does someone have an idea of how I can resolve my problem ?


Solution

  • Problem: You don't have a Gtk::Main.

    Solution: Create a Gtk::Main. You need this:

    Gtk::Main main(argc, argv);
    main.run();
    

    To avoid Gtkmm freaking out, create the Gtk::Main as soon as possible. Call main.run() once you've initialized everything.