linux: fix the regression caused by previous refactoring

Sadly we have to bring back the GTK dependency at compile time.

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-12-20 16:39:20 +08:00
parent ba709ec598
commit ea6a070766
7 changed files with 190 additions and 56 deletions

View File

@ -45,10 +45,6 @@ if(FRAMELESSHELPER_NO_BUNDLE_RESOURCE)
message(WARNING "Nothing will be embeded into FramelessHelper, the chrome buttons will have no icon.")
endif()
if(FRAMELESSHELPER_NO_PRIVATE AND UNIX AND NOT APPLE)
message(SEND_ERROR "Disable private Qt functionalities will completely break FramelessHelper's Linux experience for now.")
endif()
if(FRAMELESSHELPER_ENABLE_VCLTL AND NOT MSVC)
message(WARNING "VC-LTL is only available for the MSVC toolchain.")
endif()

View File

@ -54,8 +54,11 @@
*/
using Display = struct _XDisplay;
using xcb_connection_t = struct xcb_connection_t;
#if __has_include(<xcb/xcb.h>)
# include <xcb/xcb.h>
#else // !__has_include(<xcb/xcb.h>)
using xcb_connection_t = struct xcb_connection_t;
using xcb_button_t = uint8_t;
using xcb_window_t = uint32_t;
using xcb_timestamp_t = uint32_t;
@ -177,6 +180,7 @@ using xcb_list_properties_reply_t = struct xcb_list_properties_reply_t
[[maybe_unused]] inline constexpr const auto XCB_EVENT_MASK_STRUCTURE_NOTIFY = 131072;
[[maybe_unused]] inline constexpr const auto XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT = 1048576;
[[maybe_unused]] inline constexpr const auto XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY = 524288;
#endif // __has_include(<xcb/xcb.h>)
[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0;
[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_TOP = 1;
@ -350,6 +354,9 @@ xcb_get_property_unchecked(
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#if __has_include(<gtk/gtk.h>)
# include <gtk/gtk.h>
#else // !__has_include(<gtk/gtk.h>)
#define G_VALUE_INIT { 0, { { 0 } } }
#define g_signal_connect(instance, detailed_signal, c_handler, data) \
g_signal_connect_data((instance), (detailed_signal), (c_handler), (data), nullptr, G_CONNECT_DEFAULT)
@ -367,8 +374,8 @@ using gchar = char;
using guchar = unsigned char;
using gchararray = char *;
using gpointer = void *;
using gint64 = int64_t;
using guint64 = uint64_t;
using gint64 = signed long;
using guint64 = unsigned long;
using gsize = unsigned int;
using GType = unsigned long;
@ -404,11 +411,13 @@ struct _GValue
gpointer v_pointer;
} data[2];
};
#endif // __has_include(<gtk/gtk.h>)
[[maybe_unused]] inline constexpr const char GTK_THEME_NAME_ENV_VAR[] = "GTK_THEME";
[[maybe_unused]] inline constexpr const char GTK_THEME_NAME_PROP[] = "gtk-theme-name";
[[maybe_unused]] inline constexpr const char GTK_THEME_PREFER_DARK_PROP[] = "gtk-application-prefer-dark-theme";
#if 0
extern "C"
{
@ -482,3 +491,7 @@ g_clear_object(
);
} // extern "C"
#endif
template<typename T>
T gtkSettings(const gchar *property);

View File

@ -160,7 +160,7 @@ FRAMELESSHELPER_CORE_API void bringWindowToFront(const WId windowId);
(const WId windowId, const xcb_atom_t prop, const xcb_atom_t type, const quint32 data_len);
FRAMELESSHELPER_CORE_API void setWindowProperty
(const WId windowId, const xcb_atom_t prop, const xcb_atom_t type,
const void *data, const quint32 data_len = 1, const uint8_t format = 8);
const void *data, const quint32 data_len, const uint8_t format);
FRAMELESSHELPER_CORE_API void clearWindowProperty(const WId windowId, const xcb_atom_t prop);
[[nodiscard]] FRAMELESSHELPER_CORE_API xcb_atom_t internAtom(const char *name);
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getWindowManagerName();
@ -173,6 +173,8 @@ FRAMELESSHELPER_CORE_API void openSystemMenu(const WId windowId, const QPoint &g
FRAMELESSHELPER_CORE_API void sendMoveResizeMessage
(const WId windowId, const uint32_t action, const QPoint &globalPos, const Qt::MouseButton button = Qt::LeftButton);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isCustomDecorationSupported();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool
setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &props);
#endif // Q_OS_LINUX
#ifdef Q_OS_MACOS

View File

@ -22,6 +22,14 @@
SOFTWARE.
]]
if(UNIX AND NOT APPLE)
if(FRAMELESSHELPER_NO_PRIVATE)
find_package(Qt5 QUIET COMPONENTS X11Extras)
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
endif()
set(SUB_MOD_NAME Core)
set(SUB_PROJ_NAME ${PROJECT_NAME}${SUB_MOD_NAME})
set(SUB_PROJ_PATH ${PROJECT_NAME}/${SUB_MOD_NAME})
@ -178,6 +186,13 @@ if(APPLE)
"-framework Cocoa"
"-framework AppKit"
)
elseif(UNIX)
target_include_directories(${SUB_PROJ_NAME} PRIVATE
${GTK3_INCLUDE_DIRS}
)
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
${GTK3_LINK_LIBRARIES}
)
endif()
if(FRAMELESSHELPER_NO_PRIVATE)
@ -185,6 +200,13 @@ if(FRAMELESSHELPER_NO_PRIVATE)
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui
)
# Qt X11Extras was first introduced in 5.1 and got removed in 6.0
# But it was again brought back as a private feature of QtGui in 6.2
if(TARGET Qt5::X11Extras)
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
Qt5::X11Extras
)
endif()
else()
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::CorePrivate

View File

@ -25,27 +25,7 @@
#include "sysapiloader_p.h"
#include "framelesshelper_linux.h"
#define GTK_SETTINGS(Name, Type, ...) \
Type Name(const gchar *property) \
{ \
Q_ASSERT(property); \
if (!property) { \
return {}; \
} \
GtkSettings *settings = gtk_settings_get_default(); \
Q_ASSERT(settings); \
if (!settings) { \
return {}; \
} \
GValue value = G_VALUE_INIT; \
g_object_get_property(reinterpret_cast<GObject *>(settings), property, &value); \
__VA_ARGS__ \
g_value_unset(&value); \
return result; \
}
FRAMELESSHELPER_STRING_CONSTANT(libxcb)
FRAMELESSHELPER_STRING_CONSTANT2(libgtk, "libgtk-3")
FRAMELESSHELPER_STRING_CONSTANT(xcb_send_event)
FRAMELESSHELPER_STRING_CONSTANT(xcb_flush)
@ -64,19 +44,6 @@ FRAMELESSHELPER_STRING_CONSTANT(xcb_list_properties_atoms_length)
FRAMELESSHELPER_STRING_CONSTANT(xcb_list_properties_atoms)
FRAMELESSHELPER_STRING_CONSTANT(xcb_get_property_unchecked)
FRAMELESSHELPER_STRING_CONSTANT(gtk_init)
FRAMELESSHELPER_STRING_CONSTANT(g_value_init)
FRAMELESSHELPER_STRING_CONSTANT(g_value_reset)
FRAMELESSHELPER_STRING_CONSTANT(g_value_unset)
FRAMELESSHELPER_STRING_CONSTANT(g_value_get_boolean)
FRAMELESSHELPER_STRING_CONSTANT(g_value_get_string)
FRAMELESSHELPER_STRING_CONSTANT(gtk_settings_get_default)
FRAMELESSHELPER_STRING_CONSTANT(g_object_get_property)
FRAMELESSHELPER_STRING_CONSTANT(g_signal_connect_data)
FRAMELESSHELPER_STRING_CONSTANT(g_free)
FRAMELESSHELPER_STRING_CONSTANT(g_object_unref)
FRAMELESSHELPER_STRING_CONSTANT(g_clear_object)
//////////////////////////////////////////////
// XCB
@ -298,6 +265,41 @@ xcb_get_property_unchecked(
///////////////////////////////////////////////////
// GTK
#if 0
#define GTK_SETTINGS_IMPL(Name, Type, ...) \
Type Name(const gchar *property) \
{ \
Q_ASSERT(property); \
if (!property) { \
return Type{}; \
} \
static GtkSettings * const settings = gtk_settings_get_default(); \
Q_ASSERT(settings); \
if (!settings) { \
return Type{}; \
} \
GValue value = G_VALUE_INIT; \
g_object_get_property(reinterpret_cast<GObject *>(settings), property, &value); \
__VA_ARGS__ \
g_value_unset(&value); \
return result; \
}
FRAMELESSHELPER_STRING_CONSTANT2(libgtk, "libgtk-3")
FRAMELESSHELPER_STRING_CONSTANT(gtk_init)
FRAMELESSHELPER_STRING_CONSTANT(g_value_init)
FRAMELESSHELPER_STRING_CONSTANT(g_value_reset)
FRAMELESSHELPER_STRING_CONSTANT(g_value_unset)
FRAMELESSHELPER_STRING_CONSTANT(g_value_get_boolean)
FRAMELESSHELPER_STRING_CONSTANT(g_value_get_string)
FRAMELESSHELPER_STRING_CONSTANT(gtk_settings_get_default)
FRAMELESSHELPER_STRING_CONSTANT(g_object_get_property)
FRAMELESSHELPER_STRING_CONSTANT(g_signal_connect_data)
FRAMELESSHELPER_STRING_CONSTANT(g_free)
FRAMELESSHELPER_STRING_CONSTANT(g_object_unref)
FRAMELESSHELPER_STRING_CONSTANT(g_clear_object)
extern "C" void
gtk_init(
int *argc,
@ -439,5 +441,33 @@ g_clear_object(
API_CALL_FUNCTION(g_clear_object, object_ptr);
}
GTK_SETTINGS(GTK_bool, bool, const bool result = g_value_get_boolean(&value);)
GTK_SETTINGS(GTK_str, QString, const QString result = QUtf8String(g_value_get_string(&value));)
GTK_SETTINGS_IMPL(GTK_bool, bool, const bool result = g_value_get_boolean(&value);)
GTK_SETTINGS_IMPL(GTK_str, QString, const QString result = QUtf8String(g_value_get_string(&value));)
#endif
template<typename T>
T gtkSettings(const gchar *property)
{
Q_ASSERT(property);
Q_ASSERT(*property != '\0');
if (!property || (*property == '\0')) {
return T{};
}
static GtkSettings * const settings = gtk_settings_get_default();
if (!settings) {
return T{};
}
T result = {};
g_object_get(settings, property, &result, nullptr);
return result;
}
template bool gtkSettings<bool>(const gchar *);
QString gtkSettings(const gchar *property)
{
const auto raw = gtkSettings<gchar *>(property);
const QString result = QUtf8String(raw);
g_free(raw);
return result;
}

View File

@ -23,7 +23,6 @@
*/
#include "utils.h"
#include "framelesshelper_linux.h"
#include "framelessconfig_p.h"
#include "framelessmanager.h"
#include "framelessmanager_p.h"
@ -31,7 +30,12 @@
#include <QtGui/qwindow.h>
#include <QtGui/qscreen.h>
#include <QtGui/qguiapplication.h>
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# if __has_include(<QtX11Extras/qx11info_x11.h>)
# include <QtX11Extras/qx11info_x11.h>
# define FRAMELESSHELPER_HAS_X11EXTRAS
# endif // __has_include(<QtX11Extras/qx11info_x11.h>)
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
# include <QtGui/qpa/qplatformnativeinterface.h>
# include <QtGui/qpa/qplatformwindow.h>
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
@ -42,8 +46,8 @@
# endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
extern bool GTK_bool(const gchar *);
extern QString GTK_str(const gchar *);
extern template bool gtkSettings<bool>(const gchar *);
extern QString gtkSettings(const gchar *);
FRAMELESSHELPER_BEGIN_NAMESPACE
@ -146,8 +150,12 @@ quint32 Utils::x11_appRootWindow(const int screen)
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
{
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# ifdef FRAMELESSHELPER_HAS_X11EXTRAS
return QX11Info::appRootWindow(screen);
# else // !FRAMELESSHELPER_HAS_X11EXTRAS
Q_UNUSED(screen);
return 0;
# endif // FRAMELESSHELPER_HAS_X11EXTRAS
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
if (!qApp) {
return 0;
@ -167,7 +175,11 @@ quint32 Utils::x11_appRootWindow(const int screen)
int Utils::x11_appScreen()
{
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# ifdef FRAMELESSHELPER_HAS_X11EXTRAS
return QX11Info::appScreen();
# else // !FRAMELESSHELPER_HAS_X11EXTRAS
return 0;
# endif // FRAMELESSHELPER_HAS_X11EXTRAS
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
if (!qApp) {
return 0;
@ -183,7 +195,11 @@ int Utils::x11_appScreen()
quint32 Utils::x11_appTime()
{
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# ifdef FRAMELESSHELPER_HAS_X11EXTRAS
return QX11Info::appTime();
# else // !FRAMELESSHELPER_HAS_X11EXTRAS
return 0;
# endif // FRAMELESSHELPER_HAS_X11EXTRAS
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
if (!qApp) {
return 0;
@ -203,7 +219,11 @@ quint32 Utils::x11_appTime()
quint32 Utils::x11_appUserTime()
{
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# ifdef FRAMELESSHELPER_HAS_X11EXTRAS
return QX11Info::appUserTime();
# else // !FRAMELESSHELPER_HAS_X11EXTRAS
return 0;
# endif // FRAMELESSHELPER_HAS_X11EXTRAS
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
if (!qApp) {
return 0;
@ -223,7 +243,11 @@ quint32 Utils::x11_appUserTime()
quint32 Utils::x11_getTimestamp()
{
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# ifdef FRAMELESSHELPER_HAS_X11EXTRAS
return QX11Info::getTimestamp();
# else // !FRAMELESSHELPER_HAS_X11EXTRAS
return 0;
# endif // FRAMELESSHELPER_HAS_X11EXTRAS
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
if (!qApp) {
return 0;
@ -243,7 +267,11 @@ quint32 Utils::x11_getTimestamp()
QByteArray Utils::x11_nextStartupId()
{
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# ifdef FRAMELESSHELPER_HAS_X11EXTRAS
return QX11Info::nextStartupId();
# else // !FRAMELESSHELPER_HAS_X11EXTRAS
return {};
# endif // FRAMELESSHELPER_HAS_X11EXTRAS
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
if (!qApp) {
return {};
@ -259,7 +287,11 @@ QByteArray Utils::x11_nextStartupId()
Display *Utils::x11_display()
{
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# ifdef FRAMELESSHELPER_HAS_X11EXTRAS
return QX11Info::display();
# else // !FRAMELESSHELPER_HAS_X11EXTRAS
return nullptr;
# endif // FRAMELESSHELPER_HAS_X11EXTRAS
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
if (!qApp) {
return nullptr;
@ -284,7 +316,11 @@ Display *Utils::x11_display()
xcb_connection_t *Utils::x11_connection()
{
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
# ifdef FRAMELESSHELPER_HAS_X11EXTRAS
return QX11Info::connection();
# else // !FRAMELESSHELPER_HAS_X11EXTRAS
return nullptr;
# endif // FRAMELESSHELPER_HAS_X11EXTRAS
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
if (!qApp) {
return nullptr;
@ -385,7 +421,7 @@ bool Utils::shouldAppsUseDarkMode_linux()
gtk-theme-name provides both light and dark variants. We can save a
regex check by testing this property first.
*/
const bool preferDark = GTK_bool(GTK_THEME_PREFER_DARK_PROP);
const auto preferDark = gtkSettings<bool>(GTK_THEME_PREFER_DARK_PROP);
if (preferDark) {
return true;
}
@ -393,7 +429,7 @@ bool Utils::shouldAppsUseDarkMode_linux()
/*
https://docs.gtk.org/gtk3/property.Settings.gtk-theme-name.html
*/
const QString curThemeName = GTK_str(GTK_THEME_NAME_PROP);
const auto curThemeName = gtkSettings(GTK_THEME_NAME_PROP);
if (!curThemeName.isEmpty()) {
return curThemeName.contains(kdark, Qt::CaseInsensitive);
}
@ -428,7 +464,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
clearWindowProperty(windowId, atom);
} else {
const quint32 value = true;
setWindowProperty(windowId, atom, XCB_ATOM_CARDINAL, &value);
setWindowProperty(windowId, atom, XCB_ATOM_CARDINAL, &value, 1, sizeof(quint32) * 8);
}
return true;
}
@ -779,13 +815,13 @@ bool Utils::tryHideSystemTitleBar(const WId windowId, const bool hide)
return false;
}
const quint32 value = hide;
setWindowProperty(windowId, deepinNoTitleBarAtom, XCB_ATOM_CARDINAL, &value);
setWindowProperty(windowId, deepinNoTitleBarAtom, XCB_ATOM_CARDINAL, &value, 1, sizeof(quint32) * 8);
static const xcb_atom_t deepinForceDecorateAtom = internAtom(ATOM_DEEPIN_FORCE_DECORATE);
if ((deepinForceDecorateAtom == XCB_NONE) || !isSupportedByWindowManager(deepinForceDecorateAtom)) {
return true;
}
if (hide) {
setWindowProperty(windowId, deepinForceDecorateAtom, XCB_ATOM_CARDINAL, &value);
setWindowProperty(windowId, deepinForceDecorateAtom, XCB_ATOM_CARDINAL, &value, 1, sizeof(quint32) * 8);
} else {
clearWindowProperty(windowId, deepinForceDecorateAtom);
}
@ -849,4 +885,41 @@ bool Utils::isCustomDecorationSupported()
return ((atom != XCB_NONE) && isSupportedByWindowManager(atom));
}
bool Utils::setPlatformPropertiesForWindow(QWindow *window, const QVariantHash &props)
{
Q_ASSERT(window);
Q_ASSERT(!props.isEmpty());
if (!window || props.isEmpty()) {
return false;
}
static const auto object = [window]() -> QObject * {
if (!qGuiApp) {
return nullptr;
}
using buildNativeSettingsPtr = bool(*)(QObject *, WId);
static const auto pbuildNativeSettings
= reinterpret_cast<buildNativeSettingsPtr>(
QGuiApplication::platformFunction(
FRAMELESSHELPER_BYTEARRAY_LITERAL("_d_buildNativeSettings")));
if (!pbuildNativeSettings) {
return nullptr;
}
const auto obj = new QObject(window);
if (!pbuildNativeSettings(obj, window->winId())) {
delete obj;
return nullptr;
}
return obj;
}();
if (!object) {
return false;
}
auto it = props.constBegin();
while (it != props.constEnd()) {
object->setProperty(qUtf8Printable(it.key()), it.value());
++it;
}
return true;
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -189,14 +189,13 @@ void FramelessWidgetsHelperPrivate::setBlurBehindWindowEnabled(const bool enable
return;
}
if (Utils::isBlurBehindWindowSupported()) {
#ifdef Q_OS_WINDOWS
QPalette palette = m_window->palette();
if (enable) {
m_savedWindowBackgroundColor = palette.color(QPalette::Window);
}
palette.setColor(QPalette::Window, (enable ? kDefaultTransparentColor : m_savedWindowBackgroundColor));
m_window->setPalette(palette);
#else // !Q_OS_WINDOWS
#ifndef Q_OS_WINDOWS
m_window->setAttribute(Qt::WA_TranslucentBackground, enable);
#endif // Q_OS_WINDOWS
if (Utils::setBlurBehindWindowEnabled(m_window->winId(),
@ -296,8 +295,7 @@ WidgetsSharedHelper *FramelessWidgetsHelperPrivate::findOrCreateSharedHelper(QWi
QWidget * const topLevelWindow = window->window();
WidgetsSharedHelper *helper = topLevelWindow->findChild<WidgetsSharedHelper *>();
if (!helper) {
helper = new WidgetsSharedHelper;
helper->setParent(topLevelWindow);
helper = new WidgetsSharedHelper(topLevelWindow);
helper->setup(topLevelWindow);
}
return helper;