mirror-chatterino2/src/util/QObjectRef.hpp

85 lines
1.5 KiB
C++
Raw Normal View History

2019-08-13 16:39:22 +02:00
#pragma once
#include <QObject>
#include <type_traits>
2019-08-13 18:48:22 +02:00
namespace chatterino {
/// Holds a pointer to a QObject and resets it to nullptr if the QObject
/// gets destroyed.
template <typename T>
class QObjectRef
2019-08-13 16:39:22 +02:00
{
2019-08-13 18:48:22 +02:00
public:
QObjectRef()
2019-08-13 16:39:22 +02:00
{
2019-08-13 18:48:22 +02:00
static_assert(std::is_base_of_v<QObject, T>);
}
2019-08-13 16:39:22 +02:00
2019-08-13 18:48:22 +02:00
explicit QObjectRef(T *t)
{
static_assert(std::is_base_of_v<QObject, T>);
2019-08-13 16:39:22 +02:00
2019-08-13 18:48:22 +02:00
this->set(t);
}
2019-08-13 16:39:22 +02:00
QObjectRef(const QObjectRef &other)
{
this->set(other.t_);
}
2019-08-13 18:48:22 +02:00
~QObjectRef()
{
this->set(nullptr);
}
2019-08-13 16:39:22 +02:00
2019-08-13 18:48:22 +02:00
QObjectRef &operator=(T *t)
{
this->set(t);
2019-08-13 16:39:22 +02:00
2019-08-13 18:48:22 +02:00
return *this;
}
2019-08-13 16:39:22 +02:00
2019-08-13 18:48:22 +02:00
operator bool()
{
return t_;
}
T *operator->()
{
return t_;
}
2019-08-13 16:39:22 +02:00
2019-08-13 18:48:22 +02:00
T *get()
{
return t_;
}
private:
void set(T *other)
{
// old
if (this->conn_)
2019-08-13 16:39:22 +02:00
{
2019-08-13 18:48:22 +02:00
QObject::disconnect(this->conn_);
2019-08-13 16:39:22 +02:00
}
2019-08-13 18:48:22 +02:00
// new
if (other)
2019-08-13 16:39:22 +02:00
{
2020-08-15 19:46:18 +02:00
// the cast here should absolutely not be necessary, but gcc still requires it
this->conn_ =
QObject::connect((QObject *)other, &QObject::destroyed, qApp,
[this](QObject *) {
this->set(nullptr);
},
2020-08-15 19:46:18 +02:00
Qt::DirectConnection);
2019-08-13 16:39:22 +02:00
}
2019-08-13 18:48:22 +02:00
this->t_ = other;
}
2019-08-20 23:29:11 +02:00
std::atomic<T *> t_{};
2019-08-13 18:48:22 +02:00
QMetaObject::Connection conn_;
};
2019-08-13 16:39:22 +02:00
} // namespace chatterino