From 68c2082cf2fd17077cdbc6c2080e37906faa1e0c Mon Sep 17 00:00:00 2001 From: David Korth Date: Thu, 2 Jan 2025 17:17:39 -0500 Subject: [PATCH] [gtk] Split the libadwaita/libhandy code into a separate file. pfn_adwaita.c handles all of the dlopen() functionality and uses either adw_* or hdy_* depending on the GTK version in use. It's built for GTK3 and GTK4, but not for GTK2. Effectively no user-visible changes. --- src/gtk/CMakeLists.txt | 10 ++++- src/gtk/RomDataView.cpp | 81 +++++++++---------------------------- src/gtk/RomDataView_p.hpp | 3 +- src/gtk/gtk3/CMakeLists.txt | 6 +++ src/gtk/gtk4/CMakeLists.txt | 6 +++ src/gtk/pfn_adwaita.c | 66 ++++++++++++++++++++++++++++++ src/gtk/pfn_adwaita.h | 65 +++++++++++++++++++++++++++++ 7 files changed, 173 insertions(+), 64 deletions(-) create mode 100644 src/gtk/pfn_adwaita.c create mode 100644 src/gtk/pfn_adwaita.h diff --git a/src/gtk/CMakeLists.txt b/src/gtk/CMakeLists.txt index 3fec59b78c..734d7141e3 100644 --- a/src/gtk/CMakeLists.txt +++ b/src/gtk/CMakeLists.txt @@ -161,7 +161,15 @@ SET(${PROJECT_NAME}_GTK3MAX_H gtk3/sort_funcs.h ) -# Sources and headers (GTK4+ only) +# Sources and headers (GTK3+) +SET(${PROJECT_NAME}_GTK3MIN_SRCS + pfn_adwaita.c + ) +SET(${PROJECT_NAME}_GTK3MIN_H + pfn_adwaita.h + ) + +# Sources and headers (GTK4+) SET(${PROJECT_NAME}_GTK4MIN_SRCS LanguageComboBox_gtk4.cpp LanguageComboBoxItem.c diff --git a/src/gtk/RomDataView.cpp b/src/gtk/RomDataView.cpp index 9047df1f60..0c00a06812 100644 --- a/src/gtk/RomDataView.cpp +++ b/src/gtk/RomDataView.cpp @@ -2,7 +2,7 @@ * ROM Properties Page shell extension. (GTK+ common) * * RomDataView.cpp: RomData viewer widget. * * * - * Copyright (c) 2017-2024 by David Korth. * + * Copyright (c) 2017-2025 by David Korth. * * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ @@ -15,6 +15,9 @@ #include "is-supported.hpp" #include "rp-gtk-enums.h" +// libadwaita/libhandy function pointers +#include "pfn_adwaita.h" + // Custom widgets #include "DragImage.hpp" #include "LanguageComboBox.hpp" @@ -25,16 +28,6 @@ using namespace LibRpBase; using namespace LibRpText; using namespace LibRpTexture; -// libdl -#ifdef HAVE_DLVSYM -# ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -# endif /* _GNU_SOURCE */ -#else /* !HAVE_DLVSYM */ -# define dlvsym(handle, symbol, version) dlsym((handle), (symbol)) -#endif /* HAVE_DLVSYM */ -#include - // C++ STL classes using std::set; using std::string; @@ -92,21 +85,6 @@ static void cboLanguage_notify_selected_lc_handler(RpLanguageComboBox *widget, GParamSpec *pspec, RpRomDataView *page); -#if GTK_CHECK_VERSION(3,0,0) -// libadwaita/libhandy function pointers. -// Only initialized if libadwaita/libhandy is linked into the process. -// NOTE: The function pointers are essentially the same, but -// libhandy was renamed to libadwaita for the GTK4 conversion. -// We'll use libadwaita terminology everywhere. -struct AdwHeaderBar; -typedef GType (*pfnGlibGetType_t)(void); -typedef GType (*pfnAdwHeaderBarPackEnd_t)(AdwHeaderBar *self, GtkWidget *child); -static bool has_checked_adw = false; -static pfnGlibGetType_t pfn_adw_deck_get_type = nullptr; -static pfnGlibGetType_t pfn_adw_header_bar_get_type = nullptr; -static pfnAdwHeaderBarPackEnd_t pfn_adw_header_bar_pack_end = nullptr; -#endif /* GTK_CHECK_VERSION(3,0,0) */ - // NOTE: G_DEFINE_TYPE() doesn't work in C++ mode with gcc-6.2 // due to an implicit int to GTypeFlags conversion. G_DEFINE_TYPE_EXTENDED(RpRomDataView, rp_rom_data_view, @@ -150,32 +128,8 @@ rp_rom_data_view_class_init(RpRomDataViewClass *klass) // Install the properties. g_object_class_install_properties(gobject_class, PROP_LAST, props); -#if GTK_CHECK_VERSION(3,0,0) - /** libadwaita/libhandy **/ - - // Check if libadwaita-1 is loaded in the process. - // TODO: Verify that it is in fact 1.x if symbol versioning isn't available. - if (!has_checked_adw) { - has_checked_adw = true; -# if GTK_CHECK_VERSION(4,0,0) - // GTK4: libadwaita -# define ADW_SYM_PREFIX "adw_" -# define ADW_SYM_VERSION "LIBADWAITA_1_0" -# else /* !GTK_CHECK_VERSION(4,0,0) */ - // GTK3: libhandy -# define ADW_SYM_PREFIX "hdy_" -# define ADW_SYM_VERSION "LIBHANDY_1_0" -# endif - pfn_adw_deck_get_type = (pfnGlibGetType_t)dlvsym( - RTLD_DEFAULT, ADW_SYM_PREFIX "deck_get_type", ADW_SYM_VERSION); - if (pfn_adw_deck_get_type) { - pfn_adw_header_bar_get_type = (pfnGlibGetType_t)dlvsym( - RTLD_DEFAULT, ADW_SYM_PREFIX "header_bar_get_type", ADW_SYM_VERSION); - pfn_adw_header_bar_pack_end = (pfnAdwHeaderBarPackEnd_t)dlvsym( - RTLD_DEFAULT, ADW_SYM_PREFIX "header_bar_pack_end", ADW_SYM_VERSION); - } - } -#endif /* GTK_CHECK_VERSION(3,0,0) */ + // Initialize libadwaita/libhandy function pointers. + rp_init_pfn_adwaita(); } /** @@ -1127,8 +1081,9 @@ static void rp_rom_data_view_create_options_button(RpRomDataView *page) { assert(!page->btnOptions); - if (page->btnOptions != nullptr) + if (page->btnOptions != nullptr) { return; + } GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET(page)); if (page->desc_format_type == RP_DFT_XFCE) { @@ -1169,12 +1124,14 @@ rp_rom_data_view_create_options_button(RpRomDataView *page) parent = gtk_widget_get_parent(parent); #if GTK_CHECK_VERSION(3,0,0) assert(GTK_IS_BOX(parent)); - if (!GTK_IS_BOX(parent)) + if (!GTK_IS_BOX(parent)) { return; + } #else /* !GTK_CHECK_VERSION(3,0,0) */ assert(GTK_IS_VBOX(parent)); - if (!GTK_IS_VBOX(parent)) + if (!GTK_IS_VBOX(parent)) { return; + } #endif /* GTK_CHECK_VERSION(3,0,0) */ // Next: GtkDialog subclass. @@ -1191,7 +1148,7 @@ rp_rom_data_view_create_options_button(RpRomDataView *page) } #endif /* GTK_CHECK_VERSION(4,0,0) */ -#if GTK_CHECK_VERSION(3,0,0) +#ifdef RP_MAY_HAVE_ADWAITA bool isLibAdwaita = false; if (!GTK_IS_DIALOG(parent)) { // NOTE: As of Nautilus 40, there may be an AdwDeck/HdyDeck here. @@ -1206,15 +1163,17 @@ rp_rom_data_view_create_options_button(RpRomDataView *page) // Main window is based on AdwWindow/HdyWindow, which is derived from // GtkWindow, not GtkDialog. assert(GTK_IS_WINDOW(parent)); - if (!GTK_IS_WINDOW(parent)) + if (!GTK_IS_WINDOW(parent)) { return; + } } else -#endif /* GTK_CHECK_VERSION(3,0,0) */ +#endif /* RP_MAY_HAVE_ADWAITA */ { // Main window is derived from GtkDialog. assert(GTK_IS_DIALOG(parent)); - if (!GTK_IS_DIALOG(parent)) + if (!GTK_IS_DIALOG(parent)) { return; + } } // Create the RpOptionsMenuButton. @@ -1225,11 +1184,11 @@ rp_rom_data_view_create_options_button(RpRomDataView *page) // (Normally not mapped in a properties dialog; but it *is* mapped in the test program.) gtk_widget_set_visible(page->btnOptions, gtk_widget_get_mapped(GTK_WIDGET(page))); -#if GTK_CHECK_VERSION(3,0,0) +#ifdef RP_MAY_HAVE_ADWAITA if (isLibAdwaita) { // LibAdwaita/LibHandy version doesn't use GtkDialog. } else -#endif /* GTK_CHECK_VERSION(3,0,0) */ +#endif /* RP_MAY_HAVE_ADWAITA */ { // Not using LibAdwaita/LibHandy, so add the widget to the GtkDialog. gtk_dialog_add_action_widget(GTK_DIALOG(parent), page->btnOptions, GTK_RESPONSE_NONE); diff --git a/src/gtk/RomDataView_p.hpp b/src/gtk/RomDataView_p.hpp index ac0434d42c..9feb53071e 100644 --- a/src/gtk/RomDataView_p.hpp +++ b/src/gtk/RomDataView_p.hpp @@ -2,13 +2,12 @@ * ROM Properties Page shell extension. (GTK+ common) * * RomDataView.cpp: RomData viewer widget. (Private functions) * * * - * Copyright (c) 2017-2024 by David Korth. * + * Copyright (c) 2017-2025 by David Korth. * * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #pragma once -#include "config.gtk.h" #include #include "OptionsMenuButton.hpp" diff --git a/src/gtk/gtk3/CMakeLists.txt b/src/gtk/gtk3/CMakeLists.txt index 8a3dc605af..79c79ef9e9 100644 --- a/src/gtk/gtk3/CMakeLists.txt +++ b/src/gtk/gtk3/CMakeLists.txt @@ -76,6 +76,10 @@ STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_H "${rom-properties-g STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_GTK3MAX_SRCS "${rom-properties-gtk_GTK3MAX_SRCS}") STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_GTK3MAX_H "${rom-properties-gtk_GTK3MAX_H}") +# Sources and headers (GTK3 minimum) +STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_GTK3MIN_SRCS "${rom-properties-gtk_GTK3MIN_SRCS}") +STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_GTK3MIN_H "${rom-properties-gtk_GTK3MIN_H}") + # CairoImageConv (GTK+ 3.x) SET(${PROJECT_NAME}_SRCS ${${PROJECT_NAME}_SRCS} CairoImageConv.cpp) SET(${PROJECT_NAME}_H ${${PROJECT_NAME}_H} CairoImageConv.hpp) @@ -93,6 +97,7 @@ CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.caja-extension.in" " SET(${PROJECT_NAME}_SRCS ${${PROJECT_NAME}_SRCS} ${${PROJECT_NAME}_GTK3MAX_SRCS} + ${${PROJECT_NAME}_GTK3MIN_SRCS} ${${PROJECT_NAME}-notify_SRCS} ${${PROJECT_NAME}_IFUNC_SRCS} NautilusPlugin.cpp @@ -108,6 +113,7 @@ SET(${PROJECT_NAME}_SRCS SET(${PROJECT_NAME}_H ${${PROJECT_NAME}_H} ${${PROJECT_NAME}_GTK3MAX_H} + ${${PROJECT_NAME}_GTK3MIN_H} ${${PROJECT_NAME}-notify_H} ../plugin-helper.h NautilusPlugin.hpp diff --git a/src/gtk/gtk4/CMakeLists.txt b/src/gtk/gtk4/CMakeLists.txt index 3888e107eb..5035b24ee9 100644 --- a/src/gtk/gtk4/CMakeLists.txt +++ b/src/gtk/gtk4/CMakeLists.txt @@ -53,6 +53,10 @@ ADD_DEFINITIONS(-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_66 -DGLIB_VERSION_MAX STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_SRCS "${rom-properties-gtk_SRCS}") STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_H "${rom-properties-gtk_H}") +# Sources and headers (GTK3 minimum) +STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_GTK3MIN_SRCS "${rom-properties-gtk_GTK3MIN_SRCS}") +STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_GTK3MIN_H "${rom-properties-gtk_GTK3MIN_H}") + # Sources and headers (GTK4 minimum) STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_GTK4MIN_SRCS "${rom-properties-gtk_GTK4MIN_SRCS}") STRING(REGEX REPLACE "([^;]+)" "../\\1" ${PROJECT_NAME}_GTK4MIN_H "${rom-properties-gtk_GTK4MIN_H}") @@ -70,6 +74,7 @@ ENDIF(ENABLE_ACHIEVEMENTS) # Sources and headers (GTK4-specific) SET(${PROJECT_NAME}_SRCS ${${PROJECT_NAME}_SRCS} + ${${PROJECT_NAME}_GTK3MIN_SRCS} ${${PROJECT_NAME}_GTK4MIN_SRCS} ${${PROJECT_NAME}-notify_SRCS} ${${PROJECT_NAME}_IFUNC_SRCS} @@ -87,6 +92,7 @@ SET(${PROJECT_NAME}_SRCS ) SET(${PROJECT_NAME}_H ${${PROJECT_NAME}_H} + ${${PROJECT_NAME}_GTK3MIN_H} ${${PROJECT_NAME}_GTK4MIN_H} ${${PROJECT_NAME}-notify_H} ../plugin-helper.h diff --git a/src/gtk/pfn_adwaita.c b/src/gtk/pfn_adwaita.c new file mode 100644 index 0000000000..2cdc1d0a37 --- /dev/null +++ b/src/gtk/pfn_adwaita.c @@ -0,0 +1,66 @@ +/*************************************************************************** + * ROM Properties Page shell extension. (GTK+ common) * + * pfn_adwaita.c: libadwaita/libhandy function pointer handling. * + * * + * Copyright (c) 2017-2025 by David Korth. * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#include "stdafx.h" +#include "config.gtk.h" +#include "pfn_adwaita.h" + +// libdl +#ifdef HAVE_DLVSYM +# ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +# endif /* _GNU_SOURCE */ +#else /* !HAVE_DLVSYM */ +# define dlvsym(handle, symbol, version) dlsym((handle), (symbol)) +#endif /* HAVE_DLVSYM */ +#include + +// libadwaita/libhandy function pointers. +// Only initialized if libadwaita/libhandy is linked into the process. +// NOTE: The function pointers are essentially the same, but +// libhandy was renamed to libadwaita for the GTK4 conversion. +// We'll use libadwaita terminology everywhere. + +static gsize has_checked_adw = 0; +pfnGlibGetType_t pfn_adw_deck_get_type = NULL; +pfnGlibGetType_t pfn_adw_header_bar_get_type = NULL; +pfnAdwHeaderBarPackEnd_t pfn_adw_header_bar_pack_end = NULL; + +#if GTK_CHECK_VERSION(4,0,0) + // GTK4: libadwaita +# define ADW_SYM_PREFIX "adw_" +# define ADW_SYM_VERSION "LIBADWAITA_1_0" +#else /* !GTK_CHECK_VERSION(4,0,0) */ + // GTK3: libhandy +# define ADW_SYM_PREFIX "hdy_" +# define ADW_SYM_VERSION "LIBHANDY_1_0" +#endif + +/** + * Initialize libadwaita/libhandy function pointers. + * @return TRUE on success; FALSE on failure. + */ +gboolean rp_init_pfn_adwaita(void) +{ + if (g_once_init_enter(&has_checked_adw)) { + // Check if libadwaita-1 is loaded in the process. + // TODO: Verify that it is in fact 1.x if symbol versioning isn't available. + pfn_adw_deck_get_type = (pfnGlibGetType_t)dlvsym( + RTLD_DEFAULT, ADW_SYM_PREFIX "deck_get_type", ADW_SYM_VERSION); + if (pfn_adw_deck_get_type) { + pfn_adw_header_bar_get_type = (pfnGlibGetType_t)dlvsym( + RTLD_DEFAULT, ADW_SYM_PREFIX "header_bar_get_type", ADW_SYM_VERSION); + pfn_adw_header_bar_pack_end = (pfnAdwHeaderBarPackEnd_t)dlvsym( + RTLD_DEFAULT, ADW_SYM_PREFIX "header_bar_pack_end", ADW_SYM_VERSION); + } + + g_once_init_leave(&has_checked_adw, 1); + } + + return (pfn_adw_deck_get_type != NULL); +} diff --git a/src/gtk/pfn_adwaita.h b/src/gtk/pfn_adwaita.h new file mode 100644 index 0000000000..e431e2bcc3 --- /dev/null +++ b/src/gtk/pfn_adwaita.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * ROM Properties Page shell extension. (GTK+ common) * + * pfn_adwaita.h: libadwaita/libhandy function pointer handling. * + * * + * Copyright (c) 2017-2025 by David Korth. * + * SPDX-License-Identifier: GPL-2.0-or-later * + ***************************************************************************/ + +#pragma once + +#include "gtk-compat.h" + +G_BEGIN_DECLS + +// libadwaita/libhandy function pointers. +// Only initialized if libadwaita/libhandy is linked into the process. +// NOTE: The function pointers are essentially the same, but +// libhandy was renamed to libadwaita for the GTK4 conversion. +// We'll use libadwaita terminology everywhere. +typedef struct _AdwHeaderBar AdwHeaderBar; +typedef GType (*pfnGlibGetType_t)(void); +typedef void (*pfnAdwHeaderBarPackEnd_t)(AdwHeaderBar *self, GtkWidget *child); + +#if GTK_CHECK_VERSION(3,0,0) +# define RP_MAY_HAVE_ADWAITA 1 + +extern pfnGlibGetType_t pfn_adw_deck_get_type; +extern pfnGlibGetType_t pfn_adw_header_bar_get_type; +extern pfnAdwHeaderBarPackEnd_t pfn_adw_header_bar_pack_end; + +/** + * Initialize libadwaita/libhandy function pointers. + * @return TRUE on success; FALSE on failure. + */ +gboolean rp_init_pfn_adwaita(void); + +#else /* !GTK_CHECK_VERSION(3,0,0) */ + +// GTK2: No libadwaita/libhandy. +static inline GType pfn_adw_deck_get_type(void) +{ + return 0; +} +static inline GType pfn_adw_header_bar_get_type(void) +{ + return 0; +} +static inline void pfn_adw_header_bar_pack_end(AdwHeaderBar *self, GtkWidget *child) +{ + ((void)self); + ((void)child); +} + +/** + * Initialize libadwaita/libhandy function pointers. + * @return TRUE on success; FALSE on failure. + */ +static inline gboolean rp_init_pfn_adwaita(void) +{ + return FALSE; +} + +#endif /* GTK_CHECK_VERSION(3,0,0) */ + +G_END_DECLS