From 60ed20e1204f19a5de593aeec89780af9d70724a Mon Sep 17 00:00:00 2001 From: falkTX Date: Wed, 18 Aug 2021 14:07:39 +0100 Subject: [PATCH] lv2 ui bridges: dlopen gtk instead of linking to it Signed-off-by: falkTX --- Makefile.print.mk | 8 +- source/Makefile.mk | 9 +- source/bridges-ui/CarlaBridgeToolkitGtk.cpp | 302 +++++++++++++++++--- source/bridges-ui/Makefile | 26 +- 4 files changed, 273 insertions(+), 72 deletions(-) diff --git a/Makefile.print.mk b/Makefile.print.mk index 8a2d745b2..27cdb5a5d 100644 --- a/Makefile.print.mk +++ b/Makefile.print.mk @@ -149,15 +149,15 @@ endif # MACOS @printf -- "$(tS)---> LV2 UI toolkit support: $(tE)\n" @printf -- "External: $(ANS_YES) (direct)\n" ifneq ($(MACOS_OR_WIN32),true) -ifeq ($(HAVE_GTK2),true) +ifeq ($(HAVE_GOBJECT),true) @printf -- "Gtk2: $(ANS_YES) (bridge)\n" else - @printf -- "Gtk2: $(ANS_NO) $(mS)Gtk2 missing$(mE)\n" + @printf -- "Gtk2: $(ANS_NO) $(mS)gobject missing$(mE)\n" endif -ifeq ($(HAVE_GTK3),true) +ifeq ($(HAVE_GOBJECT),true) @printf -- "Gtk3: $(ANS_YES) (bridge)\n" else - @printf -- "Gtk3: $(ANS_NO) $(mS)Gtk3 missing$(mE)\n" + @printf -- "Gtk3: $(ANS_NO) $(mS)gobject missing$(mE)\n" endif ifeq ($(HAVE_QT4),true) @printf -- "Qt4: $(ANS_YES) (bridge)\n" diff --git a/source/Makefile.mk b/source/Makefile.mk index d471dcb89..704a88a4a 100644 --- a/source/Makefile.mk +++ b/source/Makefile.mk @@ -297,12 +297,11 @@ HAVE_HYLIA = true endif ifeq ($(MACOS_OR_WIN32),true) -HAVE_DGL = true +HAVE_DGL = true else -HAVE_DGL = $(shell $(PKG_CONFIG) --exists gl x11 && echo true) -HAVE_GTK2 = $(shell $(PKG_CONFIG) --exists gtk+-2.0 && echo true) -HAVE_GTK3 = $(shell $(PKG_CONFIG) --exists gtk+-3.0 && echo true) -HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) +HAVE_DGL = $(shell $(PKG_CONFIG) --exists gl x11 && echo true) +HAVE_GOBJECT = $(shell $(PKG_CONFIG) --exists glib-2.0 gobject-2.0 && echo true) +HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) endif ifeq ($(UNIX),true) diff --git a/source/bridges-ui/CarlaBridgeToolkitGtk.cpp b/source/bridges-ui/CarlaBridgeToolkitGtk.cpp index 778744db0..283c61c45 100644 --- a/source/bridges-ui/CarlaBridgeToolkitGtk.cpp +++ b/source/bridges-ui/CarlaBridgeToolkitGtk.cpp @@ -1,6 +1,6 @@ /* * Carla Bridge UI - * Copyright (C) 2011-2017 Filipe Coelho + * Copyright (C) 2011-2021 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,19 +17,212 @@ #include "CarlaBridgeFormat.hpp" #include "CarlaBridgeToolkit.hpp" +#include "CarlaLibUtils.hpp" -#include +#include +#include #ifdef HAVE_X11 -# include +# include +#endif + +// #include + +// #ifdef HAVE_X11 +// # include +// #endif + +// #undef GTK_TYPE_CONTAINER +// #define GTK_TYPE_CONTAINER (gtk.container_get_type()) +// +// #undef GTK_TYPE_WINDOW +// #define GTK_TYPE_WINDOW (gtk.window_get_type()) + +#define GTK_CONTAINER(G) ((GtkContainer*)G) +#define GTK_WINDOW(G) ((GtkWindow*)G) + +struct GdkDisplay; +struct GdkDrawable; +struct GdkWindow; + +struct GtkContainer; +struct GtkWidget; +struct GtkWindow; + +enum GtkWindowType { + GTK_WINDOW_TOPLEVEL +}; + +typedef void (*gtksym_init)(int* argc, char*** argv); +typedef void (*gtksym_main)(void); +typedef uint (*gtksym_main_level)(void); +typedef void (*gtksym_main_quit)(void); +typedef GType (*gtksym_container_get_type)(void) G_GNUC_CONST; +typedef void (*gtksym_container_add)(GtkContainer* container, GtkWidget* widget); +typedef void (*gtksym_widget_destroy)(GtkWidget* widget); +typedef void (*gtksym_widget_hide)(GtkWidget* widget); +typedef void (*gtksym_widget_show_all)(GtkWidget* widget); +typedef GType (*gtksym_window_get_type)(void) G_GNUC_CONST; +typedef GtkWidget* (*gtksym_window_new)(GtkWindowType type); +typedef void (*gtksym_window_get_position)(GtkWindow* window, int* root_x, int* root_y); +typedef void (*gtksym_window_get_size)(GtkWindow* window, int* width, int* height); +typedef void (*gtksym_window_resize)(GtkWindow* window, int width, int height); +typedef void (*gtksym_window_set_resizable)(GtkWindow* window, int resizable); +typedef void (*gtksym_window_set_title)(GtkWindow* window, const char* title); +#ifdef HAVE_X11 +typedef GdkWindow* (*gtksym_widget_get_window)(GtkWidget* widget); +# ifdef BRIDGE_GTK3 +typedef GdkDisplay* (*gdksym_window_get_display)(GdkWindow* window); +typedef Display* (*gdksym_x11_display_get_xdisplay)(GdkDisplay* display); +typedef Window (*gdksym_x11_window_get_xid)(GdkWindow* window); +# else +typedef Display* (*gdksym_x11_drawable_get_xdisplay)(GdkDrawable* drawable); +typedef XID (*gdksym_x11_drawable_get_xid)(GdkDrawable* drawable); +# endif #endif CARLA_BRIDGE_UI_START_NAMESPACE // ------------------------------------------------------------------------- -static int gargc = 0; -static char** gargv = nullptr; +struct GtkLoader { + void* lib; + gtksym_init init; + gtksym_main main; + gtksym_main_level main_level; + gtksym_main_quit main_quit; + gtksym_container_get_type container_get_type; + gtksym_container_add container_add; + gtksym_widget_destroy widget_destroy; + gtksym_widget_hide widget_hide; + gtksym_widget_show_all widget_show_all; + gtksym_window_get_type window_get_type; + gtksym_window_new window_new; + gtksym_window_get_position window_get_position; + gtksym_window_get_size window_get_size; + gtksym_window_resize window_resize; + gtksym_window_set_resizable window_set_resizable; + gtksym_window_set_title window_set_title; + bool ok; + +#ifdef HAVE_X11 + gtksym_widget_get_window widget_get_window; +# ifdef BRIDGE_GTK3 + gdksym_window_get_display window_get_display; + gdksym_x11_display_get_xdisplay x11_display_get_xdisplay; + gdksym_x11_window_get_xid x11_window_get_xid; +# else + gdksym_x11_drawable_get_xdisplay x11_drawable_get_xdisplay; + gdksym_x11_drawable_get_xid x11_drawable_get_xid; +# endif +#endif + + GtkLoader() + : lib(nullptr), + init(nullptr), + main(nullptr), + main_level(nullptr), + main_quit(nullptr), + container_get_type(nullptr), + container_add(nullptr), + widget_destroy(nullptr), + widget_hide(nullptr), + widget_show_all(nullptr), + window_get_type(nullptr), + window_new(nullptr), + window_get_position(nullptr), + window_get_size(nullptr), + window_resize(nullptr), + window_set_resizable(nullptr), + window_set_title(nullptr), + ok(false) +#ifdef HAVE_X11 + , widget_get_window(nullptr), +# ifdef BRIDGE_GTK3 + window_get_display(nullptr), + x11_display_get_xdisplay(nullptr), + x11_window_get_xid(nullptr) +# else + x11_drawable_get_xdisplay(nullptr), + x11_drawable_get_xid(nullptr) +# endif +#endif + { +#ifdef BRIDGE_GTK3 + const char* const filename = "libgtk-3.so.0"; +#else + const char* const filename = "libgtk-x11-2.0.so.0"; +#endif + lib = lib_open(filename); + + if (lib == nullptr) + { + fprintf(stderr, "Failed to load Gtk, reason:\n%s\n", lib_error(filename)); + return; + } + else + { + fprintf(stdout, "%s loaded successfully!\n", filename); + } + + #define GTK_LIB_SYMBOL(NAME) \ + NAME = lib_symbol(lib, "gtk_" #NAME); \ + CARLA_SAFE_ASSERT_RETURN(NAME != nullptr,); + + #define GDK_LIB_SYMBOL(NAME) \ + NAME = lib_symbol(lib, "gdk_" #NAME); + + GTK_LIB_SYMBOL(init) + GTK_LIB_SYMBOL(main) + GTK_LIB_SYMBOL(main_level) + GTK_LIB_SYMBOL(main_quit) + GTK_LIB_SYMBOL(container_get_type) + GTK_LIB_SYMBOL(container_add) + GTK_LIB_SYMBOL(widget_destroy) + GTK_LIB_SYMBOL(widget_hide) + GTK_LIB_SYMBOL(widget_show_all) + GTK_LIB_SYMBOL(window_get_type) + GTK_LIB_SYMBOL(window_new) + GTK_LIB_SYMBOL(window_get_position) + GTK_LIB_SYMBOL(window_get_size) + GTK_LIB_SYMBOL(window_resize) + GTK_LIB_SYMBOL(window_set_resizable) + GTK_LIB_SYMBOL(window_set_title) + + ok = true; + +#ifdef HAVE_X11 + GTK_LIB_SYMBOL(widget_get_window) +# ifdef BRIDGE_GTK3 + GDK_LIB_SYMBOL(window_get_display) + GDK_LIB_SYMBOL(x11_display_get_xdisplay) + GDK_LIB_SYMBOL(x11_window_get_xid) +# else + GDK_LIB_SYMBOL(x11_drawable_get_xdisplay) + GDK_LIB_SYMBOL(x11_drawable_get_xid) +# endif +#endif + + #undef GDK_LIB_SYMBOL + #undef GTK_LIB_SYMBOL + } + + ~GtkLoader() + { + if (lib != nullptr) + lib_close(lib); + } + + void main_quit_if_needed() + { + if (main_level() != 0) + main_quit(); + } + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(GtkLoader) +}; + +// ------------------------------------------------------------------------- static const bool gHideShowTesting = std::getenv("CARLA_UI_TESTING") != nullptr; @@ -40,6 +233,7 @@ class CarlaBridgeToolkitGtk : public CarlaBridgeToolkit public: CarlaBridgeToolkitGtk(CarlaBridgeFormat* const format) : CarlaBridgeToolkit(format), + gtk(), fNeedsShow(false), fWindow(nullptr), fLastX(0), @@ -61,13 +255,18 @@ public: CARLA_SAFE_ASSERT_RETURN(fWindow == nullptr, false); carla_debug("CarlaBridgeToolkitGtk::init()"); - gtk_init(&gargc, &gargv); + if (! gtk.ok) + return false; + + static int gargc = 0; + static char** gargv = nullptr; + gtk.init(&gargc, &gargv); - fWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); + fWindow = gtk.window_new(GTK_WINDOW_TOPLEVEL); CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr, false); - gtk_window_resize(GTK_WINDOW(fWindow), 30, 30); - gtk_widget_hide(fWindow); + gtk.window_resize(GTK_WINDOW(fWindow), 30, 30); + gtk.widget_hide(fWindow); return true; } @@ -84,10 +283,10 @@ public: CARLA_SAFE_ASSERT_RETURN(gtkWindow != nullptr,); GtkWidget* const widget((GtkWidget*)fPlugin->getWidget()); - gtk_container_add(GTK_CONTAINER(fWindow), widget); + gtk.container_add(GTK_CONTAINER(fWindow), widget); - gtk_window_set_resizable(gtkWindow, options.isResizable); - gtk_window_set_title(gtkWindow, options.windowTitle.buffer()); + gtk.window_set_resizable(gtkWindow, options.isResizable); + gtk.window_set_title(gtkWindow, options.windowTitle.buffer()); if (showUI || fNeedsShow) { @@ -103,7 +302,7 @@ public: handleTimeout(); // Main loop - gtk_main(); + gtk.main(); } void quit() override @@ -112,10 +311,10 @@ public: if (fWindow != nullptr) { - gtk_widget_destroy(fWindow); + gtk.widget_destroy(fWindow); fWindow = nullptr; - gtk_main_quit_if_needed(); + gtk.main_quit_if_needed(); } } @@ -126,7 +325,7 @@ public: fNeedsShow = true; if (fWindow != nullptr) - gtk_widget_show_all(fWindow); + gtk.widget_show_all(fWindow); } void focus() override @@ -141,7 +340,7 @@ public: fNeedsShow = false; if (fWindow != nullptr) - gtk_widget_hide(fWindow); + gtk.widget_hide(fWindow); } void setChildWindow(void* const) override {} @@ -151,7 +350,7 @@ public: CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); carla_debug("CarlaBridgeToolkitGtk::resize(%i, %i)", width, height); - gtk_window_resize(GTK_WINDOW(fWindow), static_cast(width), static_cast(height)); + gtk.window_resize(GTK_WINDOW(fWindow), static_cast(width), static_cast(height)); } void setTitle(const char* const title) override @@ -159,43 +358,47 @@ public: CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); carla_debug("CarlaBridgeToolkitGtk::setTitle(\"%s\")", title); - gtk_window_set_title(GTK_WINDOW(fWindow), title); + gtk.window_set_title(GTK_WINDOW(fWindow), title); } // --------------------------------------------------------------------- protected: + GtkLoader gtk; bool fNeedsShow; GtkWidget* fWindow; - gint fLastX; - gint fLastY; - gint fLastWidth; - gint fLastHeight; + int fLastX; + int fLastY; + int fLastWidth; + int fLastHeight; void handleDestroy() { carla_debug("CarlaBridgeToolkitGtk::handleDestroy()"); fWindow = nullptr; + gtk.main_quit_if_needed(); } void handleRealize() { carla_debug("CarlaBridgeToolkitGtk::handleRealize()"); +#ifdef HAVE_X11 const CarlaBridgeFormat::Options& options(fPlugin->getOptions()); if (options.transientWindowId != 0) setTransient(options.transientWindowId); +#endif } - gboolean handleTimeout() + int handleTimeout() { if (fWindow != nullptr) { - gtk_window_get_position(GTK_WINDOW(fWindow), &fLastX, &fLastY); - gtk_window_get_size(GTK_WINDOW(fWindow), &fLastWidth, &fLastHeight); + gtk.window_get_position(GTK_WINDOW(fWindow), &fLastX, &fLastY); + gtk.window_get_size(GTK_WINDOW(fWindow), &fLastWidth, &fLastHeight); } if (fPlugin->isPipeRunning()) @@ -219,64 +422,73 @@ protected: } } - return true; + return 1; } +#ifdef HAVE_X11 void setTransient(const uintptr_t winId) { CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); carla_debug("CarlaBridgeToolkitGtk::setTransient(0x" P_UINTPTR ")", winId); -#ifdef HAVE_X11 - GdkWindow* const gdkWindow(gtk_widget_get_window(fWindow)); + if (gtk.widget_get_window == nullptr) + return; +# ifdef BRIDGE_GTK3 + if (gtk.window_get_display == nullptr) + return; + if (gtk.x11_display_get_xdisplay == nullptr) + return; + if (gtk.x11_window_get_xid == nullptr) + return; +# else + if (gtk.x11_drawable_get_xdisplay == nullptr) + return; + if (gtk.x11_drawable_get_xid == nullptr) + return; +# endif + + GdkWindow* const gdkWindow = gtk.widget_get_window(fWindow); CARLA_SAFE_ASSERT_RETURN(gdkWindow != nullptr,); # ifdef BRIDGE_GTK3 - GdkDisplay* const gdkDisplay(gdk_window_get_display(gdkWindow)); + GdkDisplay* const gdkDisplay = gtk.window_get_display(gdkWindow); CARLA_SAFE_ASSERT_RETURN(gdkDisplay != nullptr,); - ::Display* const display(gdk_x11_display_get_xdisplay(gdkDisplay)); + ::Display* const display = gtk.x11_display_get_xdisplay(gdkDisplay); CARLA_SAFE_ASSERT_RETURN(display != nullptr,); - const ::XID xid(gdk_x11_window_get_xid(gdkWindow)); + const ::XID xid = gtk.x11_window_get_xid(gdkWindow); CARLA_SAFE_ASSERT_RETURN(xid != 0,); # else - ::Display* const display(gdk_x11_drawable_get_xdisplay(gdkWindow)); + ::Display* const display = gtk.x11_drawable_get_xdisplay((GdkDrawable*)gdkWindow); CARLA_SAFE_ASSERT_RETURN(display != nullptr,); - const ::XID xid(gdk_x11_drawable_get_xid(gdkWindow)); + const ::XID xid = gtk.x11_drawable_get_xid((GdkDrawable*)gdkWindow); CARLA_SAFE_ASSERT_RETURN(xid != 0,); # endif XSetTransientForHint(display, xid, static_cast< ::Window>(winId)); -#endif } +#endif // --------------------------------------------------------------------- private: - static void gtk_main_quit_if_needed() - { - if (gtk_main_level() != 0) - gtk_main_quit(); - } - - static void gtk_ui_destroy(GtkWidget*, gpointer data) + static void gtk_ui_destroy(GtkWidget*, void* data) { CARLA_SAFE_ASSERT_RETURN(data != nullptr,); ((CarlaBridgeToolkitGtk*)data)->handleDestroy(); - gtk_main_quit_if_needed(); } - static void gtk_ui_realize(GtkWidget*, gpointer data) + static void gtk_ui_realize(GtkWidget*, void* data) { CARLA_SAFE_ASSERT_RETURN(data != nullptr,); ((CarlaBridgeToolkitGtk*)data)->handleRealize(); } - static gboolean gtk_ui_timeout(gpointer data) + static int gtk_ui_timeout(void* data) { CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); diff --git a/source/bridges-ui/Makefile b/source/bridges-ui/Makefile index 13b121622..7a4f3bea5 100644 --- a/source/bridges-ui/Makefile +++ b/source/bridges-ui/Makefile @@ -27,14 +27,14 @@ LINK_FLAGS += $(WATER_LIBS) -lpthread # --------------------------------------------------------------------------------------------------------------------- -BUILD_GTK2_FLAGS = $(BUILD_CXX_FLAGS) -DBRIDGE_GTK2 $(shell pkg-config --cflags gtk+-2.0) -LINK_GTK2_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs gtk+-2.0) $(LIBDL_LIBS) +BUILD_GTK2_FLAGS = $(BUILD_CXX_FLAGS) -DBRIDGE_GTK2 $(shell pkg-config --cflags glib-2.0 gobject-2.0) $(X11_FLAGS) +LINK_GTK2_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs glib-2.0 gobject-2.0) $(X11_LIBS) $(LIBDL_LIBS) -BUILD_GTK3_FLAGS = $(BUILD_CXX_FLAGS) -DBRIDGE_GTK3 $(shell pkg-config --cflags gtk+-3.0) -LINK_GTK3_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs gtk+-3.0) $(LIBDL_LIBS) +BUILD_GTK3_FLAGS = $(BUILD_CXX_FLAGS) -DBRIDGE_GTK3 $(shell pkg-config --cflags glib-2.0 gobject-2.0) $(X11_FLAGS) +LINK_GTK3_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs glib-2.0 gobject-2.0) $(X11_LIBS) $(LIBDL_LIBS) -BUILD_QT4_FLAGS = $(BUILD_CXX_FLAGS) -DBRIDGE_QT4 $(shell pkg-config --cflags QtCore QtGui) -I$(OBJDIR) -I$(CWD)/theme -Wno-unused-variable -LINK_QT4_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs QtCore QtGui) $(LIBDL_LIBS) +BUILD_QT4_FLAGS = $(BUILD_CXX_FLAGS) -DBRIDGE_QT4 $(shell pkg-config --cflags QtCore QtGui) $(X11_FLAGS) -I$(OBJDIR) -I$(CWD)/theme -Wno-unused-variable +LINK_QT4_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs QtCore QtGui) $(X11_LIBS) $(LIBDL_LIBS) BUILD_QT5_FLAGS = $(BUILD_CXX_FLAGS) -DBRIDGE_QT5 $(shell pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets) -I$(OBJDIR) -I$(CWD)/theme LINK_QT5_FLAGS = $(LINK_FLAGS) $(shell pkg-config --libs Qt5Core Qt5Gui Qt5Widgets) $(LIBDL_LIBS) @@ -48,17 +48,7 @@ LINK_COCOA_FLAGS = $(LINK_FLAGS) -framework Cocoa $(LIBDL_LIBS) BUILD_WINDOWS_FLAGS = $(BUILD_CXX_FLAGS) -DBRIDGE_HWND LINK_WINDOWS_FLAGS = $(LINK_FLAGS) -static -mwindows -ifeq ($(HAVE_X11),true) -LINK_GTK2_FLAGS += -lX11 -LINK_GTK3_FLAGS += -lX11 -LINK_QT4_FLAGS += -lX11 -endif - ifeq ($(TESTBUILD),true) -BUILD_GTK2_FLAGS += -isystem /usr/include/glib-2.0 -BUILD_GTK2_FLAGS += -isystem /usr/include/gtk-2.0 -BUILD_GTK3_FLAGS += -isystem /usr/include/glib-2.0 -BUILD_GTK3_FLAGS += -isystem /usr/include/gtk-3.0 BUILD_QT4_FLAGS += -isystem /usr/include/qt4 BUILD_QT5_FLAGS += -isystem /usr/include/qt5 BUILD_QT5_FLAGS += -isystem /usr/include/x86_64-linux-gnu/qt5 @@ -67,11 +57,11 @@ endif # --------------------------------------------------------------------------------------------------------------------- ifneq ($(MACOS_OR_WIN32),true) -ifeq ($(HAVE_GTK2),true) +ifeq ($(HAVE_GOBJECT),true) TARGETS += ui_lv2-gtk2 endif -ifeq ($(HAVE_GTK3),true) +ifeq ($(HAVE_GOBJECT),true) TARGETS += ui_lv2-gtk3 endif