lv2 ui bridges: dlopen gtk instead of linking to it

Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
falkTX 2021-08-18 14:07:39 +01:00
parent bef7663b54
commit 60ed20e120
No known key found for this signature in database
GPG Key ID: CDBAA37ABC74FBA0
4 changed files with 273 additions and 72 deletions

View File

@ -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"

View File

@ -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)

View File

@ -1,6 +1,6 @@
/*
* Carla Bridge UI
* Copyright (C) 2011-2017 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2011-2021 Filipe Coelho <falktx@falktx.com>
*
* 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 <gtk/gtk.h>
#include <glib.h>
#include <glib-object.h>
#ifdef HAVE_X11
# include <gdk/gdkx.h>
# include <X11/Xlib.h>
#endif
// #include <gtk/gtk.h>
// #ifdef HAVE_X11
// # include <gdk/gdkx.h>
// #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<gtksym_##NAME>(lib, "gtk_" #NAME); \
CARLA_SAFE_ASSERT_RETURN(NAME != nullptr,);
#define GDK_LIB_SYMBOL(NAME) \
NAME = lib_symbol<gdksym_##NAME>(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;
fWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
static int gargc = 0;
static char** gargv = nullptr;
gtk.init(&gargc, &gargv);
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<gint>(width), static_cast<gint>(height));
gtk.window_resize(GTK_WINDOW(fWindow), static_cast<int>(width), static_cast<int>(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);

View File

@ -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