Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions .github/workflows/qt5platform-plugins-archlinux-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: Build qt5platform-plugins on Arch Linux

on:
push:

pull_request:

jobs:
container:
runs-on: ubuntu-latest
container: archlinux:latest
steps:
- name: Initialize pacman and system update
run: |
pacman-key --init
pacman --noconfirm --noprogressbar -Syu

- name: Install base build tools
run: |
pacman -S --noconfirm --noprogressbar base-devel git cmake ninja pkgconf

- name: Install qt5platform-plugins system dependencies
run: |
pacman -S --noconfirm --noprogressbar \
qt5-base qt5-xcb-private-headers qt5-x11extras qt5-wayland \
extra-cmake-modules \
gtest \
libxcb xcb-util xcb-util-image xcb-util-keysyms \
xcb-util-renderutil xcb-util-wm xcb-util-cursor \
libxkbcommon libxkbcommon-x11 \
libxi libxrender libsm libice cairo \
dbus libglvnd fontconfig glib2 mtdev systemd \
kwayland5 \
dtkcommon

- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Print Qt5 version and available xcb private headers
run: |
qmake --version
echo "--- qtxcb-private headers ---"
ls /usr/include/qtxcb-private/ | cat
echo "--- QXcbBackingStore m_image check ---"
grep -n "m_image" /usr/include/qtxcb-private/qxcbbackingstore.h 2>/dev/null || echo "NOT FOUND"
echo "--- QXcbCursor m_cursorHash check ---"
grep -n "m_cursorHash\|CursorHash" /usr/include/qtxcb-private/qxcbcursor.h 2>/dev/null || echo "NOT FOUND"
echo "--- QXcbDrag members check ---"
grep -n "currentWindow\|currentPosition\|m_dropData\|accepted_drop_action\|xdnd_dragsource\|target_time\|waiting_for_status\|current_proxy_target" /usr/include/qtxcb-private/qxcbdrag.h 2>/dev/null || echo "NOT FOUND"

- name: Configure and build qt5platform-plugins
run: |
set -o pipefail
cmake -B build \
-GNinja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=lib \
-DCMAKE_BUILD_TYPE=Release \
-DQT_XCB_PRIVATE_HEADERS=/usr/include/qtxcb-private \
-DDTK5=ON 2>&1 | tee /tmp/cmake-configure.log
cmake --build build -j$(nproc) 2>&1 | tee /tmp/cmake-build.log
echo "✅ qt5platform-plugins built successfully!"
echo "=== Built .so files ==="
find build -name "*.so" | head -20

- name: Print build logs on failure
if: failure()
run: |
echo "=== cmake-configure.log ==="
cat /tmp/cmake-configure.log 2>/dev/null || echo "(not found)"
echo "=== cmake-build.log (last 100 lines) ==="
tail -100 /tmp/cmake-build.log 2>/dev/null || echo "(not found)"

- name: Install qt5platform-plugins to staging directory
run: |
DESTDIR=/tmp/qt5platform-plugins-install cmake --install build --verbose
echo "Total: $(find /tmp/qt5platform-plugins-install -type f | wc -l) files"
find /tmp/qt5platform-plugins-install -type f | head -20

- name: Create installation package
run: |
ls -la /tmp/qt5platform-plugins-install/ || { echo "Install dir missing!"; exit 1; }
tar -czf /tmp/qt5platform-plugins-archlinux-$(date +%Y%m%d-%H%M%S).tar.gz -C /tmp/qt5platform-plugins-install .
ls -la /tmp/qt5platform-plugins-archlinux-*.tar.gz

- name: Upload qt5platform-plugins Arch Linux build artifacts
if: ${{ !env.ACT }}
uses: actions/upload-artifact@v4
with:
name: qt5platform-plugins-archlinux-build
path: "/tmp/qt5platform-plugins-archlinux-*.tar.gz"
if-no-files-found: error
retention-days: 30
71 changes: 71 additions & 0 deletions .github/workflows/qt5platform-plugins-deepin-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Build qt5platform-plugins on Deepin crimson

on:
push:

pull_request:

jobs:
container:
runs-on: ubuntu-latest
container: linuxdeepin/deepin:crimson
steps:
- uses: actions/checkout@v4

- name: Setup apt sources and build tools
run: |
set -euxo pipefail
echo "deb [trusted=yes] http://mirrors.kernel.org/deepin/beige/ crimson main commercial community" > /etc/apt/sources.list
echo "deb-src [trusted=yes] http://mirrors.kernel.org/deepin/beige/ crimson main commercial community" >> /etc/apt/sources.list
rm -rf /etc/apt/sources.list.d
apt-get update
apt-get install -y devscripts equivs git

- name: Build and install dtkcommon from source
run: |
set -euxo pipefail
cd /tmp
git clone --depth=1 https://github.com/linuxdeepin/dtkcommon.git
cd dtkcommon
mk-build-deps --install --remove --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control
dpkg-buildpackage -uc -us -b
dpkg -i ../*.deb 2>/dev/null || apt-get install -f -y
echo "✅ dtkcommon installed"

- name: Install qt5platform-plugins build dependencies
run: |
set -euxo pipefail
mk-build-deps --install --remove --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control

- name: Build qt5platform-plugins deb packages
run: |
dpkg-buildpackage -uc -us -b 2>&1 | tee /tmp/build.log
if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "❌ Build failed!"
exit 1
fi
echo "✅ qt5platform-plugins deb packages built successfully!"
ls -la ../

- name: Upload build log on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: qt5platform-plugins-deepin-build-log
path: /tmp/build.log
if-no-files-found: warn
retention-days: 7

- name: Collect deb artifacts
run: |
mkdir -p dist
mv ../*.deb dist/
ls -la dist

- name: Upload qt5platform-plugins deb packages as artifacts
uses: actions/upload-artifact@v4
with:
name: qt5platform-plugins-deepin-deb-packages
path: dist/*.deb
if-no-files-found: error
retention-days: 30
7 changes: 5 additions & 2 deletions src/dnativesettings.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2017 - 2022 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2017 - 2026 Uniontech Software Technology Co.,Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand All @@ -21,9 +21,12 @@
#define IN_DXCB_PLUGIN
#endif

#include "util/dprivateaccessor_p.h"
D_DECLARE_PRIVATE_CONST_METHOD(QObject_senderSignalIndex, QObject, senderSignalIndex, int);

#include <QDebug>

Check warning on line 27 in src/dnativesettings.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDebug> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 27 in src/dnativesettings.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QDebug> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QMetaProperty>

Check warning on line 28 in src/dnativesettings.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMetaProperty> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 28 in src/dnativesettings.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QMetaProperty> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QMetaMethod>

Check warning on line 29 in src/dnativesettings.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMetaMethod> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 29 in src/dnativesettings.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QMetaMethod> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#define VALID_PROPERTIES "validProperties"
#define ALL_KEYS "allKeys"
Expand Down Expand Up @@ -439,7 +442,7 @@
break;
}

int signal = m_base->senderSignalIndex();
int signal = D_PRIVATE_CALL(*m_base, QObject_senderSignalIndex{});
QByteArray signal_name;
qint32 data1 = 0, data2 = 0;

Expand Down
4 changes: 1 addition & 3 deletions src/dnativesettings.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
// SPDX-FileCopyrightText: 2017 - 2022 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2017 - 2026 Uniontech Software Technology Co.,Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#ifndef DNATIVESETTINGS_H
#define DNATIVESETTINGS_H

#define protected public
#include <private/qobject_p.h>

Check warning on line 8 in src/dnativesettings.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <private/qobject_p.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 8 in src/dnativesettings.h

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <private/qobject_p.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#undef protected

#include "global.h"

Expand Down
1 change: 1 addition & 0 deletions src/src.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# SPDX-License-Identifier: LGPL-3.0-or-later

list(APPEND GLOBAL_HEADERS
${CMAKE_CURRENT_LIST_DIR}/util/dprivateaccessor_p.h
${CMAKE_CURRENT_LIST_DIR}/dbackingstoreproxy.h
${CMAKE_CURRENT_LIST_DIR}/dnativesettings.h
${CMAKE_CURRENT_LIST_DIR}/dopenglpaintdevice.h
Expand Down
114 changes: 114 additions & 0 deletions src/util/dprivateaccessor_p.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#pragma once

#include <QtCore/qcompilerdetection.h>

Check warning on line 7 in src/util/dprivateaccessor_p.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QtCore/qcompilerdetection.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 7 in src/util/dprivateaccessor_p.h

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QtCore/qcompilerdetection.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

// Private member accessor using the explicit template instantiation technique.
//
// C++ Standard [temp.explicit]/12 states:
// "The usual access checking rules do not apply to names used to
// specify explicit instantiation definitions."
//
// This allows passing pointers to private/protected data members and
// member functions as template arguments in explicit instantiations,
// bypassing normal access control — without modifying the class definition
// and without the UB caused by "#define private public".
//
// NOTE: These helper structs must be in the SAME namespace as the Tag structs
// (global namespace, since the macros expand at file scope). If they were in a
// sub-namespace, the friend definition would create a different function than
// the friend declaration in the Tag struct, causing undefined-reference errors.

QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wnon-template-friend")

template<typename Tag>
struct Qt5PlatformPrivateAccessor
{
using MemberPtr = typename Tag::MemberPtr;
friend MemberPtr get(Tag) noexcept;
};

template<typename Tag, typename Tag::MemberPtr Ptr>
struct Qt5PlatformPrivateAccessorImpl : Qt5PlatformPrivateAccessor<Tag>
{
friend typename Tag::MemberPtr get(Tag) noexcept { return Ptr; }
};

QT_WARNING_POP

#define D_DECLARE_PRIVATE_MEMBER(TagName, ClassName, Member, MemberType) \
struct TagName { \
using MemberPtr = MemberType ClassName::*; \
friend MemberPtr get(TagName) noexcept; \
}; \
template struct Qt5PlatformPrivateAccessorImpl<TagName, &ClassName::Member>

#define D_DECLARE_PRIVATE_METHOD(TagName, ClassName, MethodName, RetType, ...) \
struct TagName { \
using MemberPtr = RetType (ClassName::*)(__VA_ARGS__); \
friend MemberPtr get(TagName) noexcept; \
}; \
template struct Qt5PlatformPrivateAccessorImpl<TagName, &ClassName::MethodName>

#define D_DECLARE_PRIVATE_CONST_METHOD(TagName, ClassName, MethodName, RetType, ...) \
struct TagName { \
using MemberPtr = RetType (ClassName::*)(__VA_ARGS__) const; \
friend MemberPtr get(TagName) noexcept; \
}; \
template struct Qt5PlatformPrivateAccessorImpl<TagName, &ClassName::MethodName>

// Trampoline: ensures get(tag) is called from a context with no class-scope
// get() member that might suppress ADL (C++ [basic.lookup.argdep] para 3).
namespace dtk_private_detail {
template<typename Tag>
inline typename Tag::MemberPtr access(Tag t) noexcept { return get(t); }

// For auto-type tags (D_DECLARE_AUTO_PRIVATE_MEMBER_TAG) that don't define MemberPtr.
template<typename Tag>
inline auto access_auto(Tag t) noexcept -> decltype(get(t)) { return get(t); }

Check warning on line 72 in src/util/dprivateaccessor_p.h

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'access_auto' is never used.

Check warning on line 72 in src/util/dprivateaccessor_p.h

View workflow job for this annotation

GitHub Actions / static-check / static-check

The function 'access_auto' is never used.
Comment on lines +66 to +72
}

#define D_PRIVATE_MEMBER(obj, tag) ((obj).*dtk_private_detail::access(tag))
#define D_PRIVATE_CALL(obj, tag, ...) ((obj).*dtk_private_detail::access(tag))(__VA_ARGS__)

// For member types that involve private enum/type names that can't be spelled
// outside the class: use a C++17 auto non-type template parameter so the
// member pointer type is deduced without naming the private type explicitly.
template<auto Ptr>
struct Qt5PlatformAutoPrivateAccessor
{
template<typename T>
static decltype(auto) access(T &obj) noexcept { return obj.*Ptr; }
};

// Explicit instantiation to bypass access control at the instantiation point.
// After this, callers can reference Qt5PlatformAutoPrivateAccessor<Ptr>::access()
// without re-triggering access checks.
#define D_DECLARE_AUTO_PRIVATE_MEMBER(ClassName, Member) \
template struct Qt5PlatformAutoPrivateAccessor<&ClassName::Member>

// Alternative auto accessor using the same get(Tag{}) pattern as D_DECLARE_PRIVATE_MEMBER,
// but without needing to name the member's type. Use this for members whose type involves
// private nested types (e.g., private enums) that cannot be spelled at the call site.
//
// The friend declaration MUST be in TagName itself so ADL can find get() when
// called as get(TagName{}) -- ADL only searches TagName's associated classes, not TagName##Impl.
//
// Usage:
// D_DECLARE_AUTO_PRIVATE_MEMBER_TAG(MyTag, ClassName, myMember);
// auto &ref = obj.*get(MyTag{}); // no access check needed here
#define D_DECLARE_AUTO_PRIVATE_MEMBER_TAG(TagName, ClassName, Member) \
struct TagName { \
friend auto get(TagName) noexcept; \
}; \
template<auto Ptr> \
struct TagName##Impl { \
friend auto get(TagName) noexcept { return Ptr; } \
}; \
template struct TagName##Impl<&ClassName::Member>
Comment on lines +104 to +112

#define D_AUTO_PRIVATE_MEMBER(obj, tag) ((obj).*dtk_private_detail::access_auto(tag{}))
18 changes: 8 additions & 10 deletions wayland/dwayland/dnotitlebarwindowhelper_wl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "dnotitlebarwindowhelper_wl.h"
#include "vtablehook.h"

Check warning on line 6 in wayland/dwayland/dnotitlebarwindowhelper_wl.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "vtablehook.h" not found.

Check warning on line 6 in wayland/dwayland/dnotitlebarwindowhelper_wl.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: "vtablehook.h" not found.

#define protected public
#include <QWindow>

Check warning on line 7 in wayland/dwayland/dnotitlebarwindowhelper_wl.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QWindow> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 7 in wayland/dwayland/dnotitlebarwindowhelper_wl.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QWindow> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#undef protected
#include "util/dprivateaccessor_p.h"

Check warning on line 8 in wayland/dwayland/dnotitlebarwindowhelper_wl.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "util/dprivateaccessor_p.h" not found.

Check warning on line 8 in wayland/dwayland/dnotitlebarwindowhelper_wl.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: "util/dprivateaccessor_p.h" not found.
D_DECLARE_PRIVATE_METHOD(QWindow_event_wl, QWindow, event, bool, QEvent *);

#include <QMouseEvent>

Check warning on line 11 in wayland/dwayland/dnotitlebarwindowhelper_wl.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMouseEvent> not found. Please note: Cppcheck does not need standard library headers to get proper results.

Check warning on line 11 in wayland/dwayland/dnotitlebarwindowhelper_wl.cpp

View workflow job for this annotation

GitHub Actions / static-check / static-check

Include file: <QMouseEvent> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QGuiApplication>
#include <QStyleHints>
#include <QTimer>
Expand All @@ -17,12 +17,10 @@
#include <qpa/qplatformwindow.h>
#include <QtWaylandClientVersion>

#define private public
#include "QtWaylandClient/private/qwaylandintegration_p.h"
#include "QtWaylandClient/private/qwaylandshellsurface_p.h"
#include "QtWaylandClient/private/qwaylandwindow_p.h"
#include "QtWaylandClient/private/qwaylandcursor_p.h"
#undef private

#include <private/qguiapplication_p.h>

Expand Down Expand Up @@ -141,9 +139,9 @@
m_enableSystemMove = !v.isValid() || v.toBool();

if (m_enableSystemMove) {
HookOverride(m_window, &QWindow::event, &DNoTitlebarWlWindowHelper::windowEvent);
HookOverride(m_window, get(QWindow_event_wl{}), &DNoTitlebarWlWindowHelper::windowEvent);
} else if (VtableHook::hasVtable(m_window)) {
HookReset(m_window, &QWindow::event);
HookReset(m_window, get(QWindow_event_wl{}));
}
}

Expand All @@ -152,7 +150,7 @@
DNoTitlebarWlWindowHelper *self = mapped.value(w);

if (!self)
return VtableHook::callOriginalFun(w, &QWindow::event, event);
return VtableHook::callOriginalFun(w, get(QWindow_event_wl{}), event);
// m_window 的 event 被 override 以后,在 windowEvent 里面获取到的 this 就成 m_window 了,
// 而不是 DNoTitlebarWlWindowHelper,所以此处 windowEvent 改为 static 并传 self 进来
{
Expand All @@ -173,7 +171,7 @@
QPointF currentPos = static_cast<QMouseEvent*>(event)->globalPos();
QPointF delta = touchBeginPosition - currentPos;
if (delta.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) {
return VtableHook::callOriginalFun(w, &QWindow::event, event);
return VtableHook::callOriginalFun(w, get(QWindow_event_wl{}), event);
}
}
}
Expand All @@ -184,7 +182,7 @@
self->m_windowMoving = false;
}

if (!HookCall(w, &QWindow::event, event))
if (!HookCall(w, get(QWindow_event_wl{}), event))
return false;

// workaround for kwin: Qt receives no release event when kwin finishes MOVE operation,
Expand Down
Loading
Loading