From 9c99a01464d1327cc57f241018d5c8a7ea17fa53 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Tue, 18 Nov 2025 09:19:15 +0100 Subject: [PATCH] Initial import --- CMakeLists.txt | 17 ++++++++ gtk-imports.c | 15 +++++++ gtk-imports.h | 98 +++++++++++++++++++++++++++++++++++++++++++ gtkloader.cpp | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ gtkloader.h | 26 ++++++++++++ main.cpp | 38 +++++++++++++++++ 6 files changed, 305 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 gtk-imports.c create mode 100644 gtk-imports.h create mode 100644 gtkloader.cpp create mode 100644 gtkloader.h create mode 100644 main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ad32c65 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.16) + +project(yellownotes LANGUAGES CXX C) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_executable(yellownotes main.cpp + gtk-imports.h + gtkloader.h gtkloader.cpp + gtk-imports.c) + +include(GNUInstallDirs) +install(TARGETS yellownotes + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/gtk-imports.c b/gtk-imports.c new file mode 100644 index 0000000..bec745c --- /dev/null +++ b/gtk-imports.c @@ -0,0 +1,15 @@ +#include + +#define GTK_DECLARE_FUNCS +#include "gtk-imports.h" + +void loadGtkFunctions(void (*loader)(const char *funcname, void **func, void *user_data), void *user_data) +{ +#undef GTK_IMPORTS_H +#undef GTK_DECLARE_FUNCS +#undef DECL +#define GTK_LOAD_FUNCS +#include "gtk-imports.h" +} + + diff --git a/gtk-imports.h b/gtk-imports.h new file mode 100644 index 0000000..89a431a --- /dev/null +++ b/gtk-imports.h @@ -0,0 +1,98 @@ +#ifndef GTK_IMPORTS_H +#define GTK_IMPORTS_H + +/************************************************************************************* + * boiler plate code to initialize Gtk functions etc. + *************************************************************************************/ + +void loadGtkFunctions(void (*loader)(const char *, void **, void *), void *user_data); + +/************************************************************************************* + * Gtk Functions to load from shared library + *************************************************************************************/ + +#ifdef GTK_DECLARE_FUNCS + #define EXTERN + #ifndef NULL + #define NULL 0 + #endif + #define DECL(ret, f, arg1) EXTERN ret (*f) arg1 = NULL; +#else + #ifdef GTK_LOAD_FUNCS + #define DECL(ret, f, arg1) loader(#f, (void **) &f, user_data); + #else + #define EXTERN extern + #define DECL(ret, f, arg1) EXTERN ret (*f) arg1; + #endif +#endif + +#ifndef GTK_IMPORTS_TYPES +#define GTK_IMPORTS_TYPES + +typedef void GtkWidget; +typedef void GtkWindow; +typedef void GtkApplication; +typedef void GApplication; +typedef void GObject; +typedef void *GCallback; +typedef void *gpointer; +typedef int gboolean; +typedef int gint; +typedef char gchar; +typedef void GClosure; +typedef void (*GClosureNotify) (gpointer data, GClosure *closure); + +typedef enum { + GTK_WINDOW_TOPLEVEL = 0 +} GtkWindowType; + +typedef enum { + G_APPLICATION_FLAGS_NONE = 0, + G_APPLICATION_DEFAULT_FLAGS = 0, + G_APPLICATION_IS_SERVICE = 1, + G_APPLICATION_IS_LAUNCHER = 2, + G_APPLICATION_HANDLES_OPEN = 4, + G_APPLICATION_HANDLES_COMMAND_LINE = 8, + G_APPLICATION_SEND_ENVIRONMENT = 16, + G_APPLICATION_NON_UNIQUE = 32, + G_APPLICATION_CAN_OVERRIDE_APP_ID = 64, + G_APPLICATION_ALLOW_REPLACEMENT = 128, + G_APPLICATION_REPLACE = 256 +} GApplicationFlags; + +typedef enum { + G_CONNECT_DEFAULT = 0, + G_CONNECT_AFTER = 1, + G_CONNECT_SWAPPED = 2 +} GConnectFlags; + +#endif + +DECL(GtkApplication *, gtk_application_new, (const char *name, GApplicationFlags flags)) +DECL(int, g_application_run, (GApplication* application, int argc, char** argv)) + +DECL(GtkWidget*, gtk_application_window_new, ( GtkApplication* application )) +DECL(GtkWidget *, gtk_window_new, (GtkWindowType)) +DECL(void, gtk_window_close, (GtkWindow *)) +DECL(void, gtk_widget_show_all, (GtkWindow *window)) +DECL(void, gtk_window_get_size, (GtkWindow *win, int *width, int *height)) +DECL(void, gtk_window_resize, (GtkWindow* window, gint width, gint height)) +DECL(void, gtk_window_set_default_size, (GtkWindow *window, gint width, gint height)) +DECL(void, gtk_window_get_position, (GtkWindow* window, gint* root_x, gint* root_y)) +DECL(void, gtk_window_move, (GtkWindow* window, gint x, gint y)) + +DECL(gboolean, gtk_window_get_decorated, (GtkWindow* window)) + +DECL(void, gtk_window_set_title, (GtkWindow* window, const gchar* title)) +DECL(const gchar*, gtk_window_get_title, (GtkWindow* window)) + +DECL(void, gtk_main, (void)) +DECL(void, gtk_main_quit, (void)) + +DECL(unsigned long, g_signal_connect_data, (GObject *obj, const char *signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags)) +DECL(void, g_object_unref, (GObject* object)) + +#define g_signal_connect(instance, signal, c_handler, data) \ + g_signal_connect_data(instance, signal, reinterpret_cast(c_handler), data, NULL, G_CONNECT_DEFAULT) + +#endif // GTK_IMPORTS_H diff --git a/gtkloader.cpp b/gtkloader.cpp new file mode 100644 index 0000000..34e7599 --- /dev/null +++ b/gtkloader.cpp @@ -0,0 +1,111 @@ +#include "gtkloader.h" + +extern "C" { +#include "gtk-imports.h" +} + +#include + +#ifdef _WIN32 +#include +#include +#endif + +void GtkLoader::loadLibraryWin64(const char *lib, void **handle) +{ +#ifdef _WIN32 + #define DIR "C:\\devel\\yellownotes\\gtk3\\bin" + HMODULE dll = nullptr; + std::string dir = DIR; + + *handle = nullptr; + + auto mklibname = [](const char *libname) { + std::string dll; + dll = std::string(DIR) + "\\" + libname + ".dll"; + return dll; + }; + + std::string library; + library = mklibname(lib); + + char *cwd = _getcwd(NULL, 0); + if (cwd == nullptr) { + throw std::string("Cannot get current working directory"); + } + + _chdir(dir.c_str()); + dll = LoadLibraryA(library.c_str()); + _chdir(cwd); + free(cwd); + if (dll == nullptr) { + throw std::string("Cannot load library '") + lib + "'"; + } + + *handle = reinterpret_cast(dll); +#endif +} + +void GtkLoader::loadFunctionWin64(const char *func, void **func_ptr) +{ +#ifdef _WIN32 + + FARPROC fp = nullptr; + std::list::const_iterator it = library_handles.begin(); + while (fp == nullptr && it != library_handles.end()) { + HMODULE handle = reinterpret_cast(*it); + fp = GetProcAddress(handle, func); + it++; + } + + *func_ptr = reinterpret_cast(fp); + if (fp == nullptr) { + throw std::string("Cannot load function '") + func; + } + +#endif +} + +void GtkLoader::dlopen() +{ + if (library_handles.size() == 0) { +#ifdef _WIN32 + const char *libs[] = { + "gobject-2.0-0", + "gtk-3-vs17", + "glib-2.0-0", + "gio-2.0-0", + NULL + }; + int i; + for(i = 0; libs[i] != NULL; i++) { + void *lib; + loadLibraryWin64(libs[i], &lib); + if (lib) { library_handles.push_back(lib); } + } +#endif + } +} + +void GtkLoader::loadFunction(const char *func, void **func_ptr) +{ +#ifdef _WIN32 + loadFunctionWin64(func, func_ptr); +#endif +} + +static void loader(const char *func, void **func_ptr, void *user_data) +{ + GtkLoader *l = reinterpret_cast(user_data); + l->loadFunction(func, func_ptr); +} + +void GtkLoader::loadGtk() +{ + dlopen(); + loadGtkFunctions(loader, this); +} + +GtkLoader::GtkLoader() +{ +} diff --git a/gtkloader.h b/gtkloader.h new file mode 100644 index 0000000..7866f02 --- /dev/null +++ b/gtkloader.h @@ -0,0 +1,26 @@ +#ifndef GTKLOADER_H +#define GTKLOADER_H + +#include + +class GtkLoader +{ +private: + std::list library_handles; + +private: + void loadLibraryWin64(const char *lib, void **handle); + void loadFunctionWin64(const char *func, void **func_ptr); + +public: + void dlopen(); + void loadFunction(const char *func, void **func_ptr); + +public: + void loadGtk(); + +public: + GtkLoader(); +}; + +#endif // GTKLOADER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..90eb865 --- /dev/null +++ b/main.cpp @@ -0,0 +1,38 @@ +#include +#include "gtkloader.h" + +extern "C" { +#include "gtk-imports.h" +} + +static void activate (GtkApplication* app, gpointer user_data) +{ + GtkWidget *window; + + window = gtk_application_window_new (app); + gtk_window_set_title (window, "Window"); + gtk_window_set_default_size (window, 200, 200); + gtk_widget_show_all (window); +} + +int main(int argc, char **argv) +{ + GtkLoader l; + + try { + l.loadGtk(); + } catch(std::string msg) { + std::cerr << msg << std::endl; + } + + GtkApplication *app; + int status; + + app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); + g_signal_connect (app, "activate", activate, NULL); + status = g_application_run (app, argc, argv); + g_object_unref (app); + + return status; +} +