New upstream Version 5.2.2.5
authorTuQinggang <tuqinggang@uniontech.com>
Wed, 2 Sep 2020 09:54:56 +0000 (09:54 +0000)
committerTuQinggang <tuqinggang@uniontech.com>
Wed, 2 Sep 2020 09:54:56 +0000 (09:54 +0000)
12 files changed:
debian/changelog
debian/compat
debian/control
debian/rules
rpm/dtkcore.spec [new file with mode: 0644]
src/util/DThreadUtils [new file with mode: 0644]
src/util/dthreadutils.cpp [new file with mode: 0644]
src/util/dthreadutils.h [new file with mode: 0644]
src/util/util.pri
tests/dthreadutils/dthreadutils.pro [new file with mode: 0644]
tests/dthreadutils/tst_dthreadutils.cpp [new file with mode: 0644]
tests/tests.pro

index 63463dc7119294cf4173b36d6a53b40014077c42..88df8f372b655186bbfe4c8565d8251544b7b9e1 100644 (file)
@@ -2,7 +2,7 @@ dtkcore (5.0.3) unstable; urgency=medium
 
   * Release 5.0.3
 
- -- Deepin Packages Builder <packages@deepin.com>  Tue, 21 Sep 2019 13:31:03 +0800
+ -- Deepin Packages Builder <packages@deepin.com>  Sat, 21 Sep 2019 13:31:03 +0800
 
 dtkcore (5.0.0) unstable; urgency=medium
 
index ec635144f60048986bc560c5576355344005e6e7..48082f72f087ce7e6fa75b9c41d7387daecd447b 100644 (file)
@@ -1 +1 @@
-9
+12
index 0a5dde2a77b85a95fd6d27bd558d992ff6878dd8..9c46a7ec7687d2afdaa9dc7d47ae30a7d896b4bf 100644 (file)
@@ -2,7 +2,7 @@ Source: dtkcore
 Section: libdevel
 Priority: optional
 Maintainer: Deepin Packages Builder <packages@deepin.com>
-Build-Depends: debhelper (>= 9), pkg-config,
+Build-Depends: debhelper (>= 12), pkg-config,
  qttools5-dev-tools, qtbase5-private-dev,
  libgsettings-qt-dev
 Standards-Version: 3.9.8
index d13bf0f16e7d389f6446c56855e09b9d2def59c2..d911e370e6a74ad88f2369f6bd67a5d79317a445 100755 (executable)
@@ -19,7 +19,7 @@ endif
 endif
 
 %:
-       dh $@ --parallel
+       dh $@ 
 
 override_dh_auto_configure:
        dh_auto_configure -- LIB_INSTALL_DIR=/usr/lib/$(DEB_HOST_MULTIARCH) VERSION=$(CONFIG_VERSION)
diff --git a/rpm/dtkcore.spec b/rpm/dtkcore.spec
new file mode 100644 (file)
index 0000000..5358875
--- /dev/null
@@ -0,0 +1,75 @@
+Name:           dtkcore
+Version:        5.2.2.3
+Release:        1%{?dist}
+Summary:        Deepin tool kit core modules
+License:        GPLv3
+URL:            https://github.com/linuxdeepin/dtkcore
+Source0:        %{name}_%{version}.orig.tar.xz
+BuildRequires:  gcc-c++
+BuildRequires:  annobin
+BuildRequires:  pkgconfig(Qt5Core)
+BuildRequires:  pkgconfig(gsettings-qt)
+Obsoletes:      deepin-tool-kit <= 0.3.3
+Obsoletes:      deepin-tool-kit-devel <= 0.3.3
+Obsoletes:      dtksettings <= 0.1.7
+Obsoletes:      dtksettings-devel <= 0.1.7
+
+%description
+Deepin tool kit core modules.
+
+%package devel
+Summary:        Development package for %{name}
+Requires:       %{name}%{?_isa} = %{version}-%{release}
+Requires:       qt5-qtbase-devel
+
+%description devel
+Header files and libraries for %{name}.
+
+%prep
+%setup -q
+
+sed -i 's|/lib|/libexec|' tools/settings/settings.pro
+## consider relying on %%_qt5_bindir (see %%build below) instead of patching -- rex
+#sed -i 's|qmake|qmake-qt5|' src/dtk_module.prf
+#sed -i 's|lrelease|lrelease-qt5|' tools/script/dtk-translate.py src/dtk_translation.prf
+
+%build
+# help find (and prefer) qt5 utilities, e.g. qmake, lrelease
+export PATH=%{_qt5_bindir}:$PATH
+%qmake_qt5 PREFIX=%{_prefix} \
+           DTK_VERSION=%{version} \
+           LIB_INSTALL_DIR=%{_libdir} \
+           BIN_INSTALL_DIR=%{_libexecdir}/dtk5 \
+           TOOL_INSTALL_DIR=%{_libexecdir}/dtk5
+%make_build
+
+%install
+%make_install INSTALL_ROOT=%{buildroot}
+
+%ldconfig_scriptlets
+
+%files
+%doc README.md
+%license LICENSE
+%{_libdir}/libdtkcore.so.*
+%{_libexecdir}/dtk5/dtk-settings
+%{_libexecdir}/dtk5/dtk-license.py*
+%{_libexecdir}/dtk5/dtk-translate.py*
+%{_libexecdir}/dtk5/deepin-os-release
+
+%files devel
+%doc doc/Specification.md
+%{_includedir}/libdtk-*/
+%{_qt5_archdatadir}/mkspecs/features/*.prf
+%{_qt5_archdatadir}/mkspecs/modules/*.pri
+%{_libdir}/cmake/Dtk/
+%{_libdir}/cmake/DtkCore/
+%{_libdir}/cmake/DtkCMake/
+%{_libdir}/cmake/DtkTools/
+%{_libdir}/pkgconfig/dtkcore.pc
+%{_libdir}/libdtkcore.so
+/usr/share/glib-2.0/schemas/*
+
+%changelog
+* Thu Jun 11 2020 uoser <uoser@uniontech.com> - 5.2.2.3
+- Update to 5.2.2.3
diff --git a/src/util/DThreadUtils b/src/util/DThreadUtils
new file mode 100644 (file)
index 0000000..13b83d8
--- /dev/null
@@ -0,0 +1 @@
+#include "dthreadutils.h"
diff --git a/src/util/dthreadutils.cpp b/src/util/dthreadutils.cpp
new file mode 100644 (file)
index 0000000..e459129
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 ~ 2020 Deepin Technology Co., Ltd.
+ *
+ * Author:     zccrs <zccrs@live.com>
+ *
+ * Maintainer: zccrs <zhangjide@deepin.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dthreadutils.h"
+
+DCORE_BEGIN_NAMESPACE
+
+namespace DThreadUtil {
+FunctionCallProxy::FunctionCallProxy(QThread *thread)
+{
+    qRegisterMetaType<QPointer<QObject>>();
+
+    connect(this, &FunctionCallProxy::callInLiveThread, this, [] (QSemaphore *s, QPointer<QObject> target, FunctionType *func) {
+        if (Q_LIKELY(target)) {
+            (*func)();
+        } else {
+            qWarning() << "DThreadUtils::runInThread:" << "The target object is destoryed";
+        }
+
+        s->release();
+    }, Qt::QueuedConnection);
+    connect(thread, &QThread::finished, this, [this] {
+        qWarning() << "DThreadUtils::runInThread:" << sender() << "the thread finished";
+    }, Qt::DirectConnection);
+}
+
+void FunctionCallProxy::proxyCall(QSemaphore *s, QThread *thread, QObject *target, FunctionType fun)
+{
+    if (QThread::currentThread() == thread)
+        return fun();
+
+    FunctionCallProxy proxy(thread);
+    proxy.moveToThread(thread);
+
+    // 如果线程未开启事件循环,且不是主线程,则需要给出严重警告信息,因为可能会导致死锁
+    if (thread->loopLevel() <= 0 && (!QCoreApplication::instance() || thread != QCoreApplication::instance()->thread())) {
+        qCritical() << Q_FUNC_INFO << thread << ", the thread no event loop";
+    }
+
+    proxy.callInLiveThread(s, target ? target : &proxy, &fun);
+    s->acquire();
+}
+} // end namespace DThreadUtil
+
+DCORE_END_NAMESPACE
diff --git a/src/util/dthreadutils.h b/src/util/dthreadutils.h
new file mode 100644 (file)
index 0000000..3b1609a
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2020 ~ 2020 Deepin Technology Co., Ltd.
+ *
+ * Author:     zccrs <zccrs@live.com>
+ *
+ * Maintainer: zccrs <zhangjide@deepin.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef DTHREADUTILS_H
+#define DTHREADUTILS_H
+
+#include <dtkcore_global.h>
+#include <QObject>
+#include <QSemaphore>
+#include <QThread>
+#include <QCoreApplication>
+#include <QPointer>
+#include <QDebug>
+
+DCORE_BEGIN_NAMESPACE
+
+namespace DThreadUtil {
+typedef std::function<void()> FunctionType;
+
+class FunctionCallProxy : public QObject
+{
+    Q_OBJECT
+public:
+    explicit FunctionCallProxy(QThread *thread);
+
+    static void proxyCall(QSemaphore *s, QThread *thread, QObject *target, FunctionType fun);
+
+Q_SIGNALS:
+    void callInLiveThread(QSemaphore *s, QPointer<QObject> target, FunctionType *func);
+};
+
+template <typename ReturnType>
+class _TMP
+{
+public:
+    inline static ReturnType runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function<ReturnType()> fun)
+    {
+        ReturnType result;
+        FunctionType proxyFun = [&result, &fun] () {
+            result = fun();
+        };
+
+        FunctionCallProxy::proxyCall(s, thread, target, proxyFun);
+        return result;
+    }
+
+    template <typename T>
+    inline static typename std::enable_if<!std::is_base_of<QObject, T>::value, ReturnType>::type
+            runInThread(QSemaphore *s, QThread *thread, T *, std::function<ReturnType()> fun)
+    {
+        return runInThread(s, thread, static_cast<QObject*>(nullptr), fun);
+    }
+};
+template <>
+class _TMP<void>
+{
+public:
+    inline static void runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function<void()> fun)
+    {
+        FunctionCallProxy::proxyCall(s, thread, target, fun);
+    }
+
+    template <typename T>
+    inline static typename std::enable_if<!std::is_base_of<QObject, T>::value, void>::type
+            runInThread(QSemaphore *s, QThread *thread, T *, std::function<void()> fun)
+    {
+        return runInThread(s, thread, static_cast<QObject*>(nullptr), fun);
+    }
+};
+
+template <typename Fun, typename... Args>
+inline auto runInThread(QSemaphore *s, QThread *thread, QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...))
+{
+    return _TMP<decltype(fun(args...))>::runInThread(s, thread, target, std::bind(fun, std::forward<Args>(args)...));
+}
+template <typename Fun, typename... Args>
+inline auto runInThread(QSemaphore *s, QThread *thread, Fun fun, Args&&... args) -> decltype(fun(args...))
+{
+    return runInThread(s, thread, nullptr, fun, std::forward<Args>(args)...);
+}
+template <typename Fun, typename... Args>
+inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
+        runInThread(QSemaphore *s, QThread *thread, QObject *target, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
+{
+    return _TMP<typename QtPrivate::FunctionPointer<Fun>::ReturnType>::runInThread(s, thread, target, std::bind(fun, obj, std::forward<Args>(args)...));
+}
+template <typename Fun, typename... Args>
+inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
+        runInThread(QSemaphore *s, QThread *thread, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
+{
+    return _TMP<typename QtPrivate::FunctionPointer<Fun>::ReturnType>::runInThread(s, thread, obj, std::bind(fun, obj, std::forward<Args>(args)...));
+}
+
+template <typename Fun, typename... Args>
+inline auto runInThread(QThread *thread, QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...))
+{
+    QSemaphore s;
+
+    return runInThread(&s, thread, target, fun, std::forward<Args>(args)...);
+}
+template <typename Fun, typename... Args>
+inline auto runInThread(QThread *thread, Fun fun, Args&&... args) -> decltype(fun(args...))
+{
+    return runInThread(thread, nullptr, fun, std::forward<Args>(args)...);
+}
+template <typename T, typename Fun, typename... Args>
+inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
+        runInThread(QThread *thread, T *target, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
+{
+    QSemaphore s;
+
+    return runInThread(&s, thread, target, obj, fun, std::forward<Args>(args)...);
+}
+
+template <typename Fun, typename... Args>
+inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
+        runInThread(QThread *thread, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
+{
+    return runInThread(thread, obj, obj, fun, std::forward<Args>(args)...);
+}
+
+template <typename Fun, typename... Args>
+inline auto runInMainThread(QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...))
+{
+    if (!QCoreApplication::instance()) {
+        return fun(std::forward<Args>(args)...);
+    }
+
+    return runInThread(QCoreApplication::instance()->thread(), target, fun, std::forward<Args>(args)...);
+}
+template <typename Fun, typename... Args>
+inline auto runInMainThread(Fun fun, Args&&... args) -> decltype(fun(args...))
+{
+    return runInMainThread(nullptr, fun, std::forward<Args>(args)...);
+}
+
+template <typename T, typename Fun, typename... Args>
+inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
+        runInMainThread(T *target, typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
+{
+    if (!QCoreApplication::instance()) {
+        return (obj->*fun)(std::forward<Args>(args)...);
+    }
+
+    return runInThread(QCoreApplication::instance()->thread(), target, obj, fun, std::forward<Args>(args)...);
+}
+template <typename Fun, typename... Args>
+inline typename QtPrivate::FunctionPointer<Fun>::ReturnType
+        runInMainThread(typename QtPrivate::FunctionPointer<Fun>::Object *obj, Fun fun, Args&&... args)
+{
+    return runInMainThread(obj, obj, fun, std::forward<Args>(args)...);
+}
+}
+
+DCORE_END_NAMESPACE
+
+#endif // DTHREADUTILS_H
index a45dea8e082fcdc76b41b4ed9d85579a3fb52fd4..3f2353c0ab4c1ff7b5df0ff85fd5c9adfc33e7d2 100644 (file)
@@ -9,7 +9,8 @@ HEADERS += \
     $$PWD/dnotifysender.h \
     $$PWD/dexportedinterface.h \
     $$PWD/dvtablehook.h \
-    $$PWD/dfileservices.h
+    $$PWD/dfileservices.h \
+    $$PWD/dthreadutils.h
 
 INCLUDEPATH += $$PWD
 
@@ -22,7 +23,8 @@ includes.files += \
     $$PWD/DNotifySender \
     $$PWD/DExportedInterface \
     $$PWD/DVtableHook \
-    $$PWD/DFileServices
+    $$PWD/DFileServices \
+    $$PWD/DThreadUtils
 
 RESOURCES += \
     $$PWD/util.qrc
@@ -36,7 +38,8 @@ SOURCES += \
     $$PWD/dnotifysender.cpp \
     $$PWD/dpinyin.cpp \
     $$PWD/dexportedinterface.cpp \
-    $$PWD/dvtablehook.cpp
+    $$PWD/dvtablehook.cpp \
+    $$PWD/dthreadutils.cpp
 
 linux {
     QT += dbus
diff --git a/tests/dthreadutils/dthreadutils.pro b/tests/dthreadutils/dthreadutils.pro
new file mode 100644 (file)
index 0000000..aa6af36
--- /dev/null
@@ -0,0 +1,25 @@
+QT += testlib concurrent
+QT -= gui
+
+TEMPLATE = app
+CONFIG += c++11
+
+!isEmpty(DTK_STATIC_LIB){
+    DEFINES += DTK_STATIC_LIB
+}
+
+win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../src/release/ -ldtkcore
+else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../src/debug/ -ldtkcore
+else:unix: LIBS += -L$$OUT_PWD/../../src/ -ldtkcore
+
+INCLUDEPATH += $$PWD/../../src
+DEPENDPATH += $$PWD/../../src
+
+CONFIG(debug, debug|release) {
+    unix:QMAKE_RPATHDIR += $$OUT_PWD/../../src
+}
+
+QMAKE_LFLAGS += -Wl,--export-dynamic
+
+SOURCES += \
+    tst_dthreadutils.cpp
diff --git a/tests/dthreadutils/tst_dthreadutils.cpp b/tests/dthreadutils/tst_dthreadutils.cpp
new file mode 100644 (file)
index 0000000..b25c8fc
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 ~ 2020 Deepin Technology Co., Ltd.
+ *
+ * Author:     zccrs <zccrs@live.com>
+ *
+ * Maintainer: zccrs <zhangjide@deepin.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QObject>
+#include <QTest>
+#include <QtConcurrent>
+
+#include <util/DThreadUtils>
+
+DCORE_USE_NAMESPACE
+
+class tst_DThreadUtils : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testCallInMainThread();
+};
+
+void tst_DThreadUtils::testCallInMainThread()
+{
+    QVERIFY(DThreadUtil::runInMainThread([] {
+        return QThread::currentThread() == QCoreApplication::instance()->thread();
+    }));
+
+    auto result = QtConcurrent::run([] {
+        QThread *t = QThread::currentThread();
+        QVERIFY(DThreadUtil::runInMainThread([] (QThread *thread) {
+            return QThread::currentThread() == QCoreApplication::instance()->thread() && QThread::currentThread() != thread;
+        }, t));
+    });
+
+    QVERIFY(QTest::qWaitFor([&] {
+        return result.isFinished();
+    }));
+
+    {
+        // 测试target对象销毁后是否还会触发函数调用
+        QPointer<QObject> object = new QObject();
+        bool test = true;
+        auto result1 = QtConcurrent::run([&test, object] {
+            DThreadUtil::runInMainThread(object, [&test, object] () {
+                if (!object)
+                    return false;
+
+                delete object.data();
+                return true;
+            });
+        });
+        auto result2 = QtConcurrent::run([&test, object] {
+            DThreadUtil::runInMainThread(object, [&test, object] () {
+                if (!object)
+                    return false;
+
+                delete object.data();
+                return true;
+            });
+        });
+
+        QVERIFY(QTest::qWaitFor([&] {
+            return result1.isFinished() && result2.isFinished();
+        }));
+        QVERIFY(test);
+    }
+}
+
+QTEST_MAIN(tst_DThreadUtils)
+
+#include "tst_dthreadutils.moc"
index d37cc258a3eb6d862b8e8f763e57a1bc1bb3bc14..2a5e2de18a140488257bb598e559e96715f6d473 100644 (file)
@@ -2,4 +2,5 @@ TEMPLATE = subdirs
 SUBDIRS += \
     dutils \
     dvtablehook \
-    ddesktopentry
+    ddesktopentry \
+    dthreadutils