Fix segfault when leaving certain rooms.

square-messages
Black Hat 2018-11-07 16:29:24 +08:00
parent 6e44347efd
commit 06983a506c
12 changed files with 74 additions and 86 deletions

View File

@ -24,7 +24,7 @@ class AccountListModel : public QAbstractListModel {
void setController(Controller* value); void setController(Controller* value);
private: private:
Controller* m_controller; Controller* m_controller = nullptr;
QVector<Connection*> m_connections; QVector<Connection*> m_connections;
signals: signals:

View File

@ -40,13 +40,6 @@ Controller::Controller(QObject* parent)
QTimer::singleShot(0, this, SLOT(invokeLogin())); QTimer::singleShot(0, this, SLOT(invokeLogin()));
} }
Controller::~Controller() {
for (auto c : qAsConst(m_connections)) {
c->saveState();
c->stopSync();
}
}
inline QString accessTokenFileName(const AccountSettings& account) { inline QString accessTokenFileName(const AccountSettings& account) {
QString fileName = account.userId(); QString fileName = account.userId();
fileName.replace(':', '_'); fileName.replace(':', '_');
@ -109,7 +102,10 @@ void Controller::addConnection(Connection* c) {
m_connections.push_back(c); m_connections.push_back(c);
connect(c, &Connection::syncDone, this, [=] { c->sync(30000); }); connect(c, &Connection::syncDone, this, [=] {
c->saveState();
c->sync(30000);
});
connect(c, &Connection::loggedOut, this, [=] { dropConnection(c); }); connect(c, &Connection::loggedOut, this, [=] { dropConnection(c); });
using namespace QMatrixClient; using namespace QMatrixClient;

View File

@ -23,7 +23,7 @@ class Controller : public QObject {
public: public:
explicit Controller(QObject* parent = nullptr); explicit Controller(QObject* parent = nullptr);
~Controller(); ~Controller(){};
// All the Q_INVOKABLEs. // All the Q_INVOKABLEs.
Q_INVOKABLE void loginWithCredentials(QString, QString, QString); Q_INVOKABLE void loginWithCredentials(QString, QString, QString);

View File

@ -6,7 +6,7 @@
ImageItem::ImageItem(QQuickItem *parent) : QQuickPaintedItem(parent) {} ImageItem::ImageItem(QQuickItem *parent) : QQuickPaintedItem(parent) {}
inline QString stringtoColor(QString string) { inline static QString stringtoColor(QString string) {
int hash = 0; int hash = 0;
for (int i = 0; i < string.length(); i++) for (int i = 0; i < string.length(); i++)
hash = string.at(i).unicode() + ((hash << 5) - hash); hash = string.at(i).unicode() + ((hash << 5) - hash);
@ -16,68 +16,64 @@ inline QString stringtoColor(QString string) {
return colour; return colour;
} }
inline static QImage getImageFromPaintable(QPointer<Paintable> p, QRectF b) {
if (p.isNull()) return {};
QImage image(p->image(int(b.width()), int(b.height())));
if (image.isNull()) return {};
return image;
}
void ImageItem::paint(QPainter *painter) { void ImageItem::paint(QPainter *painter) {
QRectF bounding_rect = boundingRect(); QRectF bounding_rect = boundingRect();
painter->setRenderHint(QPainter::Antialiasing, true); painter->setRenderHint(QPainter::Antialiasing, true);
if (!m_paintable) { QImage image(getImageFromPaintable(m_paintable, bounding_rect));
paintHint(painter, bounding_rect);
return;
}
QImage image = m_paintable->image(int(bounding_rect.width()),
int(bounding_rect.height()));
if (image.isNull()) { if (image.isNull()) {
paintHint(painter, bounding_rect); painter->setPen(Qt::NoPen);
return; if (m_color.isEmpty())
painter->setBrush(QColor(stringtoColor(m_hint)));
else
painter->setBrush(QColor(m_color));
if (m_round)
painter->drawEllipse(0, 0, int(bounding_rect.width()),
int(bounding_rect.height()));
else
painter->drawRect(0, 0, int(bounding_rect.width()),
int(bounding_rect.height()));
painter->setPen(QPen(Qt::white, 2));
QFont font;
font.setStyleHint(QFont::SansSerif);
font.setPixelSize(int(bounding_rect.width() / 2));
font.setBold(true);
painter->setFont(font);
painter->drawText(
QRect(0, 0, int(bounding_rect.width()), int(bounding_rect.height())),
Qt::AlignCenter, m_hint.at(0).toUpper());
} else {
QImage scaled = image.scaled(
int(bounding_rect.width()) + 1, int(bounding_rect.height()) + 1,
Qt::KeepAspectRatioByExpanding, Qt::FastTransformation);
QPointF center = bounding_rect.center() - scaled.rect().center();
if (m_round) {
QPainterPath clip;
clip.addEllipse(
0, 0, bounding_rect.width(),
bounding_rect.height()); // this is the shape we want to clip to
painter->setClipPath(clip);
}
painter->drawImage(center, scaled);
} }
QImage scaled = image.scaled(
int(bounding_rect.width()) + 1, int(bounding_rect.height()) + 1,
Qt::KeepAspectRatioByExpanding, Qt::FastTransformation);
QPointF center = bounding_rect.center() - scaled.rect().center();
if (m_round) {
QPainterPath clip;
clip.addEllipse(
0, 0, bounding_rect.width(),
bounding_rect.height()); // this is the shape we want to clip to
painter->setClipPath(clip);
}
painter->drawImage(center, scaled);
}
void ImageItem::paintHint(QPainter *painter, QRectF bounding_rect) {
painter->setPen(Qt::NoPen);
if (m_color.isEmpty())
painter->setBrush(QColor(stringtoColor(m_hint)));
else
painter->setBrush(QColor(m_color));
if (m_round)
painter->drawEllipse(0, 0, int(bounding_rect.width()),
int(bounding_rect.height()));
else
painter->drawRect(0, 0, int(bounding_rect.width()),
int(bounding_rect.height()));
painter->setPen(QPen(Qt::white, 2));
QFont font;
font.setStyleHint(QFont::SansSerif);
font.setPixelSize(int(bounding_rect.width() / 2));
font.setBold(true);
painter->setFont(font);
painter->drawText(
QRect(0, 0, int(bounding_rect.width()), int(bounding_rect.height())),
Qt::AlignCenter, m_hint.at(0).toUpper());
} }
void ImageItem::setPaintable(Paintable *paintable) { void ImageItem::setPaintable(Paintable *paintable) {
if (!paintable) return; if (!paintable) return;
disconnect(m_paintable); if (!m_paintable.isNull()) m_paintable->disconnect(this);
m_paintable = paintable; m_paintable = paintable;
connect(m_paintable, &Paintable::paintableChanged, this, connect(m_paintable, &Paintable::paintableChanged, this,
[=] { this->update(); }); [=] { this->update(); });

View File

@ -1,6 +1,7 @@
#ifndef IMAGEITEM_H #ifndef IMAGEITEM_H
#define IMAGEITEM_H #define IMAGEITEM_H
#include <QPointer>
#include <QImage> #include <QImage>
#include <QObject> #include <QObject>
#include <QPainter> #include <QPainter>
@ -42,12 +43,10 @@ class ImageItem : public QQuickPaintedItem {
void roundChanged(); void roundChanged();
private: private:
Paintable* m_paintable = nullptr; QPointer<Paintable> m_paintable;
QString m_hint = "H"; QString m_hint = "H";
QString m_color; QString m_color;
bool m_round = true; bool m_round = true;
void paintHint(QPainter* painter, QRectF bounding_rect);
}; };
#endif // IMAGEITEM_H #endif // IMAGEITEM_H

View File

@ -32,7 +32,7 @@ class ImageProvider : public QObject, public QQuickImageProvider {
private: private:
QReadWriteLock m_lock; QReadWriteLock m_lock;
QMatrixClient::Connection* m_connection; QMatrixClient::Connection* m_connection = nullptr;
}; };
#endif // IMAGEPROVIDER_H #endif // IMAGEPROVIDER_H

View File

@ -23,9 +23,7 @@
using namespace QMatrixClient; using namespace QMatrixClient;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
#if defined(Q_OS_WIN)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QApplication app(argc, argv); QApplication app(argc, argv);

View File

@ -72,8 +72,6 @@ void RoomListModel::connectRoomSignals(SpectralRoom* room) {
[=] { unreadMessagesChanged(room); }); [=] { unreadMessagesChanged(room); });
connect(room, &Room::tagsChanged, this, [=] { refresh(room); }); connect(room, &Room::tagsChanged, this, [=] { refresh(room); });
connect(room, &Room::joinStateChanged, this, [=] { refresh(room); }); connect(room, &Room::joinStateChanged, this, [=] { refresh(room); });
connect(room, &Room::avatarChanged, this,
[=] { refresh(room, {PaintableRole}); });
connect(room, &Room::addedMessages, this, connect(room, &Room::addedMessages, this,
[=] { refresh(room, {LastEventRole}); }); [=] { refresh(room, {LastEventRole}); });
connect(room, &Room::aboutToAddNewMessages, this, connect(room, &Room::aboutToAddNewMessages, this,

View File

@ -16,7 +16,7 @@
SpectralRoom::SpectralRoom(Connection* connection, QString roomId, SpectralRoom::SpectralRoom(Connection* connection, QString roomId,
JoinState joinState) JoinState joinState)
: Room(connection, std::move(roomId), joinState) { : Room(connection, std::move(roomId), joinState), m_paintable(this) {
connect(this, &SpectralRoom::notificationCountChanged, this, connect(this, &SpectralRoom::notificationCountChanged, this,
&SpectralRoom::countChanged); &SpectralRoom::countChanged);
connect(this, &SpectralRoom::highlightCountChanged, this, connect(this, &SpectralRoom::highlightCountChanged, this,

View File

@ -6,6 +6,7 @@
#include "spectraluser.h" #include "spectraluser.h"
#include <QObject> #include <QObject>
#include <QPointer>
#include <QTimer> #include <QTimer>
using namespace QMatrixClient; using namespace QMatrixClient;
@ -18,16 +19,11 @@ class RoomPaintable : public Paintable {
} }
QImage image(int dimension) override { QImage image(int dimension) override {
if (!m_room) { if (!m_room) return QImage();
qDebug() << "Room is null";
return QImage();
}
return m_room->avatar(dimension); return m_room->avatar(dimension);
} }
QImage image(int width, int height) override { QImage image(int width, int height) override {
if (!m_room) { if (!m_room) return QImage();
return QImage();
}
return m_room->avatar(width, height); return m_room->avatar(width, height);
} }
@ -52,7 +48,7 @@ class SpectralRoom : public Room {
explicit SpectralRoom(Connection* connection, QString roomId, explicit SpectralRoom(Connection* connection, QString roomId,
JoinState joinState = {}); JoinState joinState = {});
Paintable* paintable() { return new RoomPaintable(this); } Paintable* paintable() { return &m_paintable; }
const QString& cachedInput() const { return m_cachedInput; } const QString& cachedInput() const { return m_cachedInput; }
void setCachedInput(const QString& input) { void setCachedInput(const QString& input) {
@ -110,7 +106,7 @@ class SpectralRoom : public Room {
bool m_hasFileUploading = false; bool m_hasFileUploading = false;
int m_fileUploadingProgress = 0; int m_fileUploadingProgress = 0;
bool m_busy; bool m_busy = false;
QString getMIME(const QUrl& fileUrl) const; QString getMIME(const QUrl& fileUrl) const;
void postFile(const QUrl& localFile, const QUrl& mxcUrl); void postFile(const QUrl& localFile, const QUrl& mxcUrl);
@ -137,6 +133,9 @@ class SpectralRoom : public Room {
void sendTypingNotification(bool isTyping); void sendTypingNotification(bool isTyping);
void sendReply(QString userId, QString eventId, QString replyContent, void sendReply(QString userId, QString eventId, QString replyContent,
QString sendContent); QString sendContent);
private:
RoomPaintable m_paintable;
}; };
#endif // SpectralRoom_H #endif // SpectralRoom_H

View File

@ -6,15 +6,14 @@
#include "user.h" #include "user.h"
#include <QObject> #include <QObject>
#include <QPointer>
using namespace QMatrixClient; using namespace QMatrixClient;
class UserPaintable : public Paintable { class UserPaintable : public Paintable {
Q_OBJECT Q_OBJECT
public: public:
UserPaintable(User* parent) : Paintable(parent), m_user(parent) { UserPaintable(User* parent) : Paintable(parent), m_user(parent) {}
connect(m_user, &User::avatarChanged, [=] { emit paintableChanged(); });
}
QImage image(int dimension) override { QImage image(int dimension) override {
if (!m_user) return QImage(); if (!m_user) return QImage();
@ -34,9 +33,12 @@ class SpectralUser : public User {
Q_PROPERTY(Paintable* paintable READ paintable CONSTANT) Q_PROPERTY(Paintable* paintable READ paintable CONSTANT)
public: public:
SpectralUser(QString userId, Connection* connection) SpectralUser(QString userId, Connection* connection)
: User(userId, connection) {} : User(userId, connection), m_paintable(this) {}
Paintable* paintable() { return new UserPaintable(this); } Paintable* paintable() { return &m_paintable; }
private:
UserPaintable m_paintable;
}; };
#endif // SpectralUser_H #endif // SpectralUser_H

View File

@ -18,9 +18,9 @@ void UserListModel::setRoom(QMatrixClient::Room* room) {
using namespace QMatrixClient; using namespace QMatrixClient;
beginResetModel(); beginResetModel();
if (m_currentRoom && m_currentRoom->connection()) { if (m_currentRoom) {
m_currentRoom->connection()->disconnect(this);
m_currentRoom->disconnect(this); m_currentRoom->disconnect(this);
// m_currentRoom->connection()->disconnect(this);
for (User* user : m_users) user->disconnect(this); for (User* user : m_users) user->disconnect(this);
m_users.clear(); m_users.clear();
} }