Commit 4ba245d6 authored by Ronan Abhamon's avatar Ronan Abhamon

feat(src/app/App): calls/settings windows are now created in asynchronous calls

parent d3a54121
......@@ -78,6 +78,7 @@ endif()
set(SOURCES
src/app/App.cpp
src/app/AsyncObjectBuilder.cpp
src/app/AvatarProvider.cpp
src/app/DefaultTranslator.cpp
src/app/Logger.cpp
......@@ -111,6 +112,7 @@ set(SOURCES
set(HEADERS
src/app/App.hpp
src/app/AsyncObjectBuilder.hpp
src/app/AvatarProvider.hpp
src/app/DefaultTranslator.hpp
src/app/Logger.hpp
......
......@@ -157,27 +157,7 @@ void App::initContentApp () {
if (m_parser.isSet("selftest"))
QObject::connect(core, &CoreManager::linphoneCoreCreated, this, &App::quit);
else
QObject::connect(
core, &CoreManager::linphoneCoreCreated, this, [core, this]() {
tryToUsePreferredLocale();
qInfo() << QStringLiteral("Linphone core created.");
core->enableHandlers();
#ifndef __APPLE__
// Enable TrayIconSystem.
if (!QSystemTrayIcon::isSystemTrayAvailable())
qWarning("System tray not found on this system.");
else
setTrayIcon();
if (!m_parser.isSet("iconified"))
getMainWindow()->showNormal();
#else
getMainWindow()->showNormal();
#endif // ifndef __APPLE__
}
);
QObject::connect(core, &CoreManager::linphoneCoreCreated, this, &App::openAppAfterInit);
QObject::connect(
this, &App::receivedMessage, this, [this](int, QByteArray message) {
......@@ -238,11 +218,8 @@ void App::tryToUsePreferredLocale () {
// -----------------------------------------------------------------------------
QQuickWindow *App::getCallsWindow () {
if (!m_calls_window)
m_calls_window = createSubWindow(this, QML_VIEW_CALLS_WINDOW);
return m_calls_window;
QQuickWindow *App::getCallsWindow () const {
return qobject_cast<QQuickWindow *>(m_calls_window.getObject());
}
QQuickWindow *App::getMainWindow () const {
......@@ -251,28 +228,14 @@ QQuickWindow *App::getMainWindow () const {
);
}
QQuickWindow *App::getSettingsWindow () {
if (!m_settings_window) {
m_settings_window = createSubWindow(this, QML_VIEW_SETTINGS_WINDOW);
QObject::connect(
m_settings_window, &QWindow::visibilityChanged, this, [](QWindow::Visibility visibility) {
if (visibility == QWindow::Hidden) {
qInfo() << "Update nat policy.";
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
core->setNatPolicy(core->getNatPolicy());
}
}
);
}
return m_settings_window;
QQuickWindow *App::getSettingsWindow () const {
return qobject_cast<QQuickWindow *>(m_settings_window.getObject());
}
// -----------------------------------------------------------------------------
bool App::hasFocus () const {
return getMainWindow()->isActive() || (m_calls_window && m_calls_window->isActive());
return getMainWindow()->isActive() || (m_calls_window.isCreated() && getCallsWindow()->isActive());
}
// -----------------------------------------------------------------------------
......@@ -398,6 +361,45 @@ QString App::getLocale () const {
// -----------------------------------------------------------------------------
void App::openAppAfterInit () {
tryToUsePreferredLocale();
qInfo() << QStringLiteral("Linphone core created.");
CoreManager::getInstance()->enableHandlers();
#ifndef __APPLE__
// Enable TrayIconSystem.
if (!QSystemTrayIcon::isSystemTrayAvailable())
qWarning("System tray not found on this system.");
else
setTrayIcon();
if (!m_parser.isSet("iconified"))
getMainWindow()->showNormal();
#else
getMainWindow()->showNormal();
#endif // ifndef __APPLE__
m_calls_window.createObject(&m_engine, QML_VIEW_CALLS_WINDOW);
m_settings_window.createObject(
&m_engine, QML_VIEW_SETTINGS_WINDOW, [this](QObject *object) {
QQuickWindow *window = qobject_cast<QQuickWindow *>(object);
QObject::connect(
window, &QWindow::visibilityChanged, this, [](QWindow::Visibility visibility) {
if (visibility == QWindow::Hidden) {
qInfo() << "Update nat policy.";
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
core->setNatPolicy(core->getNatPolicy());
}
}
);
}
);
}
// -----------------------------------------------------------------------------
void App::quit () {
if (m_parser.isSet("selftest"))
cout << tr("selftestResult").toStdString() << endl;
......
......@@ -25,6 +25,7 @@
#include "../components/notifier/Notifier.hpp"
#include "../externals/single-application/SingleApplication.hpp"
#include "AsyncObjectBuilder.hpp"
#include <QCommandLineParser>
#include <QQmlApplicationEngine>
......@@ -58,12 +59,12 @@ public:
return m_notifier;
}
QQuickWindow *getCallsWindow ();
QQuickWindow *getCallsWindow () const;
QQuickWindow *getMainWindow () const;
bool hasFocus () const;
Q_INVOKABLE QQuickWindow *getSettingsWindow ();
Q_INVOKABLE QQuickWindow *getSettingsWindow () const;
static App *getInstance () {
return static_cast<App *>(QApplication::instance());
......@@ -88,6 +89,8 @@ private:
return m_available_locales;
}
void openAppAfterInit ();
QCommandLineParser m_parser;
QVariantList m_available_locales;
......@@ -98,8 +101,8 @@ private:
DefaultTranslator *m_translator = nullptr;
Notifier *m_notifier = nullptr;
QQuickWindow *m_calls_window = nullptr;
QQuickWindow *m_settings_window = nullptr;
AsyncObjectBuilder m_calls_window;
AsyncObjectBuilder m_settings_window;
};
#endif // APP_H_
/*
* AsyncObjectBuilder.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* 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 2
* of the License, or (at your option) 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: March 27, 2017
* Author: Ronan Abhamon
*/
#include <QCoreApplication>
#include <QDebug>
#include <QQmlIncubator>
#include "AsyncObjectBuilder.hpp"
using namespace std;
// =============================================================================
class AsyncObjectBuilder::ObjectIncubator : public QQmlIncubator {
public:
// FIXME: At this moment, asynchronous loading is unstable.
// Use `IncubationMode::Synchronous` instead in Qt 5.9.
//
// See: https://bugreports.qt.io/browse/QTBUG-49416 and
// https://bugreports.qt.io/browse/QTBUG-50992
ObjectIncubator (AsyncObjectBuilder *builder) : QQmlIncubator(IncubationMode::Synchronous) {
m_builder = builder;
}
protected:
void statusChanged (Status status) override {
if (status == Error) {
qWarning() << "ObjectIncubator failed to build component:" << errors();
abort();
}
if (status == Ready) {
QObject *object = QQmlIncubator::object();
QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
object->setParent(m_builder);
m_builder->m_is_created = true;
// Call user decorator.
if (m_builder->m_decorator)
m_builder->m_decorator(object);
qInfo() << QStringLiteral("Creation of component instance is successful:") << m_builder->m_component;
m_builder->m_object = object;
emit m_builder->objectCreated(object);
// Optimization: Delete unused component now.
m_builder->m_component->deleteLater();
// Optimization: Delete unused incubator.
m_builder->m_incubator = nullptr;
delete this; // Very courageous but works.
}
}
private:
AsyncObjectBuilder *m_builder;
};
// -----------------------------------------------------------------------------
AsyncObjectBuilder::AsyncObjectBuilder (QObject *parent) : QObject(parent) {}
AsyncObjectBuilder::~AsyncObjectBuilder () {
delete m_incubator;
}
void AsyncObjectBuilder::createObject (QQmlEngine *engine, const char *path, Decorator decorator) {
Q_ASSERT(!m_block_creation);
#ifdef QT_DEBUG
m_block_creation = true;
#endif // ifdef QT_DEBUG
m_component = new QQmlComponent(engine, QUrl(path), QQmlComponent::Asynchronous, this);
m_decorator = decorator;
qInfo() << QStringLiteral("Start async creation of: `%1`. Component:").arg(path) << m_component;
QObject::connect(m_component, &QQmlComponent::statusChanged, this, &AsyncObjectBuilder::handleComponentCreation);
}
QObject *AsyncObjectBuilder::getObject () const {
while (!m_object)
QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
return m_object;
}
void AsyncObjectBuilder::handleComponentCreation (QQmlComponent::Status status) {
if (status == QQmlComponent::Ready) {
qInfo() << QStringLiteral("Component built:") << m_component;
m_incubator = new ObjectIncubator(this);
qInfo() << QStringLiteral("Start creation of component instance:") << m_component;
m_component->create(*m_incubator);
} else if (status == QQmlComponent::Error) {
qWarning() << "AsyncObjectBuilder failed to build component:" << m_component->errors();
abort();
}
}
/*
* AsyncObjectBuilder.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* 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 2
* of the License, or (at your option) 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: March 27, 2017
* Author: Ronan Abhamon
*/
#ifndef ASYNC_OBJECT_BUILDER_H_
#define ASYNC_OBJECT_BUILDER_H_
#include <functional>
#include <QQmlEngine>
#include <QQmlComponent>
// =============================================================================
class AsyncObjectBuilder : public QObject {
Q_OBJECT;
class ObjectIncubator;
typedef std::function<void (QObject *)> Decorator;
public:
AsyncObjectBuilder (QObject *parent = Q_NULLPTR);
~AsyncObjectBuilder ();
void createObject (QQmlEngine *engine, const char *path, Decorator decorator = nullptr);
QObject *getObject () const;
bool isCreated () const {
return m_is_created;
}
signals:
void objectCreated (QObject *object);
private:
void handleComponentCreation (QQmlComponent::Status status);
ObjectIncubator *m_incubator = nullptr;
QQmlComponent *m_component = nullptr;
Decorator m_decorator;
QObject *m_object = nullptr;
bool m_is_created = false;
#ifdef QT_DEBUG
bool m_block_creation = false;
#endif // ifdef QT_DEBUG
};
#endif // ASYNC_OBJECT_BUILDER_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment