Skip to content

Commit 3df2e8f

Browse files
committed
refactor: replace private access hacks with accessor pattern
Remove all '#define private/protected public' hacks and replace them with a proper C++ template-based private accessor pattern using explicit template instantiation (friend injection trick), mirroring the approach used in linuxdeepin/treeland#875. Adds platformthemeplugin/dprivateaccessor_p.h with Accessor/AccessorImpl templates and D_DECLARE_PRIVATE_MEMBER, D_PRIVATE_MEMBER macros. All helpers live at global scope so ADL correctly resolves the friend-injected get() function.
1 parent b7b4e7f commit 3df2e8f

3 files changed

Lines changed: 102 additions & 12 deletions

File tree

platformthemeplugin/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
1+
# SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
22
#
33
# SPDX-License-Identifier: LGPL-3.0-or-later
44

@@ -55,6 +55,7 @@ dtk_add_plugin(
5555
main.cpp
5656
${DBUS_INTERFACES}
5757
HEADERS
58+
dprivateaccessor_p.h
5859
dthemesettings.h
5960
qdeepinfiledialoghelper.h
6061
qdeepintheme.h
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
2+
// SPDX-License-Identifier: LGPL-3.0-or-later
3+
4+
#pragma once
5+
6+
#include <QtCore/qcompilerdetection.h>
7+
8+
// Private member accessor using the explicit template instantiation technique.
9+
//
10+
// C++ Standard [temp.explicit]/12 states:
11+
// "The usual access checking rules do not apply to names used to
12+
// specify explicit instantiation definitions."
13+
//
14+
// This allows passing pointers to private/protected data members and
15+
// member functions as template arguments in explicit instantiations,
16+
// bypassing normal access control — without modifying the class definition
17+
// and without the UB caused by "#define private public".
18+
//
19+
// NOTE: The friend declaration must live inside the Tag struct so the friend
20+
// function is findable via ADL when calling get(TagName{}).
21+
22+
QT_WARNING_PUSH
23+
QT_WARNING_DISABLE_GCC("-Wnon-template-friend")
24+
25+
template<typename Tag>
26+
struct Qt5IntegrationPrivateAccessor
27+
{
28+
using MemberPtr = typename Tag::MemberPtr;
29+
friend MemberPtr get(Tag) noexcept;
30+
};
31+
32+
template<typename Tag, typename Tag::MemberPtr Ptr>
33+
struct Qt5IntegrationPrivateAccessorImpl : Qt5IntegrationPrivateAccessor<Tag>
34+
{
35+
friend typename Tag::MemberPtr get(Tag) noexcept { return Ptr; }
36+
};
37+
38+
QT_WARNING_POP
39+
40+
// Non-static data member access
41+
// Usage: D_PRIVATE_MEMBER(obj, TagName{}) → gives the member value (copy/ref)
42+
// Usage: &D_PRIVATE_MEMBER(obj, TagName{}) → gives address of member
43+
#define D_DECLARE_PRIVATE_MEMBER(TagName, ClassName, MemberName, MemberType) \
44+
struct TagName { \
45+
using MemberPtr = MemberType ClassName::*; \
46+
friend MemberPtr get(TagName) noexcept; \
47+
}; \
48+
template struct Qt5IntegrationPrivateAccessorImpl<TagName, &ClassName::MemberName>
49+
50+
// Trampoline: ensures get(tag) is called from a context with no class-scope
51+
// get() member that might suppress ADL (C++ [basic.lookup.argdep] para 3).
52+
namespace dtk_private_detail {
53+
template<typename Tag>
54+
inline typename Tag::MemberPtr access(Tag t) noexcept { return get(t); }
55+
}
56+
57+
#define D_PRIVATE_MEMBER(obj, tag) ((obj).*dtk_private_detail::access(tag))
58+
59+
// Non-static member function call
60+
// Usage: D_PRIVATE_CALL(obj, TagName{}, arg1, arg2)
61+
#define D_DECLARE_PRIVATE_FUNCTION(TagName, ClassName, FuncName, RetType, ...) \
62+
struct TagName { \
63+
using MemberPtr = RetType (ClassName::*)(__VA_ARGS__); \
64+
friend MemberPtr get(TagName) noexcept; \
65+
}; \
66+
template struct Qt5IntegrationPrivateAccessorImpl<TagName, &ClassName::FuncName>
67+
68+
#define D_PRIVATE_CALL(obj, tag, ...) ((obj).*dtk_private_detail::access(tag))(__VA_ARGS__)
69+
70+
// Static data member access
71+
// get(TagName{}) returns MemberType*, so D_PRIVATE_STATIC_MEMBER dereferences it
72+
#define D_DECLARE_PRIVATE_STATIC_MEMBER(TagName, ClassName, MemberName, MemberType) \
73+
struct TagName { \
74+
using MemberPtr = MemberType*; \
75+
friend MemberPtr get(TagName) noexcept; \
76+
}; \
77+
template struct Qt5IntegrationPrivateAccessorImpl<TagName, &ClassName::MemberName>
78+
79+
#define D_PRIVATE_STATIC_MEMBER(tag) (*dtk_private_detail::access(tag))

platformthemeplugin/qdeepintheme.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd.
2+
* SPDX-FileCopyrightText: 2017 - 2026 UnionTech Software Technology Co., Ltd.
33
* SPDX-License-Identifier: LGPL-3.0-or-later
44
*/
55
#include "qdeepintheme.h"
@@ -18,21 +18,31 @@
1818

1919
#include <private/qicon_p.h>
2020
#include <private/qiconloader_p.h>
21-
#define private public
2221
#include <private/qhighdpiscaling_p.h>
23-
#undef private
2422
#include <private/qwindow_p.h>
2523
#include <private/qguiapplication_p.h>
2624
#include <private/qfactoryloader_p.h>
2725
#include <qpa/qwindowsysteminterface_p.h>
2826
#include <qpa/qplatformscreen.h>
2927
#include <qpa/qplatformcursor.h>
28+
#include "dprivateaccessor_p.h"
3029

3130
#undef signals
3231
#include <X11/Xlib.h>
3332

3433
DGUI_USE_NAMESPACE
3534

35+
#if QT_VERSION < QT_VERSION_CHECK(5,14,0)
36+
using QHighDpiScaling_m_logicalDpi_type = QPair<qreal, qreal>;
37+
D_DECLARE_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_logicalDpi_tag, QHighDpiScaling, m_logicalDpi, QHighDpiScaling_m_logicalDpi_type);
38+
#elif QT_VERSION < QT_VERSION_CHECK(6,0,0)
39+
D_DECLARE_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_usePixelDensity_tag, QHighDpiScaling, m_usePixelDensity, bool);
40+
#else
41+
D_DECLARE_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_usePlatformPluginDpi_tag, QHighDpiScaling, m_usePlatformPluginDpi, bool);
42+
#endif
43+
D_DECLARE_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_factor_tag, QHighDpiScaling, m_factor, qreal);
44+
D_DECLARE_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_screenFactorSet_tag, QHighDpiScaling, m_screenFactorSet, bool);
45+
3646
#ifdef XDG_ICON_VERSION_MAR
3747
#include <XdgIcon>
3848
extern void updateXdgIconSystemTheme();
@@ -275,7 +285,7 @@ static bool updateScaleFactor(qreal value)
275285
value = 1.0;
276286
}
277287

278-
if (qFuzzyCompare(QHighDpiScaling::m_factor, value)) {
288+
if (qFuzzyCompare(D_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_factor_tag{}), value)) {
279289
return false;
280290
}
281291

@@ -386,20 +396,20 @@ static bool updateScaleLogcailDpi(const QPair<qreal, qreal> &dpi)
386396
bool ok = dpi.first >= 0 && dpi.second >= 0;
387397
#if QT_VERSION < QT_VERSION_CHECK(5,14,0)
388398
if (dpi.first > 0) {
389-
QHighDpiScaling::m_logicalDpi.first = dpi.first;
399+
D_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_logicalDpi_tag{}).first = dpi.first;
390400
} else if (qIsNull(dpi.first)) {
391-
QHighDpiScaling::m_logicalDpi.first = qGuiApp->primaryScreen()->handle()->logicalDpi().first;
401+
D_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_logicalDpi_tag{}).first = qGuiApp->primaryScreen()->handle()->logicalDpi().first;
392402
}
393403

394404
if (dpi.second > 0) {
395-
QHighDpiScaling::m_logicalDpi.second = dpi.second;
405+
D_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_logicalDpi_tag{}).second = dpi.second;
396406
} else if (qIsNull(dpi.second)) {
397-
QHighDpiScaling::m_logicalDpi.second = qGuiApp->primaryScreen()->handle()->logicalDpi().second;
407+
D_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_logicalDpi_tag{}).second = qGuiApp->primaryScreen()->handle()->logicalDpi().second;
398408
}
399409
#elif QT_VERSION < QT_VERSION_CHECK(6,0,0)
400-
QHighDpiScaling::m_usePixelDensity = false; // Do not use dpi from platform plugin
410+
D_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_usePixelDensity_tag{}) = false; // Do not use dpi from platform plugin
401411
#else
402-
QHighDpiScaling::m_usePlatformPluginDpi = false; // Do not use dpi from platform plugin
412+
D_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_usePlatformPluginDpi_tag{}) = false; // Do not use dpi from platform plugin
403413
#endif
404414
return ok;
405415
}
@@ -753,7 +763,7 @@ static void compelledUpdateScaleLogcailDpi() {
753763
}
754764

755765
static void onScreenAdded(QScreen *s) {
756-
if (QHighDpiScaling::m_screenFactorSet) {
766+
if (D_PRIVATE_STATIC_MEMBER(QHighDpiScaling_m_screenFactorSet_tag{})) {
757767
auto setting = QDeepinTheme::getSettings();
758768
auto value = setting->screenScaleFactors();
759769

0 commit comments

Comments
 (0)