diff --git a/CMakeLists.txt b/CMakeLists.txt index 15c7247..6bf1930 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,14 +5,19 @@ # https://github.com/desktop-app/legal/blob/master/LEGAL add_subdirectory(external) -if (DESKTOP_APP_USE_GLIBC_WRAPS) - add_subdirectory(linux_glibc_wraps) -endif() if (LINUX AND NOT DESKTOP_APP_USE_PACKAGED AND Qt5WaylandClient_FOUND) add_subdirectory(linux_wayland_helper) endif() +if (LINUX + AND NOT DESKTOP_APP_USE_PACKAGED + AND NOT DESKTOP_APP_DISABLE_GTK_INTEGRATION) + add_subdirectory(linux_gtk_helper) +endif() if (DESKTOP_APP_USE_ALLOCATION_TRACER) add_subdirectory(linux_allocation_tracer) endif() +if (WIN32) + add_subdirectory(win_directx_helper) +endif() diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 91a7806..118178c 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -11,6 +11,7 @@ macro(add_checked_subdirectory name) endif() endmacro() +add_checked_subdirectory(angle) add_checked_subdirectory(auto_updates) add_checked_subdirectory(crash_reports) if (LINUX AND NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION) @@ -36,14 +37,14 @@ if (add_hunspell_library) add_checked_subdirectory(hunspell) endif() add_checked_subdirectory(iconv) +if (LINUX) + add_checked_subdirectory(jemalloc) +endif() add_checked_subdirectory(jpeg) if (LINUX AND NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION) add_checked_subdirectory(kwayland) endif() add_checked_subdirectory(lz4) -if (LINUX) - add_checked_subdirectory(mallocng) -endif() add_checked_subdirectory(minizip) if (LINUX) add_checked_subdirectory(nimf_qt5) diff --git a/external/angle/CMakeLists.txt b/external/angle/CMakeLists.txt new file mode 100644 index 0000000..a646db2 --- /dev/null +++ b/external/angle/CMakeLists.txt @@ -0,0 +1,24 @@ +# This file is part of Desktop App Toolkit, +# a set of libraries for developing nice desktop applications. +# +# For license and copyright information please follow this link: +# https://github.com/desktop-app/legal/blob/master/LEGAL + +add_library(external_angle INTERFACE IMPORTED GLOBAL) +add_library(desktop-app::external_angle ALIAS external_angle) + +if (WIN32) + target_include_directories(external_angle + INTERFACE + ${libs_loc}/tg_angle/include + ) + target_link_libraries(external_angle + INTERFACE + ${libs_loc}/tg_angle/out/$,Debug,Release>/tg_angle.lib + dxguid.lib + ) + target_link_libraries(external_angle + INTERFACE + desktop-app::win_directx_helper + ) +endif() diff --git a/external/hime_qt/hime_im_client/CMakeLists.txt b/external/hime_qt/hime_im_client/CMakeLists.txt index 63773b0..9e70b1d 100644 --- a/external/hime_qt/hime_im_client/CMakeLists.txt +++ b/external/hime_qt/hime_im_client/CMakeLists.txt @@ -55,6 +55,20 @@ else() GTK_DISABLE_DEPRECATED ) + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_library(external_hime_im_client_options INTERFACE) + + target_compile_options(external_hime_im_client_options + INTERFACE + -Wno-sometimes-uninitialized + ) + + target_link_libraries(external_hime_im_client + PRIVATE + external_hime_im_client_options + ) + endif() + target_link_libraries(external_hime_im_client PRIVATE desktop-app::external_glib diff --git a/external/jemalloc/CMakeLists.txt b/external/jemalloc/CMakeLists.txt new file mode 100644 index 0000000..9d7ce2f --- /dev/null +++ b/external/jemalloc/CMakeLists.txt @@ -0,0 +1,58 @@ +# This file is part of Desktop App Toolkit, +# a set of libraries for developing nice desktop applications. +# +# For license and copyright information please follow this link: +# https://github.com/desktop-app/legal/blob/master/LEGAL + +add_library(external_jemalloc INTERFACE IMPORTED GLOBAL) +add_library(desktop-app::external_jemalloc ALIAS external_jemalloc) + +if (DESKTOP_APP_USE_PACKAGED) + find_package(PkgConfig REQUIRED) + pkg_check_modules(JEMALLOC IMPORTED_TARGET jemalloc) + + if (JEMALLOC_FOUND) + target_link_libraries(external_jemalloc INTERFACE PkgConfig::JEMALLOC) + endif() +endif() + +if (NOT JEMALLOC_FOUND) + add_library(external_jemalloc_bundled STATIC IMPORTED GLOBAL) + + include(ExternalProject) + ExternalProject_Add(jemalloc + URL https://github.com/jemalloc/jemalloc/releases/download/5.2.1/jemalloc-5.2.1.tar.bz2 + CONFIGURE_COMMAND cd "${CMAKE_CURRENT_BINARY_DIR}/jemalloc-prefix/src/jemalloc" && ./configure + BUILD_IN_SOURCE 1 + ) + + ExternalProject_Get_property(jemalloc SOURCE_DIR) + ExternalProject_Get_property(jemalloc BINARY_DIR) + + file(MAKE_DIRECTORY "${SOURCE_DIR}/include") + + set_target_properties(external_jemalloc_bundled PROPERTIES + IMPORTED_LOCATION "${BINARY_DIR}/lib/libjemalloc.a" + ) + + target_include_directories(external_jemalloc_bundled + INTERFACE + ${SOURCE_DIR}/include + ) + + target_link_libraries(external_jemalloc_bundled + INTERFACE + dl + pthread + ) + + add_dependencies(external_jemalloc_bundled jemalloc) + + target_link_libraries(external_jemalloc + INTERFACE + -Wl,--whole-archive + $ + -Wl,--no-whole-archive + external_jemalloc_bundled + ) +endif() diff --git a/external/mallocng/CMakeLists.txt b/external/mallocng/CMakeLists.txt deleted file mode 100644 index c3d2422..0000000 --- a/external/mallocng/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# This file is part of Desktop App Toolkit, -# a set of libraries for developing nice desktop applications. -# -# For license and copyright information please follow this link: -# https://github.com/desktop-app/legal/blob/master/LEGAL - -add_library(external_mallocng INTERFACE IMPORTED GLOBAL) -add_library(desktop-app::external_mallocng ALIAS external_mallocng) - -add_library(external_mallocng_bundled STATIC) -init_target(external_mallocng_bundled "(external)") - -set(mallocng_loc ${third_party_loc}/mallocng) - -nice_target_sources(external_mallocng_bundled ${mallocng_loc} -PRIVATE - malloc.c - calloc.c - free.c - realloc.c - aligned_alloc.c - posix_memalign.c - memalign.c - malloc_usable_size.c - meta.h - glue.h - valloc.c - pvalloc.c -) - -target_compile_options(external_mallocng_bundled -PRIVATE - -Wno-unused-value -) - -target_include_directories(external_mallocng_bundled -PRIVATE - ${mallocng_loc} -) - -target_link_libraries(external_mallocng -INTERFACE - -Wl,--whole-archive - external_mallocng_bundled - -Wl,--no-whole-archive -) diff --git a/external/openssl/openssl_common/CMakeLists.txt b/external/openssl/openssl_common/CMakeLists.txt index e05ef9f..3343366 100644 --- a/external/openssl/openssl_common/CMakeLists.txt +++ b/external/openssl/openssl_common/CMakeLists.txt @@ -21,14 +21,6 @@ if (NOT DESKTOP_APP_USE_PACKAGED) endif() if (LINUX) - if (DESKTOP_APP_USE_GLIBC_WRAPS) - target_link_libraries(external_openssl_common - INTERFACE - desktop-app::linux_glibc_wraps - $ - ) - endif() - target_link_libraries(external_openssl_common INTERFACE ${CMAKE_DL_LIBS} diff --git a/external/qt/CMakeLists.txt b/external/qt/CMakeLists.txt index bd51d20..e7c78a8 100644 --- a/external/qt/CMakeLists.txt +++ b/external/qt/CMakeLists.txt @@ -157,6 +157,11 @@ else() foreach (lib ${qt_libs}) list(APPEND qt_libs_list "${qt_loc}/${lib}${qt_lib_suffix}") endforeach() + + target_link_libraries(external_qt + INTERFACE + desktop-app::external_angle + ) elseif (APPLE) if (NOT build_osx) set(qt_libs @@ -220,10 +225,17 @@ else() plugins/wayland-decoration-client/${qt_lib_prefix}bradient ) endif() + set(qt_libs_gtk_plugins) + if (NOT DESKTOP_APP_DISABLE_GTK_INTEGRATION) + set(qt_libs_gtk_plugins + plugins/platformthemes/${qt_lib_prefix}qgtk3 + ) + endif() set(qt_libs plugins/platforminputcontexts/${qt_lib_prefix}composeplatforminputcontextplugin ${qt_libs_dbus_plugins} ${qt_libs_waylandclient_plugins} + ${qt_libs_gtk_plugins} plugins/platforms/${qt_lib_prefix}qxcb plugins/xcbglintegrations/${qt_lib_prefix}qxcb-egl-integration plugins/xcbglintegrations/${qt_lib_prefix}qxcb-glx-integration @@ -287,26 +299,6 @@ else() -Wl,--no-as-needed,-lrt ) endif() - if (DESKTOP_APP_USE_GLIBC_WRAPS) - target_link_options(external_qt - INTERFACE - -Wl,-wrap,aligned_alloc - -Wl,-wrap,secure_getenv - -Wl,-wrap,clock_gettime - -Wl,--no-as-needed,-lrt - ) - if (NOT build_linux32) - target_link_options(external_qt - INTERFACE - -Wl,-wrap,__divmodti4 - ) - else() - target_link_options(external_qt - INTERFACE - -Wl,-wrap,__divmoddi4 - ) - endif() - endif() target_link_static_libraries(external_qt INTERFACE proxy @@ -335,13 +327,6 @@ else() $ ) endif() - if (DESKTOP_APP_USE_GLIBC_WRAPS) - target_link_libraries(external_qt - INTERFACE - desktop-app::linux_glibc_wraps - $ - ) - endif() if (Qt5WaylandClient_FOUND) target_link_libraries(external_qt INTERFACE @@ -349,6 +334,13 @@ else() $ ) endif() + if (NOT DESKTOP_APP_DISABLE_GTK_INTEGRATION) + target_link_libraries(external_qt + INTERFACE + desktop-app::linux_gtk_helper + $ + ) + endif() target_link_libraries(external_qt INTERFACE fontconfig diff --git a/external/qt/qt_static_plugins/qt_static_plugins.cpp b/external/qt/qt_static_plugins/qt_static_plugins.cpp index 9f0244b..71b4bad 100644 --- a/external/qt/qt_static_plugins/qt_static_plugins.cpp +++ b/external/qt/qt_static_plugins/qt_static_plugins.cpp @@ -39,6 +39,9 @@ Q_IMPORT_PLUGIN(QWaylandEglClientBufferPlugin) Q_IMPORT_PLUGIN(QWaylandWlShellIntegrationPlugin) Q_IMPORT_PLUGIN(QWaylandBradientDecorationPlugin) #endif // !DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION +#ifndef DESKTOP_APP_DISABLE_GTK_INTEGRATION +Q_IMPORT_PLUGIN(QGtk3ThemePlugin) +#endif // !DESKTOP_APP_DISABLE_GTK_INTEGRATION #endif // Q_OS_WIN | Q_OS_MAC | Q_OS_UNIX #endif // !DESKTOP_APP_USE_PACKAGED diff --git a/init_target.cmake b/init_target.cmake index e06deb5..3ee7e94 100644 --- a/init_target.cmake +++ b/init_target.cmake @@ -5,7 +5,7 @@ # https://github.com/desktop-app/legal/blob/master/LEGAL set(MAXIMUM_CXX_STANDARD cxx_std_20) -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(MAXIMUM_CXX_STANDARD cxx_std_17) endif() diff --git a/linux_glibc_wraps/CMakeLists.txt b/linux_glibc_wraps/CMakeLists.txt deleted file mode 100644 index 49a4329..0000000 --- a/linux_glibc_wraps/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of Desktop App Toolkit, -# a set of libraries for developing nice desktop applications. -# -# For license and copyright information please follow this link: -# https://github.com/desktop-app/legal/blob/master/LEGAL - -add_library(linux_glibc_wraps STATIC) -add_library(desktop-app::linux_glibc_wraps ALIAS linux_glibc_wraps) - -get_filename_component(src_loc . REALPATH) - -nice_target_sources(linux_glibc_wraps ${src_loc} -PRIVATE - platform/linux/linux_glibc_wraps.c - platform/linux/linux_glibc_wraps_32.c - platform/linux/linux_glibc_wraps_64.c -) -if (NOT build_linux32) - set_source_files_properties(${src_loc}/platform/linux/linux_glibc_wraps_32.c PROPERTIES HEADER_FILE_ONLY TRUE) -else() - set_source_files_properties(${src_loc}/platform/linux/linux_glibc_wraps_64.c PROPERTIES HEADER_FILE_ONLY TRUE) -endif() diff --git a/linux_glibc_wraps/platform/linux/linux_glibc_wraps.c b/linux_glibc_wraps/platform/linux/linux_glibc_wraps.c deleted file mode 100644 index 1770ab1..0000000 --- a/linux_glibc_wraps/platform/linux/linux_glibc_wraps.c +++ /dev/null @@ -1,29 +0,0 @@ -// This file is part of Desktop App Toolkit, -// a set of libraries for developing nice desktop applications. -// -// For license and copyright information please follow this link: -// https://github.com/desktop-app/legal/blob/master/LEGAL -// -#include -#include -#include - -void *__wrap_aligned_alloc(size_t alignment, size_t size) { - void *result = NULL; - return (posix_memalign(&result, alignment, size) == 0) - ? result - : NULL; -} - -int enable_secure_inited = 0; -int enable_secure = 1; - -char *__wrap_secure_getenv(const char *name) { - if (enable_secure_inited == 0) { - enable_secure_inited = 1; - enable_secure = (geteuid() != getuid()) - || (getegid() != getgid()); - } - return enable_secure ? NULL : getenv(name); -} - diff --git a/linux_glibc_wraps/platform/linux/linux_glibc_wraps_32.c b/linux_glibc_wraps/platform/linux/linux_glibc_wraps_32.c deleted file mode 100644 index 2a0890f..0000000 --- a/linux_glibc_wraps/platform/linux/linux_glibc_wraps_32.c +++ /dev/null @@ -1,49 +0,0 @@ -// This file is part of Desktop App Toolkit, -// a set of libraries for developing nice desktop applications. -// -// For license and copyright information please follow this link: -// https://github.com/desktop-app/legal/blob/master/LEGAL -// -#include -#include - -#if defined(_M_IX86) || defined(__i386__) -#define GETTIME_GLIBC_VERSION "2.2" -#elif defined(_M_ARM) || defined(__arm__) -#define GETTIME_GLIBC_VERSION "2.4" -#else -#error Please add glibc wraps for your architecture -#endif - -int __clock_gettime_glibc_old(clockid_t clk_id, struct timespec *tp); -__asm__(".symver __clock_gettime_glibc_old,clock_gettime@GLIBC_" GETTIME_GLIBC_VERSION); - -int __wrap_clock_gettime(clockid_t clk_id, struct timespec *tp) { - return __clock_gettime_glibc_old(clk_id, tp); -} - -uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p); - -int64_t __wrap___divmoddi4(int64_t num, int64_t den, int64_t *rem_p) { - int minus = 0; - int64_t v; - - if (num < 0) { - num = -num; - minus = 1; - } - if (den < 0) { - den = -den; - minus ^= 1; - } - - v = __udivmoddi4(num, den, (uint64_t *)rem_p); - if (minus) { - v = -v; - if (rem_p) - *rem_p = -(*rem_p); - } - - return v; -} - diff --git a/linux_glibc_wraps/platform/linux/linux_glibc_wraps_64.c b/linux_glibc_wraps/platform/linux/linux_glibc_wraps_64.c deleted file mode 100644 index 2d1ca15..0000000 --- a/linux_glibc_wraps/platform/linux/linux_glibc_wraps_64.c +++ /dev/null @@ -1,52 +0,0 @@ -// This file is part of Desktop App Toolkit, -// a set of libraries for developing nice desktop applications. -// -// For license and copyright information please follow this link: -// https://github.com/desktop-app/legal/blob/master/LEGAL -// -#include - -#if defined(_M_X64) || defined(__x86_64__) -#define GETTIME_GLIBC_VERSION "2.2.5" -#elif defined(__aarch64__) -#define GETTIME_GLIBC_VERSION "2.17" -#else -#error Please add glibc wraps for your architecture -#endif - -typedef unsigned int UTItype __attribute__ ((mode (TI))); -typedef int TItype __attribute__ ((mode (TI))); - -int __clock_gettime_glibc_old(clockid_t clk_id, struct timespec *tp); -__asm__(".symver __clock_gettime_glibc_old,clock_gettime@GLIBC_" GETTIME_GLIBC_VERSION); - - -int __wrap_clock_gettime(clockid_t clk_id, struct timespec *tp) { - return __clock_gettime_glibc_old(clk_id, tp); -} - -UTItype __udivmodti4(UTItype num, UTItype den, UTItype *rem_p); - -TItype __wrap___divmodti4(TItype num, TItype den, TItype *rem_p) { - int minus = 0; - TItype v; - - if (num < 0) { - num = -num; - minus = 1; - } - if (den < 0) { - den = -den; - minus ^= 1; - } - - v = __udivmodti4(num, den, (UTItype *)rem_p); - if (minus) { - v = -v; - if (rem_p) - *rem_p = -(*rem_p); - } - - return v; -} - diff --git a/linux_gtk_helper/CMakeLists.txt b/linux_gtk_helper/CMakeLists.txt new file mode 100644 index 0000000..32ec4aa --- /dev/null +++ b/linux_gtk_helper/CMakeLists.txt @@ -0,0 +1,24 @@ +# This file is part of Desktop App Toolkit, +# a set of libraries for developing nice desktop applications. +# +# For license and copyright information please follow this link: +# https://github.com/desktop-app/legal/blob/master/LEGAL + +add_library(linux_gtk_helper STATIC) +add_library(desktop-app::linux_gtk_helper ALIAS linux_gtk_helper) + +nice_target_sources(linux_gtk_helper ${CMAKE_CURRENT_SOURCE_DIR} +PRIVATE + linux_gtk_helper.cpp +) + +target_compile_definitions(linux_gtk_helper PRIVATE G_LOG_DOMAIN="GtkHelper") + +target_link_libraries(linux_gtk_helper +PUBLIC + desktop-app::external_glib +) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED gtk+-3.0) +target_include_directories(linux_gtk_helper PRIVATE ${GTK_INCLUDE_DIRS}) diff --git a/linux_gtk_helper/linux_gtk_helper.cpp b/linux_gtk_helper/linux_gtk_helper.cpp new file mode 100644 index 0000000..4cb4ea1 --- /dev/null +++ b/linux_gtk_helper/linux_gtk_helper.cpp @@ -0,0 +1,997 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// +#include +#include +#include +#include +#include +#include + +#define LOAD_SYMBOL(handle, func) LoadSymbol(handle, #func, func) + +namespace GtkHelper { +namespace { + +GdkPixbuf *(*gdk_pixbuf_new_from_file_at_size)( + const char *filename, + int width, + int height, + GError **error); +void (*gdk_window_focus)(GdkWindow *window, guint32 timestamp); +GdkDisplay *(*gdk_window_get_display)(GdkWindow *window); +void (*gdk_window_set_modal_hint)(GdkWindow *window, gboolean modal); +Display *(*gdk_x11_display_get_xdisplay)(GdkDisplay *display); +GType (*gdk_x11_window_get_type)(void); +Window (*gdk_x11_window_get_xid)(GdkWindow *window); +GType (*gtk_accel_label_get_type)(void); +void (*gtk_accel_label_set_accel)( + GtkAccelLabel *accel_label, + guint accelerator_key, + GdkModifierType accelerator_mods); +GtkWidget *(*gtk_bin_get_child)(GtkBin *bin); +GType (*gtk_bin_get_type)(void); +GType (*gtk_button_get_type)(void); +void (*gtk_button_set_label)(GtkButton *button, const gchar *label); +gboolean (*gtk_check_menu_item_get_active)(GtkCheckMenuItem *check_menu_item); +GType (*gtk_check_menu_item_get_type)(void); +GtkWidget* (*gtk_check_menu_item_new)(void); +void (*gtk_check_menu_item_set_active)( + GtkCheckMenuItem *check_menu_item, + gboolean is_active); +const gchar *(*gtk_check_version)( + guint required_major, + guint required_minor, + guint required_micro); +GtkClipboard *(*gtk_clipboard_get)(GdkAtom selection); +void (*gtk_clipboard_store)(GtkClipboard *clipboard); +GtkWidget *(*gtk_color_chooser_dialog_new)( + const gchar *title, + GtkWindow *parent); +GType (*gtk_color_chooser_get_type)(void); +void (*gtk_color_chooser_get_rgba)( + GtkColorChooser *chooser, + GdkRGBA *color); +void (*gtk_color_chooser_set_rgba)( + GtkColorChooser *chooser, + const GdkRGBA *color); +void (*gtk_color_chooser_set_use_alpha)( + GtkColorChooser *chooser, + gboolean use_alpha); +GType (*gtk_container_get_type)(void); +void (*gtk_container_remove)(GtkContainer *container, GtkWidget *widget); +GtkWidget *(*gtk_dialog_add_button)( + GtkDialog *dialog, + const gchar *button_text, + gint response_id); +GType (*gtk_dialog_get_type)(void); +GtkWidget* (*gtk_dialog_get_widget_for_response)( + GtkDialog *dialog, + gint response_id); +gint (*gtk_dialog_run)(GtkDialog *dialog); +void (*gtk_file_chooser_add_filter)( + GtkFileChooser *chooser, + GtkFileFilter *filter); +GType (*gtk_file_chooser_dialog_get_type)(void); +gchar *(*gtk_file_chooser_get_current_folder)(GtkFileChooser *chooser); +gchar *(*gtk_file_chooser_get_filename)(GtkFileChooser *chooser); +GSList *(*gtk_file_chooser_get_filenames)(GtkFileChooser *chooser); +GtkFileFilter *(*gtk_file_chooser_get_filter)(GtkFileChooser *chooser); +char *(*gtk_file_chooser_get_preview_filename)(GtkFileChooser *chooser); +GType (*gtk_file_chooser_get_type)(void); +void (*gtk_file_chooser_remove_filter)( + GtkFileChooser *chooser, + GtkFileFilter *filter); +gboolean (*gtk_file_chooser_select_filename)( + GtkFileChooser *chooser, + const char *filename); +void (*gtk_file_chooser_set_action)( + GtkFileChooser *chooser, + GtkFileChooserAction action); +void (*gtk_file_chooser_set_create_folders)( + GtkFileChooser *chooser, + gboolean create_folders); +gboolean (*gtk_file_chooser_set_current_folder)( + GtkFileChooser *chooser, + const gchar *filename); +void (*gtk_file_chooser_set_current_name)( + GtkFileChooser *chooser, + const gchar *name); +void (*gtk_file_chooser_set_do_overwrite_confirmation)( + GtkFileChooser *chooser, + gboolean do_overwrite_confirmation); +void (*gtk_file_chooser_set_filter)( + GtkFileChooser *chooser, + GtkFileFilter *filter); +void (*gtk_file_chooser_set_local_only)( + GtkFileChooser *chooser, + gboolean local_only); +void (*gtk_file_chooser_set_preview_widget)( + GtkFileChooser *chooser, + GtkWidget *preview_widget); +void (*gtk_file_chooser_set_preview_widget_active)( + GtkFileChooser *chooser, + gboolean active); +void (*gtk_file_chooser_set_select_multiple)( + GtkFileChooser *chooser, + gboolean select_multiple); +void (*gtk_file_filter_add_pattern)( + GtkFileFilter *filter, + const gchar *pattern); +GtkFileFilter *(*gtk_file_filter_new)(void); +void (*gtk_file_filter_set_name)( + GtkFileFilter *filter, + const gchar *name); +GtkWidget* (*gtk_font_chooser_dialog_new)( + const gchar *title, + GtkWindow *parent); +gchar* (*gtk_font_chooser_get_font)(GtkFontChooser *fontchooser); +GType (*gtk_font_chooser_get_type)(void); +void (*gtk_font_chooser_set_font)( + GtkFontChooser *fontchooser, + const gchar *fontname); +guint32 (*gtk_get_current_event_time)(void); +GType (*gtk_image_get_type)(void); +GtkWidget* (*gtk_image_new)(void); +void (*gtk_image_set_from_pixbuf)(GtkImage *image, GdkPixbuf *pixbuf); +void (*gtk_init)(int *argc, char ***argv); +GType (*gtk_menu_get_type)(void); +GType (*gtk_menu_item_get_type)(void); +GtkWidget* (*gtk_menu_item_new)(void); +void (*gtk_menu_item_set_label)(GtkMenuItem *menu_item, const gchar *label); +void (*gtk_menu_item_set_submenu)(GtkMenuItem *menu_item, GtkWidget *submenu); +void (*gtk_menu_item_set_use_underline)( + GtkMenuItem *menu_item, + gboolean setting); +GtkWidget* (*gtk_menu_new)(void); +void (*gtk_menu_popdown)(GtkMenu *menu); +void (*gtk_menu_popup)( + GtkMenu *menu, + GtkWidget *parent_menu_shell, + GtkWidget *parent_menu_item, + GtkMenuPositionFunc func, + gpointer data, + guint button, + guint32 activate_time); +GType (*gtk_menu_shell_get_type)(void); +void (*gtk_menu_shell_insert)( + GtkMenuShell *menu_shell, + GtkWidget *child, + gint position); +void (*gtk_menu_shell_select_item)( + GtkMenuShell *menu_shell, + GtkWidget *menu_item); +GtkWidget* (*gtk_separator_menu_item_new)(void); +GtkSettings* (*gtk_settings_get_default)(void); +void (*gtk_widget_destroy)(GtkWidget *widget); +gint (*gtk_widget_get_scale_factor)(GtkWidget *widget); +GType (*gtk_widget_get_type)(void); +GdkWindow *(*gtk_widget_get_window)(GtkWidget *widget); +void (*gtk_widget_hide)(GtkWidget *widget); +gboolean (*gtk_widget_hide_on_delete)(GtkWidget *widget); +void (*gtk_widget_realize)(GtkWidget *widget); +void (*gtk_widget_set_sensitive)(GtkWidget *widget, gboolean sensitive); +void (*gtk_widget_set_visible)(GtkWidget *widget, gboolean visible); +void (*gtk_widget_show)(GtkWidget *widget); +GType (*gtk_window_get_type)(void); +void (*gtk_window_set_title)(GtkWindow *window, const gchar *title); +void (*gtk_window_set_transient_for)(GtkWindow *window, GtkWindow *parent); +void (*pango_font_description_free)(PangoFontDescription *desc); +PangoFontDescription *(*pango_font_description_from_string)(const char *str); +const char *(*pango_font_description_get_family)( + const PangoFontDescription *desc); +gint (*pango_font_description_get_size)(const PangoFontDescription *desc); +PangoStyle (*pango_font_description_get_style)( + const PangoFontDescription *desc); +PangoWeight (*pango_font_description_get_weight)( + const PangoFontDescription *desc); +PangoFontDescription *(*pango_font_description_new)(void); +void (*pango_font_description_set_family)( + PangoFontDescription *desc, + const char *family); +void (*pango_font_description_set_size)( + PangoFontDescription *desc, + gint size); +void (*pango_font_description_set_style)( + PangoFontDescription *desc, + PangoStyle style); +void (*pango_font_description_set_weight)( + PangoFontDescription *desc, + PangoWeight weight); +char *(*pango_font_description_to_string)(const PangoFontDescription *desc); +GType (*pango_font_face_get_type)(void); +GType (*pango_font_family_get_type)(void); + +struct HandleDeleter { + void operator()(void *handle) { + dlclose(handle); + } +}; + +using Handle = std::unique_ptr; + +bool LoadLibrary(Handle &handle, const char *name) { + handle = Handle(dlopen(name, RTLD_LAZY | RTLD_NODELETE)); + if (handle) { + return true; + } + g_warning("Could not load library '%s': %s", name, dlerror()); + return false; +} + +template +inline bool LoadSymbol(const Handle &handle, const char *name, Function &func) { + func = handle + ? reinterpret_cast(dlsym(handle.get(), name)) + : nullptr; + if (const auto error = dlerror()) { + g_warning("Failed to load function '%s': %s", name, error); + } + return (func != nullptr); +} + +bool Resolve() { + static const auto loaded = [&] { + auto lib = Handle(); + return LoadLibrary(lib, "libgtk-3.so.0") + && LOAD_SYMBOL(lib, gdk_pixbuf_new_from_file_at_size) + && LOAD_SYMBOL(lib, gdk_window_focus) + && LOAD_SYMBOL(lib, gdk_window_get_display) + && LOAD_SYMBOL(lib, gdk_window_set_modal_hint) + && LOAD_SYMBOL(lib, gdk_x11_display_get_xdisplay) + && LOAD_SYMBOL(lib, gdk_x11_window_get_type) + && LOAD_SYMBOL(lib, gdk_x11_window_get_xid) + && LOAD_SYMBOL(lib, gtk_accel_label_get_type) + && LOAD_SYMBOL(lib, gtk_accel_label_set_accel) + && LOAD_SYMBOL(lib, gtk_bin_get_child) + && LOAD_SYMBOL(lib, gtk_bin_get_type) + && LOAD_SYMBOL(lib, gtk_button_get_type) + && LOAD_SYMBOL(lib, gtk_button_set_label) + && LOAD_SYMBOL(lib, gtk_check_menu_item_get_active) + && LOAD_SYMBOL(lib, gtk_check_menu_item_get_type) + && LOAD_SYMBOL(lib, gtk_check_menu_item_new) + && LOAD_SYMBOL(lib, gtk_check_menu_item_set_active) + && LOAD_SYMBOL(lib, gtk_check_version) + && LOAD_SYMBOL(lib, gtk_clipboard_get) + && LOAD_SYMBOL(lib, gtk_clipboard_store) + && LOAD_SYMBOL(lib, gtk_color_chooser_dialog_new) + && LOAD_SYMBOL(lib, gtk_color_chooser_get_rgba) + && LOAD_SYMBOL(lib, gtk_color_chooser_get_type) + && LOAD_SYMBOL(lib, gtk_color_chooser_set_rgba) + && LOAD_SYMBOL(lib, gtk_color_chooser_set_use_alpha) + && LOAD_SYMBOL(lib, gtk_container_get_type) + && LOAD_SYMBOL(lib, gtk_container_remove) + && LOAD_SYMBOL(lib, gtk_dialog_add_button) + && LOAD_SYMBOL(lib, gtk_dialog_get_type) + && LOAD_SYMBOL(lib, gtk_dialog_get_widget_for_response) + && LOAD_SYMBOL(lib, gtk_dialog_run) + && LOAD_SYMBOL(lib, gtk_file_chooser_add_filter) + && LOAD_SYMBOL(lib, gtk_file_chooser_dialog_get_type) + && LOAD_SYMBOL(lib, gtk_file_chooser_get_current_folder) + && LOAD_SYMBOL(lib, gtk_file_chooser_get_filename) + && LOAD_SYMBOL(lib, gtk_file_chooser_get_filenames) + && LOAD_SYMBOL(lib, gtk_file_chooser_get_filter) + && LOAD_SYMBOL(lib, gtk_file_chooser_get_preview_filename) + && LOAD_SYMBOL(lib, gtk_file_chooser_get_type) + && LOAD_SYMBOL(lib, gtk_file_chooser_remove_filter) + && LOAD_SYMBOL(lib, gtk_file_chooser_select_filename) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_action) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_create_folders) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_current_folder) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_current_name) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_do_overwrite_confirmation) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_filter) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_local_only) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_preview_widget) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_preview_widget_active) + && LOAD_SYMBOL(lib, gtk_file_chooser_set_select_multiple) + && LOAD_SYMBOL(lib, gtk_file_filter_add_pattern) + && LOAD_SYMBOL(lib, gtk_file_filter_new) + && LOAD_SYMBOL(lib, gtk_file_filter_set_name) + && LOAD_SYMBOL(lib, gtk_font_chooser_dialog_new) + && LOAD_SYMBOL(lib, gtk_font_chooser_get_font) + && LOAD_SYMBOL(lib, gtk_font_chooser_get_type) + && LOAD_SYMBOL(lib, gtk_font_chooser_set_font) + && LOAD_SYMBOL(lib, gtk_get_current_event_time) + && LOAD_SYMBOL(lib, gtk_image_get_type) + && LOAD_SYMBOL(lib, gtk_image_new) + && LOAD_SYMBOL(lib, gtk_image_set_from_pixbuf) + && LOAD_SYMBOL(lib, gtk_init) + && LOAD_SYMBOL(lib, gtk_menu_get_type) + && LOAD_SYMBOL(lib, gtk_menu_item_get_type) + && LOAD_SYMBOL(lib, gtk_menu_item_new) + && LOAD_SYMBOL(lib, gtk_menu_item_set_label) + && LOAD_SYMBOL(lib, gtk_menu_item_set_submenu) + && LOAD_SYMBOL(lib, gtk_menu_item_set_use_underline) + && LOAD_SYMBOL(lib, gtk_menu_new) + && LOAD_SYMBOL(lib, gtk_menu_popdown) + && LOAD_SYMBOL(lib, gtk_menu_popup) + && LOAD_SYMBOL(lib, gtk_menu_shell_get_type) + && LOAD_SYMBOL(lib, gtk_menu_shell_insert) + && LOAD_SYMBOL(lib, gtk_menu_shell_select_item) + && LOAD_SYMBOL(lib, gtk_separator_menu_item_new) + && LOAD_SYMBOL(lib, gtk_settings_get_default) + && LOAD_SYMBOL(lib, gtk_widget_destroy) + && LOAD_SYMBOL(lib, gtk_widget_get_scale_factor) + && LOAD_SYMBOL(lib, gtk_widget_get_type) + && LOAD_SYMBOL(lib, gtk_widget_get_window) + && LOAD_SYMBOL(lib, gtk_widget_hide) + && LOAD_SYMBOL(lib, gtk_widget_hide_on_delete) + && LOAD_SYMBOL(lib, gtk_widget_realize) + && LOAD_SYMBOL(lib, gtk_widget_set_sensitive) + && LOAD_SYMBOL(lib, gtk_widget_set_visible) + && LOAD_SYMBOL(lib, gtk_widget_show) + && LOAD_SYMBOL(lib, gtk_window_get_type) + && LOAD_SYMBOL(lib, gtk_window_set_title) + && LOAD_SYMBOL(lib, gtk_window_set_transient_for) + && LOAD_SYMBOL(lib, pango_font_description_free) + && LOAD_SYMBOL(lib, pango_font_description_from_string) + && LOAD_SYMBOL(lib, pango_font_description_get_family) + && LOAD_SYMBOL(lib, pango_font_description_get_size) + && LOAD_SYMBOL(lib, pango_font_description_get_style) + && LOAD_SYMBOL(lib, pango_font_description_get_weight) + && LOAD_SYMBOL(lib, pango_font_description_new) + && LOAD_SYMBOL(lib, pango_font_description_set_family) + && LOAD_SYMBOL(lib, pango_font_description_set_size) + && LOAD_SYMBOL(lib, pango_font_description_set_style) + && LOAD_SYMBOL(lib, pango_font_description_set_weight) + && LOAD_SYMBOL(lib, pango_font_description_to_string) + && LOAD_SYMBOL(lib, pango_font_face_get_type) + && LOAD_SYMBOL(lib, pango_font_family_get_type); + }(); + return loaded; +} + +} // namespace +} // namespace GtkHelper + +GdkPixbuf *gdk_pixbuf_new_from_file_at_size( + const char *filename, + int width, + int height, + GError **error) { + GtkHelper::Resolve(); + return GtkHelper::gdk_pixbuf_new_from_file_at_size( + filename, + width, + height, + error); +} + +void gdk_window_focus(GdkWindow *window, guint32 timestamp) { + GtkHelper::Resolve(); + return GtkHelper::gdk_window_focus(window, timestamp); +} + +GdkDisplay *gdk_window_get_display(GdkWindow *window) { + GtkHelper::Resolve(); + return GtkHelper::gdk_window_get_display(window); +} + +void gdk_window_set_modal_hint(GdkWindow *window, gboolean modal) { + GtkHelper::Resolve(); + GtkHelper::gdk_window_set_modal_hint(window, modal); +} + +Display *gdk_x11_display_get_xdisplay(GdkDisplay *display) { + GtkHelper::Resolve(); + return GtkHelper::gdk_x11_display_get_xdisplay(display); +} + +GType gdk_x11_window_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gdk_x11_window_get_type(); +} + +Window gdk_x11_window_get_xid(GdkWindow *window) { + GtkHelper::Resolve(); + return GtkHelper::gdk_x11_window_get_xid(window); +} + +GType gtk_accel_label_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_accel_label_get_type(); +} + +void gtk_accel_label_set_accel( + GtkAccelLabel *accel_label, + guint accelerator_key, + GdkModifierType accelerator_mods) { + GtkHelper::Resolve(); + GtkHelper::gtk_accel_label_set_accel( + accel_label, + accelerator_key, + accelerator_mods); +} + +GtkWidget *gtk_bin_get_child(GtkBin *bin) { + GtkHelper::Resolve(); + return GtkHelper::gtk_bin_get_child(bin); +} + +GType gtk_bin_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_bin_get_type(); +} + +GType gtk_button_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_button_get_type(); +} + +void gtk_button_set_label(GtkButton *button, const gchar *label) { + GtkHelper::Resolve(); + GtkHelper::gtk_button_set_label(button, label); +} + +gboolean gtk_check_menu_item_get_active(GtkCheckMenuItem *check_menu_item) { + GtkHelper::Resolve(); + return GtkHelper::gtk_check_menu_item_get_active(check_menu_item); +} + +GType gtk_check_menu_item_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_check_menu_item_get_type(); +} + +GtkWidget* gtk_check_menu_item_new(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_check_menu_item_new(); +} + +void gtk_check_menu_item_set_active( + GtkCheckMenuItem *check_menu_item, + gboolean is_active) { + GtkHelper::Resolve(); + return GtkHelper::gtk_check_menu_item_set_active( + check_menu_item, + is_active); +} + +const gchar *gtk_check_version( + guint required_major, + guint required_minor, + guint required_micro) { + GtkHelper::Resolve(); + return GtkHelper::gtk_check_version( + required_major, + required_minor, + required_micro); +} + +GtkClipboard *gtk_clipboard_get(GdkAtom selection) { + GtkHelper::Resolve(); + return GtkHelper::gtk_clipboard_get(selection); +} + +void gtk_clipboard_store(GtkClipboard *clipboard) { + GtkHelper::Resolve(); + GtkHelper::gtk_clipboard_store(clipboard); +} + +GtkWidget *gtk_color_chooser_dialog_new( + const gchar *title, + GtkWindow *parent) { + GtkHelper::Resolve(); + return GtkHelper::gtk_color_chooser_dialog_new(title, parent); +} + +GType gtk_color_chooser_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_color_chooser_get_type(); +} + +void gtk_color_chooser_get_rgba( + GtkColorChooser *chooser, + GdkRGBA *color) { + GtkHelper::Resolve(); + GtkHelper::gtk_color_chooser_get_rgba(chooser, color); +} + +void gtk_color_chooser_set_rgba( + GtkColorChooser *chooser, + const GdkRGBA *color) { + GtkHelper::Resolve(); + GtkHelper::gtk_color_chooser_set_rgba(chooser, color); +} + +void gtk_color_chooser_set_use_alpha( + GtkColorChooser *chooser, + gboolean use_alpha) { + GtkHelper::Resolve(); + GtkHelper::gtk_color_chooser_set_use_alpha(chooser, use_alpha); +} + +GType gtk_container_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_container_get_type(); +} + +void gtk_container_remove(GtkContainer *container, GtkWidget *widget) { + GtkHelper::Resolve(); + GtkHelper::gtk_container_remove(container, widget); +} + +GType gtk_dialog_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_dialog_get_type(); +} + +GtkWidget* gtk_dialog_get_widget_for_response( + GtkDialog *dialog, + gint response_id) { + GtkHelper::Resolve(); + return GtkHelper::gtk_dialog_get_widget_for_response( + dialog, + response_id); +} + +gint gtk_dialog_run(GtkDialog *dialog) { + GtkHelper::Resolve(); + return GtkHelper::gtk_dialog_run(dialog); +} + +void gtk_file_chooser_add_filter( + GtkFileChooser *chooser, + GtkFileFilter *filter) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_add_filter(chooser, filter); +} + +GtkWidget *gtk_file_chooser_dialog_new( + const gchar *title, + GtkWindow *parent, + GtkFileChooserAction action, + const gchar *first_button_text, + ...) { + GtkHelper::Resolve(); + + va_list varargs; + va_start(varargs, first_button_text); + + const auto result = static_cast(g_object_new( + GtkHelper::gtk_file_chooser_dialog_get_type(), + "title", + title, + "action", + action, + nullptr)); + + if (parent) { + GtkHelper::gtk_window_set_transient_for(GTK_WINDOW(result), parent); + } + + auto button_text = first_button_text; + gint response_id; + while (button_text) { + response_id = va_arg(varargs, gint); + GtkHelper::gtk_dialog_add_button( + GTK_DIALOG(result), + button_text, + response_id); + button_text = va_arg(varargs, const gchar *); + } + + va_end(varargs); + return result; +} + +gchar *gtk_file_chooser_get_current_folder(GtkFileChooser *chooser) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_chooser_get_current_folder(chooser); +} + +gchar *gtk_file_chooser_get_filename(GtkFileChooser *chooser) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_chooser_get_filename(chooser); +} + +GSList *gtk_file_chooser_get_filenames(GtkFileChooser *chooser) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_chooser_get_filenames(chooser); +} + +GtkFileFilter *gtk_file_chooser_get_filter(GtkFileChooser *chooser) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_chooser_get_filter(chooser); +} + +char *gtk_file_chooser_get_preview_filename(GtkFileChooser *chooser) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_chooser_get_preview_filename(chooser); +} + +GType gtk_file_chooser_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_chooser_get_type(); +} + +void gtk_file_chooser_remove_filter( + GtkFileChooser *chooser, + GtkFileFilter *filter) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_remove_filter(chooser, filter); +} + +gboolean gtk_file_chooser_select_filename( + GtkFileChooser *chooser, + const char *filename) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_chooser_select_filename(chooser, filename); +} + +void gtk_file_chooser_set_action( + GtkFileChooser *chooser, + GtkFileChooserAction action) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_action(chooser, action); +} + +void gtk_file_chooser_set_create_folders( + GtkFileChooser *chooser, + gboolean create_folders) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_create_folders( + chooser, + create_folders); +} + +gboolean gtk_file_chooser_set_current_folder( + GtkFileChooser *chooser, + const gchar *filename) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_chooser_set_current_folder(chooser, filename); +} + +void gtk_file_chooser_set_current_name( + GtkFileChooser *chooser, + const gchar *name) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_current_name(chooser, name); +} + +void gtk_file_chooser_set_do_overwrite_confirmation( + GtkFileChooser *chooser, + gboolean do_overwrite_confirmation) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_do_overwrite_confirmation( + chooser, + do_overwrite_confirmation); +} + +void gtk_file_chooser_set_filter( + GtkFileChooser *chooser, + GtkFileFilter *filter) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_filter(chooser, filter); +} + +void gtk_file_chooser_set_local_only( + GtkFileChooser *chooser, + gboolean local_only) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_local_only(chooser, local_only); +} + +void gtk_file_chooser_set_preview_widget( + GtkFileChooser *chooser, + GtkWidget *preview_widget) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_preview_widget(chooser, preview_widget); +} + +void gtk_file_chooser_set_preview_widget_active( + GtkFileChooser *chooser, + gboolean active) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_preview_widget_active(chooser, active); +} + +void gtk_file_chooser_set_select_multiple( + GtkFileChooser *chooser, + gboolean select_multiple) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_chooser_set_select_multiple(chooser, select_multiple); +} + +void gtk_file_filter_add_pattern( + GtkFileFilter *filter, + const gchar *pattern) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_filter_add_pattern(filter, pattern); +} + +GtkFileFilter *gtk_file_filter_new(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_file_filter_new(); +} + +void gtk_file_filter_set_name( + GtkFileFilter *filter, + const gchar *name) { + GtkHelper::Resolve(); + GtkHelper::gtk_file_filter_set_name(filter, name); +} + +GtkWidget* gtk_font_chooser_dialog_new( + const gchar *title, + GtkWindow *parent) { + GtkHelper::Resolve(); + return GtkHelper::gtk_font_chooser_dialog_new(title, parent); +} + +gchar* gtk_font_chooser_get_font(GtkFontChooser *fontchooser) { + GtkHelper::Resolve(); + return GtkHelper::gtk_font_chooser_get_font(fontchooser); +} + +GType gtk_font_chooser_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_font_chooser_get_type(); +} + +void gtk_font_chooser_set_font( + GtkFontChooser *fontchooser, + const gchar *fontname) { + GtkHelper::Resolve(); + GtkHelper::gtk_font_chooser_set_font(fontchooser, fontname); +} + +guint32 gtk_get_current_event_time(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_get_current_event_time(); +} + +GType gtk_image_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_image_get_type(); +} + +GtkWidget* gtk_image_new(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_image_new(); +} + +void gtk_image_set_from_pixbuf(GtkImage *image, GdkPixbuf *pixbuf) { + GtkHelper::Resolve(); + GtkHelper::gtk_image_set_from_pixbuf(image, pixbuf); +} + +void gtk_init(int *argc, char ***argv) { + GtkHelper::Resolve(); + GtkHelper::gtk_init(argc, argv); +} + +GType gtk_menu_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_menu_get_type(); +} + +GType gtk_menu_item_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_menu_item_get_type(); +} + +GtkWidget* gtk_menu_item_new(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_menu_item_new(); +} + +void gtk_menu_item_set_label(GtkMenuItem *menu_item, const gchar *label) { + GtkHelper::Resolve(); + GtkHelper::gtk_menu_item_set_label(menu_item, label); +} + +void gtk_menu_item_set_submenu(GtkMenuItem *menu_item, GtkWidget *submenu) { + GtkHelper::Resolve(); + GtkHelper::gtk_menu_item_set_submenu(menu_item, submenu); +} + +void gtk_menu_item_set_use_underline( + GtkMenuItem *menu_item, + gboolean setting) { + GtkHelper::Resolve(); + GtkHelper::gtk_menu_item_set_use_underline(menu_item, setting); +} + +GtkWidget* gtk_menu_new(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_menu_new(); +} + +void gtk_menu_popdown(GtkMenu *menu) { + GtkHelper::Resolve(); + GtkHelper::gtk_menu_popdown(menu); +} + +void gtk_menu_popup( + GtkMenu *menu, + GtkWidget *parent_menu_shell, + GtkWidget *parent_menu_item, + GtkMenuPositionFunc func, + gpointer data, + guint button, + guint32 activate_time) { + GtkHelper::Resolve(); + GtkHelper::gtk_menu_popup( + menu, + parent_menu_shell, + parent_menu_item, + func, + data, + button, + activate_time); +} + +GType gtk_menu_shell_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_menu_shell_get_type(); +} +void gtk_menu_shell_insert( + GtkMenuShell *menu_shell, + GtkWidget *child, + gint position) { + GtkHelper::Resolve(); + GtkHelper::gtk_menu_shell_insert(menu_shell, child, position); +} + +void gtk_menu_shell_select_item( + GtkMenuShell *menu_shell, + GtkWidget *menu_item) { + GtkHelper::Resolve(); + GtkHelper::gtk_menu_shell_select_item(menu_shell, menu_item); +} + +GtkWidget* gtk_separator_menu_item_new(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_separator_menu_item_new(); +} + +GtkSettings* gtk_settings_get_default(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_settings_get_default(); +} + +void gtk_widget_destroy(GtkWidget *widget) { + GtkHelper::Resolve(); + GtkHelper::gtk_widget_destroy(widget); +} + +gint gtk_widget_get_scale_factor(GtkWidget *widget) { + GtkHelper::Resolve(); + return GtkHelper::gtk_widget_get_scale_factor(widget); +} + +GType gtk_widget_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_widget_get_type(); +} + +GdkWindow *gtk_widget_get_window(GtkWidget *widget) { + GtkHelper::Resolve(); + return GtkHelper::gtk_widget_get_window(widget); +} + +void gtk_widget_hide(GtkWidget *widget) { + GtkHelper::Resolve(); + GtkHelper::gtk_widget_hide(widget); +} + +gboolean gtk_widget_hide_on_delete(GtkWidget *widget) { + GtkHelper::Resolve(); + return GtkHelper::gtk_widget_hide_on_delete(widget); +} + +void gtk_widget_realize(GtkWidget *widget) { + GtkHelper::Resolve(); + GtkHelper::gtk_widget_realize(widget); +} + +void gtk_widget_set_sensitive(GtkWidget *widget, gboolean sensitive) { + GtkHelper::Resolve(); + GtkHelper::gtk_widget_set_sensitive(widget, sensitive); +} + +void gtk_widget_set_visible(GtkWidget *widget, gboolean visible) { + GtkHelper::Resolve(); + GtkHelper::gtk_widget_set_visible(widget, visible); +} + +void gtk_widget_show(GtkWidget *widget) { + GtkHelper::Resolve(); + GtkHelper::gtk_widget_show(widget); +} + +GType gtk_window_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::gtk_window_get_type(); +} + +void gtk_window_set_title(GtkWindow *window, const gchar *title) { + GtkHelper::Resolve(); + GtkHelper::gtk_window_set_title(window, title); +} + +void pango_font_description_free(PangoFontDescription *desc) { + GtkHelper::Resolve(); + GtkHelper::pango_font_description_free(desc); +} + +PangoFontDescription *pango_font_description_from_string(const char *str) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_description_from_string(str); +} + +const char *pango_font_description_get_family( + const PangoFontDescription *desc) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_description_get_family(desc); +} + +gint pango_font_description_get_size(const PangoFontDescription *desc) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_description_get_size(desc); +} + +PangoStyle pango_font_description_get_style( + const PangoFontDescription *desc) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_description_get_style(desc); +} + +PangoWeight pango_font_description_get_weight( + const PangoFontDescription *desc) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_description_get_weight(desc); +} + +PangoFontDescription *pango_font_description_new(void) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_description_new(); +} + +void pango_font_description_set_family( + PangoFontDescription *desc, + const char *family) { + GtkHelper::Resolve(); + GtkHelper::pango_font_description_set_family(desc, family); +} + +void pango_font_description_set_size( + PangoFontDescription *desc, + gint size) { + GtkHelper::Resolve(); + GtkHelper::pango_font_description_set_size(desc, size); +} + +void pango_font_description_set_style( + PangoFontDescription *desc, + PangoStyle style) { + GtkHelper::Resolve(); + GtkHelper::pango_font_description_set_style(desc, style); +} + +void pango_font_description_set_weight( + PangoFontDescription *desc, + PangoWeight weight) { + GtkHelper::Resolve(); + GtkHelper::pango_font_description_set_weight(desc, weight); +} + +char *pango_font_description_to_string(const PangoFontDescription *desc) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_description_to_string(desc); +} + +GType pango_font_face_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_face_get_type(); +} + +GType pango_font_family_get_type(void) { + GtkHelper::Resolve(); + return GtkHelper::pango_font_family_get_type(); +} diff --git a/linux_wayland_helper/linux_wayland_helper.cpp b/linux_wayland_helper/linux_wayland_helper.cpp index cbcbeaf..5d75469 100644 --- a/linux_wayland_helper/linux_wayland_helper.cpp +++ b/linux_wayland_helper/linux_wayland_helper.cpp @@ -200,7 +200,7 @@ inline bool LoadSymbol(const Handle &handle, const char *name, Function &func) { } bool Resolve() { - static const auto loaded = [&] { + static const auto loaded = [] { auto egl = Handle(); auto cursor = Handle(); auto client = Handle(); @@ -618,4 +618,5 @@ struct wl_proxy *wl_proxy_marshal_constructor_versioned( args, interface, version); } + } // extern "C" diff --git a/options_linux.cmake b/options_linux.cmake index d586e79..e7b164f 100644 --- a/options_linux.cmake +++ b/options_linux.cmake @@ -16,17 +16,23 @@ INTERFACE -Wno-unused-function -Wno-switch -Wno-comment - -Wno-unused-but-set-variable -Wno-missing-field-initializers -Wno-sign-compare -Wno-attributes -Wno-parentheses - -Wno-stringop-overflow - -Wno-maybe-uninitialized - -Wno-error=class-memaccess $<$>:-Wno-register> ) +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(common_options + INTERFACE + -Wno-unused-but-set-variable + -Wno-stringop-overflow + -Wno-maybe-uninitialized + -Wno-error=class-memaccess + ) +endif() + if (DESKTOP_APP_SPECIAL_TARGET) target_compile_options(common_options INTERFACE @@ -43,11 +49,20 @@ if (DESKTOP_APP_SPECIAL_TARGET) target_compile_options(common_options INTERFACE -g0) target_link_options(common_options INTERFACE -g0) else() - target_compile_options(common_options INTERFACE $,,-g -flto>) - target_link_options(common_options INTERFACE $,,-g -flto -fuse-linker-plugin>) + target_compile_options(common_options INTERFACE $,,-g>) + target_link_options(common_options INTERFACE $,,-g>) + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(common_options INTERFACE $,,-flto>) + target_link_options(common_options INTERFACE $,,-flto -fuse-linker-plugin>) + endif() endif() endif() +target_link_libraries(common_options +INTERFACE + desktop-app::external_jemalloc +) + if (DESKTOP_APP_USE_PACKAGED) find_library(ATOMIC_LIBRARY atomic) else() diff --git a/options_win.cmake b/options_win.cmake index 98b8a9e..c56b9b0 100644 --- a/options_win.cmake +++ b/options_win.cmake @@ -26,6 +26,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") /w14834 # [[nodiscard]] /w15038 # wrong initialization order /w14265 # class has virtual functions, but destructor is not virtual + /w14101 # 'identifier' : unreferenced local variable /wd4068 # Disable "warning C4068: unknown pragma" /wd4267 # 'initializing': conversion from 'size_t' to 'int', possible loss of data. /wd4244 # '=': conversion from 'size_t' to 'int', possible loss of data. diff --git a/variables.cmake b/variables.cmake index c9b48b2..97b81b1 100644 --- a/variables.cmake +++ b/variables.cmake @@ -32,7 +32,6 @@ option(DESKTOP_APP_DISABLE_DBUS_INTEGRATION "Disable all code for D-Bus integrat option(DESKTOP_APP_DISABLE_X11_INTEGRATION "Disable all code for X11 integration (Linux only)." OFF) option(DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION "Disable all code for Wayland integration (Linux only)." OFF) option(DESKTOP_APP_DISABLE_GTK_INTEGRATION "Disable all code for GTK integration (Linux only)." OFF) -option(DESKTOP_APP_USE_GLIBC_WRAPS "Use wraps for new GLIBC features." OFF) option(DESKTOP_APP_USE_ALLOCATION_TRACER "Use simple allocation tracer (Linux only)." OFF) option(DESKTOP_APP_USE_PACKAGED "Find libraries using CMake instead of exact paths." ${no_special_target}) option(DESKTOP_APP_USE_PACKAGED_LAZY "Bundle recommended Qt plugins for self-contained packages. (Linux only)" OFF) @@ -96,7 +95,7 @@ else() report_bad_special_target() endif() endif() - if (DESKTOP_APP_SPECIAL_TARGET) + if (DESKTOP_APP_SPECIAL_TARGET AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_AR "gcc-ar") set(CMAKE_RANLIB "gcc-ranlib") set(CMAKE_NM "gcc-nm") diff --git a/win_directx_helper/CMakeLists.txt b/win_directx_helper/CMakeLists.txt new file mode 100644 index 0000000..c98935c --- /dev/null +++ b/win_directx_helper/CMakeLists.txt @@ -0,0 +1,14 @@ +# This file is part of Desktop App Toolkit, +# a set of libraries for developing nice desktop applications. +# +# For license and copyright information please follow this link: +# https://github.com/desktop-app/legal/blob/master/LEGAL + +add_library(win_directx_helper STATIC) +init_target(win_directx_helper "(external)") +add_library(desktop-app::win_directx_helper ALIAS win_directx_helper) + +nice_target_sources(win_directx_helper ${CMAKE_CURRENT_SOURCE_DIR} +PRIVATE + win_directx_helper.cpp +) diff --git a/win_directx_helper/win_directx_helper.cpp b/win_directx_helper/win_directx_helper.cpp new file mode 100644 index 0000000..d987a32 --- /dev/null +++ b/win_directx_helper/win_directx_helper.cpp @@ -0,0 +1,170 @@ +// This file is part of Desktop App Toolkit, +// a set of libraries for developing nice desktop applications. +// +// For license and copyright information please follow this link: +// https://github.com/desktop-app/legal/blob/master/LEGAL +// + +#include +#include +#include + +#define LOAD_SYMBOL(handle, func) LoadSymbol(handle, #func, func) + +namespace DirectX { +namespace { + +using Handle = HINSTANCE; + +// d3d9.dll + +IDirect3D9 * (__stdcall *Direct3DCreate9)(UINT SDKVersion); +int (__stdcall *D3DPERF_BeginEvent)(D3DCOLOR col, LPCWSTR wszName); +int (__stdcall *D3DPERF_EndEvent)(void); +void (__stdcall *D3DPERF_SetMarker)(D3DCOLOR col, LPCWSTR wszName); +DWORD (__stdcall *D3DPERF_GetStatus)(void); + +// d3d11.dll + +HRESULT (__stdcall *D3D11CreateDevice)( + _In_opt_ IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + _In_reads_opt_(FeatureLevels) CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + _COM_Outptr_opt_ ID3D11Device** ppDevice, + _Out_opt_ D3D_FEATURE_LEVEL* pFeatureLevel, + _COM_Outptr_opt_ ID3D11DeviceContext** ppImmediateContext); + +// dxgi.dll + +HRESULT (__stdcall *CreateDXGIFactory)( + REFIID riid, + _COM_Outptr_ void **ppFactory); + +HRESULT (__stdcall *CreateDXGIFactory1)( + REFIID riid, + _COM_Outptr_ void **ppFactory); + +template +inline bool LoadSymbol(Handle handle, const char *name, Function &func) { + func = handle + ? reinterpret_cast(GetProcAddress(handle, name)) + : nullptr; + return (func != nullptr); +} + +bool ResolveD3D9() { + static const auto loaded = [] { + const auto d3d9 = LoadLibrary(L"d3d9.dll"); + LOAD_SYMBOL(d3d9, D3DPERF_BeginEvent); + LOAD_SYMBOL(d3d9, D3DPERF_EndEvent); + LOAD_SYMBOL(d3d9, D3DPERF_SetMarker); + LOAD_SYMBOL(d3d9, D3DPERF_GetStatus); + return true + && LOAD_SYMBOL(d3d9, Direct3DCreate9); + }(); + return loaded; +} + +bool ResolveD3D11() { + static const auto loaded = [] { + const auto d3d11 = LoadLibrary(L"d3d11.dll"); + return true + && LOAD_SYMBOL(d3d11, D3D11CreateDevice); + }(); + return loaded; +} + +bool ResolveDXGI() { + static const auto loaded = [&] { + const auto dxgi = LoadLibrary(L"dxgi.dll"); + LOAD_SYMBOL(dxgi, CreateDXGIFactory1); + return true + && LOAD_SYMBOL(dxgi, CreateDXGIFactory); + }(); + return loaded; +} + +} // namespace +} // namespace DirectX + +namespace D = DirectX; + +extern "C" { + +IDirect3D9 * WINAPI Direct3DCreate9(UINT SDKVersion) { + return D::ResolveD3D9() + ? D::Direct3DCreate9(SDKVersion) + : nullptr; +} + +int WINAPI D3DPERF_BeginEvent(D3DCOLOR col, LPCWSTR wszName) { + return (D::ResolveD3D9() && D::D3DPERF_BeginEvent) + ? D::D3DPERF_BeginEvent(col, wszName) + : -1; +} + +int WINAPI D3DPERF_EndEvent(void) { + return (D::ResolveD3D9() && D::D3DPERF_EndEvent) + ? D::D3DPERF_EndEvent() + : -1; +} + +void WINAPI D3DPERF_SetMarker(D3DCOLOR col, LPCWSTR wszName) { + if (D::ResolveD3D9() && D::D3DPERF_SetMarker) { + D::D3DPERF_SetMarker(col, wszName); + } +} + +DWORD WINAPI D3DPERF_GetStatus(void) { + return (D::ResolveD3D9() && D::D3DPERF_GetStatus) + ? D::D3DPERF_GetStatus() + : 0; +} + +HRESULT WINAPI D3D11CreateDevice( + _In_opt_ IDXGIAdapter* pAdapter, + D3D_DRIVER_TYPE DriverType, + HMODULE Software, + UINT Flags, + _In_reads_opt_(FeatureLevels) CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, + UINT SDKVersion, + _COM_Outptr_opt_ ID3D11Device** ppDevice, + _Out_opt_ D3D_FEATURE_LEVEL* pFeatureLevel, + _COM_Outptr_opt_ ID3D11DeviceContext** ppImmediateContext) { + return D::ResolveD3D11() + ? D::D3D11CreateDevice( + pAdapter, + DriverType, + Software, + Flags, + pFeatureLevels, + FeatureLevels, + SDKVersion, + ppDevice, + pFeatureLevel, + ppImmediateContext) + : CO_E_DLLNOTFOUND; +} + +HRESULT WINAPI CreateDXGIFactory( + REFIID riid, + _COM_Outptr_ void **ppFactory) { + return D::ResolveDXGI() + ? D::CreateDXGIFactory(riid, ppFactory) + : CO_E_DLLNOTFOUND; +} + +HRESULT WINAPI CreateDXGIFactory1( + REFIID riid, + _COM_Outptr_ void **ppFactory) { + return (D::ResolveDXGI() && D::CreateDXGIFactory1) + ? D::CreateDXGIFactory1(riid, ppFactory) + : CO_E_DLLNOTFOUND; +} + +} // extern "C"