Port QCoreApplication::requestPermission() to SlotObjUniquePtr internally
Well, except that the ownership of the slot object here is actually shared between the PermissionReceiver and the lambda passed to QPermission::Private::requestPermission(), which eventually may hand ownership over to QMetaCallEvent, so we can't really use SlotObjUniquePtr. While we can, of course, manually copy and call ref(), even if the slot-object is stored in a SlotObjUniquePtr, unfortunately, the lambda is subsequently stored in a std::function, which infamously cannot hold move-only objects, so we actually need something copyable. So grasp the nettle and implement a SlotObjSharedPtr. I was originally planning to just make this a typedef for QIntrusiveSharedPointer, but that's not in dev, yet, let alone 6.5, to which we're picking this, and there was always this nagging impedance mismatch between the QIntrusiveSharedPointer behavior, inherited from it's Q(Explicitly)SharedPointer roots, on the one hand, to always ref() in the constructor from raw pointer, and, OTOH, QSlotObjectBase starting its life with a ref-count of one (1) (not zero (0), like QSharedData). I eventually found the (elegant, if I may say so myself) solution to just not provide a constructor from raw pointer, only one from SlotObjUniquePtr, which, granted, has the same issue, but which is, by now, probably, hopefully, more fully grasped by QtCore regulars, and so we can piggy-back on that for SlotObjSharedPtr's constructor semantics. Add a comment nevertheless. Inside the lambda, we could theoretically move the slotObj into QMetaCallEvent::create(), after adding such conversion to SlotObjSharedPtr, but that would require making the lambda mutable, and seeing as it's stored in a std::function and copied around, I was not ready to make that change just yet. As a drive-by, make PermissionReceiver's constructor explicit. Pick-to: 6.6 6.5 Fixes: QTBUG-115330 Change-Id: I4e0cec13d19a19eeec31e4101ce289d07c92ce46 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
902063628f
commit
f141108887
@ -2876,12 +2876,13 @@ Qt::PermissionStatus QCoreApplication::checkPermission(const QPermission &permis
|
||||
|
||||
Called by the various requestPermission overloads to perform the request.
|
||||
|
||||
Calls the functor encapsulated in the \a slotObj in the given \a context
|
||||
Calls the functor encapsulated in the \a slotObjRaw in the given \a context
|
||||
(which may be \c nullptr).
|
||||
*/
|
||||
void QCoreApplication::requestPermission(const QPermission &requestedPermission,
|
||||
QtPrivate::QSlotObjectBase *slotObj, const QObject *context)
|
||||
QtPrivate::QSlotObjectBase *slotObjRaw, const QObject *context)
|
||||
{
|
||||
QtPrivate::SlotObjSharedPtr slotObj(QtPrivate::SlotObjUniquePtr{slotObjRaw}); // adopts
|
||||
if (QThread::currentThread() != QCoreApplicationPrivate::mainThread()) {
|
||||
qWarning(lcPermissions, "Permissions can only be requested from the GUI (main) thread");
|
||||
return;
|
||||
@ -2903,7 +2904,7 @@ void QCoreApplication::requestPermission(const QPermission &requestedPermission,
|
||||
class PermissionReceiver : public QObject
|
||||
{
|
||||
public:
|
||||
PermissionReceiver(QtPrivate::QSlotObjectBase *slotObject, const QObject *context)
|
||||
explicit PermissionReceiver(const QtPrivate::SlotObjSharedPtr &slotObject, const QObject *context)
|
||||
: slotObject(slotObject), context(context)
|
||||
{}
|
||||
|
||||
@ -2916,7 +2917,6 @@ void QCoreApplication::requestPermission(const QPermission &requestedPermission,
|
||||
// only execute if context object is still alive
|
||||
if (context)
|
||||
slotObject->call(const_cast<QObject*>(context.data()), metaCallEvent->args());
|
||||
slotObject->destroyIfLastRef();
|
||||
deleteLater();
|
||||
|
||||
return true;
|
||||
@ -2925,7 +2925,7 @@ void QCoreApplication::requestPermission(const QPermission &requestedPermission,
|
||||
return QObject::event(event);
|
||||
}
|
||||
private:
|
||||
QtPrivate::QSlotObjectBase *slotObject;
|
||||
QtPrivate::SlotObjSharedPtr slotObject;
|
||||
QPointer<const QObject> context;
|
||||
};
|
||||
PermissionReceiver *receiver = nullptr;
|
||||
@ -2945,7 +2945,7 @@ void QCoreApplication::requestPermission(const QPermission &requestedPermission,
|
||||
permission.m_status = status;
|
||||
|
||||
if (receiver) {
|
||||
auto metaCallEvent = QMetaCallEvent::create(slotObj, qApp,
|
||||
auto metaCallEvent = QMetaCallEvent::create(slotObj.get(), qApp,
|
||||
PermissionReceivedID, permission);
|
||||
qApp->postEvent(receiver, metaCallEvent);
|
||||
} else {
|
||||
@ -2953,9 +2953,6 @@ void QCoreApplication::requestPermission(const QPermission &requestedPermission,
|
||||
slotObj->call(const_cast<QObject*>(context), argv);
|
||||
}
|
||||
}
|
||||
|
||||
if (!receiver)
|
||||
slotObj->destroyIfLastRef();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -453,6 +453,39 @@ namespace QtPrivate {
|
||||
using SlotObjUniquePtr = std::unique_ptr<QSlotObjectBase,
|
||||
QSlotObjectBase::Deleter>;
|
||||
|
||||
class SlotObjSharedPtr {
|
||||
SlotObjUniquePtr obj;
|
||||
public:
|
||||
Q_NODISCARD_CTOR Q_IMPLICIT SlotObjSharedPtr() noexcept = default;
|
||||
Q_NODISCARD_CTOR Q_IMPLICIT SlotObjSharedPtr(std::nullptr_t) noexcept : SlotObjSharedPtr() {}
|
||||
Q_NODISCARD_CTOR explicit SlotObjSharedPtr(SlotObjUniquePtr o)
|
||||
: obj(std::move(o))
|
||||
{
|
||||
// does NOT ref() (takes unique_ptr by value)
|
||||
// (that's why (QSlotObjectBase*) ctor doesn't exisit: don't know whether that one _should_)
|
||||
}
|
||||
Q_NODISCARD_CTOR SlotObjSharedPtr(const SlotObjSharedPtr &other) noexcept
|
||||
: obj(other.obj.get())
|
||||
{
|
||||
if (obj)
|
||||
obj->ref();
|
||||
}
|
||||
SlotObjSharedPtr &operator=(const SlotObjSharedPtr &other) noexcept
|
||||
{ auto copy = other; swap(copy); return *this; }
|
||||
|
||||
Q_NODISCARD_CTOR SlotObjSharedPtr(SlotObjSharedPtr &&other) noexcept = default;
|
||||
SlotObjSharedPtr &operator=(SlotObjSharedPtr &&other) noexcept = default;
|
||||
~SlotObjSharedPtr() = default;
|
||||
|
||||
void swap(SlotObjSharedPtr &other) noexcept { obj.swap(other.obj); }
|
||||
|
||||
auto get() const noexcept { return obj.get(); }
|
||||
auto operator->() const noexcept { return get(); }
|
||||
|
||||
explicit operator bool() const noexcept { return bool(obj); }
|
||||
};
|
||||
|
||||
|
||||
// Implementation of QSlotObjectBase for which the slot is a callable (function, PMF, functor, or lambda).
|
||||
// Args and R are the List of arguments and the return type of the signal to which the slot is connected.
|
||||
template <typename Func, typename Args, typename R>
|
||||
|
Loading…
Reference in New Issue
Block a user