mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-21 13:48:08 +00:00
feat(src/app/App): calls/settings windows are now created in asynchronous calls
This commit is contained in:
parent
d3a54121e7
commit
4ba245d60d
5 changed files with 248 additions and 47 deletions
|
|
@ -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_
|
||||
|
|
|
|||
123
linphone-desktop/src/app/AsyncObjectBuilder.cpp
Normal file
123
linphone-desktop/src/app/AsyncObjectBuilder.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
71
linphone-desktop/src/app/AsyncObjectBuilder.hpp
Normal file
71
linphone-desktop/src/app/AsyncObjectBuilder.hpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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_
|
||||
Loading…
Add table
Reference in a new issue