* 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
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
endif
%:
- dh $@ --parallel
+ dh $@
override_dh_auto_configure:
dh_auto_configure -- LIB_INSTALL_DIR=/usr/lib/$(DEB_HOST_MULTIARCH) VERSION=$(CONFIG_VERSION)
--- /dev/null
+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
--- /dev/null
+#include "dthreadutils.h"
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
$$PWD/dnotifysender.h \
$$PWD/dexportedinterface.h \
$$PWD/dvtablehook.h \
- $$PWD/dfileservices.h
+ $$PWD/dfileservices.h \
+ $$PWD/dthreadutils.h
INCLUDEPATH += $$PWD
$$PWD/DNotifySender \
$$PWD/DExportedInterface \
$$PWD/DVtableHook \
- $$PWD/DFileServices
+ $$PWD/DFileServices \
+ $$PWD/DThreadUtils
RESOURCES += \
$$PWD/util.qrc
$$PWD/dnotifysender.cpp \
$$PWD/dpinyin.cpp \
$$PWD/dexportedinterface.cpp \
- $$PWD/dvtablehook.cpp
+ $$PWD/dvtablehook.cpp \
+ $$PWD/dthreadutils.cpp
linux {
QT += dbus
--- /dev/null
+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
--- /dev/null
+/*
+ * 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"
SUBDIRS += \
dutils \
dvtablehook \
- ddesktopentry
+ ddesktopentry \
+ dthreadutils