#include <stdio.h>
#include <stdlib.h>
-QPointer<Client> Client::instanceptr = 0;
-
-/*** Initialization/destruction ***/
-
-bool Client::instanceExists()
-{
- return instanceptr;
-}
-
-
-Client *Client::instance()
-{
- if (!instanceptr)
- instanceptr = new Client();
- return instanceptr;
-}
-
-
-void Client::destroy()
-{
- if (instanceptr) {
- delete instanceptr->mainUi();
- instanceptr->deleteLater();
- instanceptr = 0;
- }
-}
-
-
-void Client::init(AbstractUi *ui)
-{
- instance()->_mainUi = ui;
- instance()->init();
-}
-
-
-Client::Client(QObject *parent)
- : QObject(parent),
+Client::Client(std::unique_ptr<AbstractUi> ui, QObject *parent)
+ : QObject(parent), Singleton<Client>(this),
_signalProxy(new SignalProxy(SignalProxy::Client, this)),
- _mainUi(0),
- _networkModel(0),
- _bufferModel(0),
+ _mainUi(std::move(ui)),
+ _networkModel(new NetworkModel(this)),
+ _bufferModel(new BufferModel(_networkModel)),
_bufferSyncer(0),
_aliasManager(0),
_backlogManager(new ClientBacklogManager(this)),
_coreInfo(new CoreInfo(this)),
_dccConfig(0),
_ircListHelper(new ClientIrcListHelper(this)),
- _inputHandler(0),
+ _inputHandler(new ClientUserInputHandler(this)),
_networkConfig(0),
_ignoreListManager(0),
_highlightRuleManager(0),
_transferManager(0),
_transferModel(new TransferModel(this)),
- _messageModel(0),
- _messageProcessor(0),
+ _messageModel(_mainUi->createMessageModel(this)),
+ _messageProcessor(_mainUi->createMessageProcessor(this)),
_coreAccountModel(new CoreAccountModel(this)),
_coreConnection(new CoreConnection(this)),
_connected(false)
{
- _signalProxy->synchronize(_ircListHelper);
-}
-
-
-Client::~Client()
-{
- disconnectFromCore();
-}
-
-
-void Client::init()
-{
- _networkModel = new NetworkModel(this);
+ //connect(mainUi(), SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &)));
+ connect(mainUi(), SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore()));
+ connect(this, SIGNAL(connected()), mainUi(), SLOT(connectedToCore()));
+ connect(this, SIGNAL(disconnected()), mainUi(), SLOT(disconnectedFromCore()));
- connect(this, SIGNAL(networkRemoved(NetworkId)),
- _networkModel, SLOT(networkRemoved(NetworkId)));
+ connect(this, SIGNAL(networkRemoved(NetworkId)), _networkModel, SLOT(networkRemoved(NetworkId)));
+ connect(this, SIGNAL(networkRemoved(NetworkId)), _messageProcessor, SLOT(networkRemoved(NetworkId)));
- _bufferModel = new BufferModel(_networkModel);
- _messageModel = mainUi()->createMessageModel(this);
- _messageProcessor = mainUi()->createMessageProcessor(this);
- _inputHandler = new ClientUserInputHandler(this);
+ connect(backlogManager(), SIGNAL(messagesReceived(BufferId, int)), _messageModel, SLOT(messagesReceived(BufferId, int)));
+ connect(coreConnection(), SIGNAL(stateChanged(CoreConnection::ConnectionState)), SLOT(connectionStateChanged(CoreConnection::ConnectionState)));
SignalProxy *p = signalProxy();
p->attachSignal(this, SIGNAL(requestKickClient(int)), SIGNAL(kickClient(int)));
p->attachSlot(SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore()));
- //connect(mainUi(), SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &)));
- connect(mainUi(), SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore()));
- connect(this, SIGNAL(connected()), mainUi(), SLOT(connectedToCore()));
- connect(this, SIGNAL(disconnected()), mainUi(), SLOT(disconnectedFromCore()));
-
- // Listen to network removed events
- connect(this, SIGNAL(networkRemoved(NetworkId)),
- _messageProcessor, SLOT(networkRemoved(NetworkId)));
-
- // attach backlog manager
p->synchronize(backlogManager());
- connect(backlogManager(), SIGNAL(messagesReceived(BufferId, int)), _messageModel, SLOT(messagesReceived(BufferId, int)));
-
- coreAccountModel()->load();
-
- // Attach CoreInfo
p->synchronize(coreInfo());
+ p->synchronize(_ircListHelper);
- connect(coreConnection(), SIGNAL(stateChanged(CoreConnection::ConnectionState)), SLOT(connectionStateChanged(CoreConnection::ConnectionState)));
+ coreAccountModel()->load();
coreConnection()->init();
}
-/*** public static methods ***/
+Client::~Client()
+{
+ disconnectFromCore();
+}
+
AbstractUi *Client::mainUi()
{
- return instance()->_mainUi;
+ return instance()->_mainUi.get();
}
#pragma once
+#include <memory>
+
#include <QList>
#include <QPointer>
#include "coreconnection.h"
#include "highlightrulemanager.h"
#include "quassel.h"
+#include "singleton.h"
#include "types.h"
class Message;
struct NetworkInfo;
-class Client : public QObject
+class Client : public QObject, public Singleton<Client>
{
Q_OBJECT
RemoteCore
};
- static bool instanceExists();
- static Client *instance();
- static void destroy();
- static void init(AbstractUi *);
+ Client(std::unique_ptr<AbstractUi>, QObject *parent = nullptr);
+ ~Client() override;
+
static AbstractUi *mainUi();
static QList<NetworkId> networkIds();
void sendBufferedUserInput();
private:
- Client(QObject *parent = 0);
- virtual ~Client();
- void init();
-
void requestInitialBacklog();
/**
static void addNetwork(Network *);
- static QPointer<Client> instanceptr;
-
SignalProxy *_signalProxy;
- AbstractUi *_mainUi;
+ std::unique_ptr<AbstractUi> _mainUi;
NetworkModel *_networkModel;
BufferModel *_bufferModel;
BufferSyncer *_bufferSyncer;
// restore locked state of docks
QtUi::actionCollection("General")->action("LockLayout")->setChecked(s.value("LockLayout", false).toBool());
- QTimer::singleShot(0, this, SLOT(doAutoConnect()));
-}
-
-
-MainWin::~MainWin()
-{
-}
+ Quassel::registerQuitHandler([this]() {
+ QtUiSettings s;
+ saveStateToSettings(s);
+ saveLayout();
+ // Close all open dialogs and the MainWin, so we can safely kill the Client instance afterwards
+ // Note: This does not quit the application, as quitOnLastWindowClosed is set to false.
+ // We rely on another quit handler to be registered that actually quits the application.
+ qApp->closeAllWindows();
+ });
-
-void MainWin::quit()
-{
- QtUiSettings s;
- saveStateToSettings(s);
- saveLayout();
- QApplication::quit();
+ QTimer::singleShot(0, this, SLOT(doAutoConnect()));
}
//
// See https://doc.qt.io/qt-5/qkeysequence.html
coll->addAction("Quit", new Action(icon::get("application-exit"), tr("&Quit"), coll,
- this, SLOT(quit()), Qt::CTRL + Qt::Key_Q));
+ Quassel::instance(), SLOT(quit()), Qt::CTRL + Qt::Key_Q));
// View
coll->addAction("ConfigureBufferViews", new Action(tr("&Configure Chat Lists..."), coll,
else if(!_aboutToQuit) {
_aboutToQuit = true;
event->accept();
- quit();
+ Quassel::instance()->quit();
}
else {
event->ignore();
public:
MainWin(QWidget *parent = 0);
- virtual ~MainWin();
void init();
void onExitRequested(const QString &reason);
- //! Quit application
- void quit();
-
protected:
void closeEvent(QCloseEvent *event);
void moveEvent(QMoveEvent *event);
}
-MonolithicApplication::~MonolithicApplication()
+Quassel::QuitHandler MonolithicApplication::quitHandler()
{
- // Client needs to be destroyed first
- Client::destroy();
- _coreThread.quit();
- _coreThread.wait();
+ return [this]() {
+ connect(_client.get(), SIGNAL(destroyed()), this, SLOT(onClientDestroyed()));
+ _client.release()->deleteLater();
+ };
+}
+
+
+void MonolithicApplication::onClientDestroyed()
+{
+ if (_core) {
+ connect(_core, SIGNAL(destroyed()), QCoreApplication::instance(), SLOT(quit()));
+ _coreThread.quit();
+ _coreThread.wait();
+ }
+ else {
+ QCoreApplication::quit();
+ }
}
public:
MonolithicApplication(int &, char **);
- ~MonolithicApplication() override;
void init() override;
+protected:
+ Quassel::QuitHandler quitHandler() override;
+
signals:
void connectInternalPeer(QPointer<InternalPeer> peer);
private slots:
void onConnectionRequest(QPointer<InternalPeer> peer);
+ void onClientDestroyed();
private:
void startInternalCore();
#include "types.h"
#include "util.h"
-MainWin *QtUi::_mainWin = nullptr;
QList<AbstractNotificationBackend *> QtUi::_notificationBackends;
QList<AbstractNotificationBackend::Notification> QtUi::_notifications;
-namespace {
-
-QtUi *_instance{nullptr};
-
-}
-
QtUi *QtUi::instance()
{
- if (!_instance) {
- _instance = new QtUi();
- }
- return _instance;
+ return static_cast<QtUi*>(GraphicalUi::instance());
}
: GraphicalUi()
, _systemIconTheme{QIcon::themeName()}
{
+ QtUiSettings uiSettings;
+ Quassel::loadTranslation(uiSettings.value("Locale", QLocale::system()).value<QLocale>());
+
if (Quassel::isOptionSet("icontheme")) {
_systemIconTheme = Quassel::optionValue("icontheme");
QIcon::setThemeName(_systemIconTheme);
}
-
- QtUiSettings uiSettings;
- Quassel::loadTranslation(uiSettings.value("Locale", QLocale::system()).value<QLocale>());
-
setupIconTheme();
-
QApplication::setWindowIcon(icon::get("quassel"));
- setContextMenuActionProvider(new ContextMenuActionProvider(this));
- setToolBarActionProvider(new ToolBarActionProvider(this));
-
setUiStyle(new QtUiStyle(this));
- _mainWin = new MainWin();
-
- setMainWidget(_mainWin);
-
- connect(_mainWin, SIGNAL(connectToCore(const QVariantMap &)), this, SIGNAL(connectToCore(const QVariantMap &)));
- connect(_mainWin, SIGNAL(disconnectFromCore()), this, SIGNAL(disconnectFromCore()));
- connect(Client::instance(), SIGNAL(bufferMarkedAsRead(BufferId)), SLOT(closeNotifications(BufferId)));
}
QtUi::~QtUi()
{
unregisterAllNotificationBackends();
- delete _mainWin;
- _mainWin = nullptr;
- _instance = nullptr;
}
void QtUi::init()
{
+ setContextMenuActionProvider(new ContextMenuActionProvider(this));
+ setToolBarActionProvider(new ToolBarActionProvider(this));
+
+ _mainWin.reset(new MainWin()); // TODO C++14: std::make_unique
+ setMainWidget(_mainWin.get());
+
+ connect(_mainWin.get(), SIGNAL(connectToCore(const QVariantMap &)), this, SIGNAL(connectToCore(const QVariantMap &)));
+ connect(_mainWin.get(), SIGNAL(disconnectFromCore()), this, SIGNAL(disconnectFromCore()));
+ connect(Client::instance(), SIGNAL(bufferMarkedAsRead(BufferId)), SLOT(closeNotifications(BufferId)));
+
_mainWin->init();
+
QtUiSettings uiSettings;
uiSettings.initAndNotify("UseSystemTrayIcon", this, SLOT(useSystemTrayChanged(QVariant)), true);
Q_OBJECT
public:
- ~QtUi();
+ QtUi();
+ ~QtUi() override;
MessageModel *createMessageModel(QObject *parent) override;
AbstractMessageProcessor *createMessageProcessor(QObject *parent) override;
void useSystemTrayChanged(const QVariant &);
private:
- QtUi();
-
/**
* Sets up icon theme handling.
*/
void setupIconTheme();
private:
- static MainWin *_mainWin;
static QList<AbstractNotificationBackend *> _notificationBackends;
static QList<AbstractNotificationBackend::Notification> _notifications;
+ std::unique_ptr<MainWin> _mainWin;
+
QString _systemIconTheme;
#if QT_VERSION >= 0x050000
};
QtUiStyle *QtUi::style() { return qobject_cast<QtUiStyle *>(uiStyle()); }
-MainWin *QtUi::mainWindow() { return _mainWin; }
+MainWin *QtUi::mainWindow() { return instance()->_mainWin.get(); }
#endif
#include "chatviewsettings.h"
-#include "client.h"
#include "cliparser.h"
#include "mainwin.h"
#include "qtui.h"
throw ExitException{EXIT_FAILURE, tr("Could not load or upgrade client settings!")};
}
- Client::init(QtUi::instance());
+ _client.reset(new Client(std::unique_ptr<QtUi>(new QtUi()))); // TODO C++14: std::make_unique
// Init UI only after the event loop has started
// TODO Qt5: Make this a lambda
QTimer::singleShot(0, this, SLOT(initUi()));
-
- Quassel::registerQuitHandler([]() {
- QtUi::mainWindow()->quit();
- });
}
-QtUiApplication::~QtUiApplication()
+void QtUiApplication::initUi()
{
- Client::destroy();
+ QtUi::instance()->init();
+
+ // Needs to happen after UI init, so the MainWin quit handler is registered first
+ Quassel::registerQuitHandler(quitHandler());
+
+ resumeSessionIfPossible();
}
-void QtUiApplication::initUi()
+Quassel::QuitHandler QtUiApplication::quitHandler()
{
- QtUi::instance()->init();
- resumeSessionIfPossible();
+ // Wait until the Client instance is destroyed before quitting the event loop
+ return [this]() {
+ connect(_client.get(), SIGNAL(destroyed()), QCoreApplication::instance(), SLOT(quit()));
+ _client.release()->deleteLater();
+ };
}
#pragma once
+#include <memory>
+
#ifdef HAVE_KDE4
# include <KApplication>
#else
#include <QSessionManager>
+#include "client.h"
#include "quassel.h"
#include "uisettings.h"
#include "qtuisettings.h"
public:
QtUiApplication(int &, char **);
- ~QtUiApplication();
+
virtual void init();
void resumeSessionIfPossible();
void saveState(QSessionManager &manager);
#endif
+protected:
+ virtual Quassel::QuitHandler quitHandler();
+
private:
/**
* Migrate settings if neccessary and possible
private slots:
void initUi();
+protected:
+ std::unique_ptr<Client> _client;
+
private:
bool _aboutToQuit{false};
};
UiStyle *GraphicalUi::_uiStyle = 0;
bool GraphicalUi::_onAllDesktops = false;
-namespace {
-GraphicalUi *_instance{nullptr};
-
-}
-
-
-GraphicalUi *GraphicalUi::instance() {
- return _instance;
-}
-
-
-GraphicalUi::GraphicalUi(QObject *parent) : AbstractUi(parent)
+GraphicalUi::GraphicalUi(QObject *parent) : AbstractUi(parent), Singleton<GraphicalUi>(this)
{
- Q_ASSERT(!_instance);
- _instance = this;
-
#ifdef Q_OS_WIN
_dwTickCount = 0;
#endif
#define GRAPHICALUI_H_
#include "abstractui.h"
+#include "singleton.h"
class ActionCollection;
class ContextMenuActionProvider;
#include <Carbon/Carbon.h>
#endif
-class GraphicalUi : public AbstractUi
+class GraphicalUi : public AbstractUi, protected Singleton<GraphicalUi>
{
Q_OBJECT
virtual void disconnectedFromCore();
private:
- static GraphicalUi *instance();
-
static QWidget *_mainWidget;
static QHash<QString, ActionCollection *> _actionCollections;
static ContextMenuActionProvider *_contextMenuActionProvider;