-
-
Save caiorss/d81dd9c422dc93ad4104b5e79259afdf to your computer and use it in GitHub Desktop.
Gtk with dynamic loading
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.9) | |
project(gtk-sample) | |
#========== Global Configurations =============# | |
#----------------------------------------------# | |
set(CMAKE_CXX_STANDARD 17) | |
set(CMAKE_VERBOSE_MAKEFILE ON) | |
add_executable( gtk-dlopen gtk-dlopen.cpp) | |
target_link_libraries( gtk-dlopen dl ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cstring> | |
#include <cassert> | |
// Uses: dlopen(), dlclose(), ... | |
#include <dlfcn.h> | |
// ---- Copied from GTK headers ------// | |
typedef char gchar; | |
typedef short gshort; | |
typedef long glong; | |
typedef int gint; | |
typedef gint gboolean; | |
typedef unsigned char guchar; | |
typedef unsigned short gushort; | |
typedef unsigned long gulong; | |
typedef unsigned int guint; | |
typedef float gfloat; | |
typedef double gdouble; | |
typedef void* gpointer; | |
typedef const void* gconstpointer; | |
enum class GtkWindowType | |
{ | |
GTK_WINDOW_TOPLEVEL, | |
GTK_WINDOW_POPUP | |
}; | |
enum class GConnectFlags | |
{ | |
G_CONNECT_AFTER = 1 << 0, | |
G_CONNECT_SWAPPED = 1 << 1 | |
}; | |
template<typename TFun> | |
TFun load_symbol(void* hnd, std::string symbol) | |
{ | |
void* hSym = dlsym(hnd, symbol.c_str()); | |
if(hSym == nullptr) | |
{ | |
std::string msg = std::string(" [Error] symbol not found: ") + symbol; | |
throw std::runtime_error(msg); | |
} | |
return reinterpret_cast<TFun>(hSym); | |
} | |
// Opaque type (aka incomplete type) | |
struct GClosure; | |
// -------- Function Pointers type aliases -------------------// | |
using GCallback = void (*) (void); | |
using GClosureNotify = void (*) (gpointer data, GClosure* closure); | |
using g_signal_connect_data_t = gulong (*) ( gpointer instance | |
, const gchar* detailed_signal | |
, GCallback c_handler | |
, gpointer data | |
, GClosureNotify destroy_data | |
, GConnectFlags connect_flags | |
); | |
int main(int argc, char** argv) | |
{ | |
std::string shared_lib = [&]() -> std::string | |
{ | |
if(argc < 2) return "libgtk-3.so.0"; | |
return argv[1]; | |
}(); | |
std::cout << " [INFO] Loading shared library: " << shared_lib << "\n"; | |
// void *dlopen(const char *filename, int flags); | |
// Handle to shared library | |
void* hnd = dlopen(shared_lib.c_str(), RTLD_NOW | RTLD_GLOBAL); | |
if(hnd == nullptr){ fprintf(stderr, "%s\n", dlerror()); } | |
assert( hnd != nullptr ); | |
void* hSym = nullptr; | |
// --------- Load gtk_init_check function pointer ------- // | |
hSym = dlsym(hnd, "gtk_init_check"); | |
assert(hSym != nullptr); | |
using gtk_init_check_t = gboolean (*) (int* argc, char*** argv); | |
auto gtk_init_check = reinterpret_cast<gtk_init_check_t>(hSym); | |
// ------- Load remaining function pointers (symbols) --------// | |
//-----------------------------------------------------------// | |
// opaque pointer | |
struct GtkWidget; | |
using gkt_window_new_t = GtkWidget* (*) (int); | |
auto gtk_window_new = load_symbol<gkt_window_new_t>(hnd, "gtk_window_new"); | |
auto gtk_widget_show = load_symbol<void (*) (GtkWidget*)>(hnd, "gtk_widget_show"); | |
auto gtk_main = load_symbol<void (*) ()>(hnd, "gtk_main"); | |
using gtk_window_set_title_t = void (*) (GtkWidget* window, const gchar* title); | |
auto gtk_window_set_title = load_symbol<gtk_window_set_title_t>(hnd, "gtk_window_set_title"); | |
using gtk_widget_set_size_t = void (*) (GtkWidget*, gint, gint); | |
auto gtk_widget_set_size = load_symbol<gtk_widget_set_size_t>(hnd, "gtk_widget_set_size_request"); | |
auto gtk_main_quit = load_symbol<void (*) ()>(hnd, "gtk_main_quit"); | |
auto gtk_signal_connect_data | |
= load_symbol<g_signal_connect_data_t>(hnd, "g_signal_connect_data"); | |
/** ------- Build Window GUI - Graphical User Interface ----------**/ | |
// Call function pointer | |
gtk_init_check(&argc, &argv); | |
GtkWidget* window = gtk_window_new( (int) GtkWindowType::GTK_WINDOW_TOPLEVEL); | |
gtk_widget_set_size(window, 400, 500); | |
gtk_window_set_title(window, "My GTK Window"); | |
gtk_widget_show(window); | |
gtk_signal_connect_data( window // Widget | |
, "destroy" // Event name | |
, gtk_main_quit // Callback | |
, nullptr // Pointer to data (closure ) | |
, nullptr | |
, (GConnectFlags) 0 // GConnect flags | |
); | |
std::cout << " [INFO] Window running. OK! " << "\n"; | |
gtk_main(); | |
// Always close shared library handler. | |
dlclose(hnd); | |
std::cout << " [INFO] Shutdown gracefully. Ok. \n" ; | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment