mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-08-09 17:25:39 +02:00
mainapplication: add URI start option
+ Refactors some window management logic in LayoutManagar.qml. + Refactors app start to support both a minimized start and a start URI. The start URI should force visibility. + StartMinimized now starts the application in a closed-to-tray state, instead of a minimized state. + The close-to-tray feature now saves the previous windowed state. + InstanceManager handles URI transfer to secondary instances. This commit does not implement URI handling. The original implementation supported only calls via a user infohash as the URI parameter. A new and flexible protocol should be defined to support multiple Jami features. Gitlab: #655 Change-Id: I2c47028930e4e9d7ccca94d9362545df14b98160
This commit is contained in:
parent
f319c95485
commit
3db33c4f89
7 changed files with 148 additions and 50 deletions
|
@ -20,6 +20,8 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Enums 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
import "mainview/components"
|
||||
|
||||
|
@ -49,6 +51,73 @@ QtObject {
|
|||
}
|
||||
visibility = priv.windowedVisibility
|
||||
}
|
||||
appWindow.allowVisibleWindow = true
|
||||
}
|
||||
|
||||
// Start in a hidden state.
|
||||
function startMinimized(visibilitySetting) {
|
||||
// Save the loaded setting for when the app is restored.
|
||||
priv.windowedVisibility = visibilitySetting
|
||||
appWindow.allowVisibleWindow = false
|
||||
appWindow.hide();
|
||||
}
|
||||
|
||||
// Close to a hidden state.
|
||||
function closeToTray(visibilitySetting = undefined) {
|
||||
// Save the current visibility.
|
||||
priv.windowedVisibility = visibility
|
||||
appWindow.hide();
|
||||
}
|
||||
|
||||
// Save the window geometry and visibility settings.
|
||||
function saveWindowSettings() {
|
||||
var geometry = Qt.rect(appWindow.x, appWindow.y,
|
||||
appWindow.width, appWindow.height)
|
||||
AppSettingsManager.setValue(Settings.WindowGeometry, geometry)
|
||||
|
||||
// If closed-to-tray or minimized, save the cached windowedVisibility
|
||||
// value instead.
|
||||
if (isHidden) {
|
||||
AppSettingsManager.setValue(Settings.WindowState, priv.windowedVisibility)
|
||||
} else {
|
||||
AppSettingsManager.setValue(Settings.WindowState, visibility)
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the window geometry and visibility settings.
|
||||
function restoreWindowSettings() {
|
||||
var geometry = AppSettingsManager.getValue(Settings.WindowGeometry)
|
||||
|
||||
// Position.
|
||||
if (!isNaN(geometry.x) && !isNaN(geometry.y)) {
|
||||
appWindow.x = geometry.x
|
||||
appWindow.y = geometry.y
|
||||
}
|
||||
|
||||
// Dimensions.
|
||||
appWindow.width = geometry.width ?
|
||||
geometry.width :
|
||||
JamiTheme.mainViewPreferredWidth
|
||||
appWindow.height = geometry.height ?
|
||||
geometry.height :
|
||||
JamiTheme.mainViewPreferredHeight
|
||||
appWindow.minimumWidth = JamiTheme.mainViewMinWidth
|
||||
appWindow.minimumHeight = JamiTheme.mainViewMinHeight
|
||||
|
||||
// State.
|
||||
const visibilityStr = AppSettingsManager.getValue(Settings.WindowState)
|
||||
var visibilitySetting = parseInt(visibilityStr)
|
||||
|
||||
// We should never restore a hidden state here. Default to normal
|
||||
// windowed state in such a case. This shouldn't happen.
|
||||
if (visibilitySetting === Window.Hidden) {
|
||||
visibilitySetting = Window.Windowed
|
||||
}
|
||||
if (MainApplication.startMinimized) {
|
||||
startMinimized(visibilitySetting)
|
||||
} else {
|
||||
visibility = visibilitySetting
|
||||
}
|
||||
}
|
||||
|
||||
// Adds an item to the fullscreen item stack. Automatically puts
|
||||
|
|
|
@ -53,6 +53,7 @@ ApplicationWindow {
|
|||
}
|
||||
|
||||
property bool windowSettingsLoaded: false
|
||||
property bool allowVisibleWindow: true
|
||||
|
||||
function checkLoadedSource() {
|
||||
var sourceString = mainApplicationLoader.source.toString()
|
||||
|
@ -83,19 +84,18 @@ ApplicationWindow {
|
|||
if (force || !UtilsAdapter.getAppValue(Settings.MinimizeOnClose) ||
|
||||
!UtilsAdapter.getAccountListSize()) {
|
||||
// Save the window geometry and state before quitting.
|
||||
var geometry = Qt.rect(appWindow.x, appWindow.y,
|
||||
appWindow.width, appWindow.height)
|
||||
AppSettingsManager.setValue(Settings.WindowGeometry, geometry)
|
||||
AppSettingsManager.setValue(Settings.WindowState, appWindow.visibility)
|
||||
layoutManager.saveWindowSettings()
|
||||
Qt.quit()
|
||||
} else {
|
||||
hide()
|
||||
layoutManager.closeToTray()
|
||||
}
|
||||
}
|
||||
|
||||
title: JamiStrings.appTitle
|
||||
|
||||
visible: mainApplicationLoader.status === Loader.Ready && windowSettingsLoaded
|
||||
visible: mainApplicationLoader.status === Loader.Ready
|
||||
&& windowSettingsLoaded
|
||||
&& allowVisibleWindow
|
||||
|
||||
// To facilitate reparenting of the callview during
|
||||
// fullscreen mode, we need QQuickItem based object.
|
||||
|
@ -134,38 +134,21 @@ ApplicationWindow {
|
|||
onSourceChanged: windowSettingsLoaded = false
|
||||
|
||||
onLoaded: {
|
||||
if (UtilsAdapter.getAppValue(Settings.StartMinimized)) {
|
||||
showMinimized()
|
||||
if (checkLoadedSource() === MainApplicationWindow.LoadedSource.WizardView) {
|
||||
// Onboarding wizard window, these settings are fixed.
|
||||
// - window screen should default to the primary
|
||||
// - position should default to being centered based on the
|
||||
// following dimensions
|
||||
// - the window will showNormal once windowSettingsLoaded is
|
||||
// set to true(then forcing visible to true)
|
||||
appWindow.width = JamiTheme.wizardViewMinWidth
|
||||
appWindow.height = JamiTheme.wizardViewMinHeight
|
||||
appWindow.minimumWidth = JamiTheme.wizardViewMinWidth
|
||||
appWindow.minimumHeight = JamiTheme.wizardViewMinHeight
|
||||
} else {
|
||||
if (checkLoadedSource() === MainApplicationWindow.LoadedSource.WizardView) {
|
||||
appWindow.width = JamiTheme.wizardViewMinWidth
|
||||
appWindow.height = JamiTheme.wizardViewMinHeight
|
||||
appWindow.minimumWidth = JamiTheme.wizardViewMinWidth
|
||||
appWindow.minimumHeight = JamiTheme.wizardViewMinHeight
|
||||
} else {
|
||||
// Main window, load settings if possible.
|
||||
var geometry = AppSettingsManager.getValue(Settings.WindowGeometry)
|
||||
|
||||
// Position.
|
||||
if (!isNaN(geometry.x) && !isNaN(geometry.y)) {
|
||||
appWindow.x = geometry.x
|
||||
appWindow.y = geometry.y
|
||||
}
|
||||
|
||||
// Dimensions.
|
||||
appWindow.width = geometry.width ?
|
||||
geometry.width :
|
||||
JamiTheme.mainViewPreferredWidth
|
||||
appWindow.height = geometry.height ?
|
||||
geometry.height :
|
||||
JamiTheme.mainViewPreferredHeight
|
||||
appWindow.minimumWidth = JamiTheme.mainViewMinWidth
|
||||
appWindow.minimumHeight = JamiTheme.mainViewMinHeight
|
||||
|
||||
// State.
|
||||
const visibilityStr = AppSettingsManager.getValue(Settings.WindowState)
|
||||
appWindow.visibility = parseInt(visibilityStr)
|
||||
}
|
||||
// Main window, load any valid app settings, and allow the
|
||||
// layoutManager to handle as much as possible.
|
||||
layoutManager.restoreWindowSettings()
|
||||
}
|
||||
|
||||
// This will trigger `visible = true`.
|
||||
|
@ -176,6 +159,9 @@ ApplicationWindow {
|
|||
UpdateManager.checkForUpdates(true)
|
||||
UpdateManager.setAutoUpdateCheck(true)
|
||||
}
|
||||
|
||||
// Handle a start URI if set as start option.
|
||||
MainApplication.handleUriAction();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,13 +52,20 @@ public:
|
|||
{}
|
||||
~Impl() = default;
|
||||
|
||||
bool tryToRun()
|
||||
bool tryToRun(const QByteArray& startUri)
|
||||
{
|
||||
if (isAnotherRunning()) {
|
||||
// This is a secondary instance,
|
||||
// connect to the primary instance to trigger a restore
|
||||
// then fail.
|
||||
// This is a secondary instance, connect to the primary
|
||||
// instance to trigger a restore then die.
|
||||
if (connectToLocal()) {
|
||||
// Okay we connected. Send the start uri if not empty.
|
||||
if (startUri.size()) {
|
||||
qDebug() << "Sending start URI to secondary instance." << startUri;
|
||||
socket_->write(startUri);
|
||||
socket_->waitForBytesWritten();
|
||||
}
|
||||
|
||||
// Now this instance can die.
|
||||
return false;
|
||||
}
|
||||
// If not connected, this means that the server doesn't exist
|
||||
|
@ -99,7 +106,7 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
socket_->write(reinterpret_cast<const char*>(terminateSeq_.data()), 4);
|
||||
socket_->write(terminateSeq_);
|
||||
socket_->waitForBytesWritten();
|
||||
};
|
||||
|
||||
|
@ -139,10 +146,15 @@ private Q_SLOTS:
|
|||
if (recievedData == terminateSeq_) {
|
||||
qWarning() << "Received terminate signal.";
|
||||
mainAppInstance_->quit();
|
||||
} else {
|
||||
qDebug() << "Received start URI:" << recievedData;
|
||||
auto startUri = QString::fromLatin1(recievedData);
|
||||
mainAppInstance_->handleUriAction(startUri);
|
||||
}
|
||||
});
|
||||
|
||||
// Restore primary instance
|
||||
qDebug() << "Received wake-up from secondary instance.";
|
||||
mainAppInstance_->restoreApp();
|
||||
};
|
||||
|
||||
|
@ -193,9 +205,9 @@ InstanceManager::~InstanceManager()
|
|||
}
|
||||
|
||||
bool
|
||||
InstanceManager::tryToRun()
|
||||
InstanceManager::tryToRun(const QByteArray& startUri)
|
||||
{
|
||||
return pimpl_->tryToRun();
|
||||
return pimpl_->tryToRun(startUri);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
explicit InstanceManager(MainApplication* mainApp);
|
||||
~InstanceManager();
|
||||
|
||||
bool tryToRun();
|
||||
bool tryToRun(const QByteArray& startUri);
|
||||
void tryToKill();
|
||||
|
||||
private:
|
||||
|
|
|
@ -106,9 +106,12 @@ main(int argc, char* argv[])
|
|||
qWarning() << "Attempting to terminate other instances.";
|
||||
im.tryToKill();
|
||||
return 0;
|
||||
} else if (!im.tryToRun()) {
|
||||
qWarning() << "Another instance is running.";
|
||||
return 0;
|
||||
} else {
|
||||
auto startUri = app.getOpt(MainApplication::Option::StartUri);
|
||||
if (!im.tryToRun(startUri.toByteArray())) {
|
||||
qWarning() << "Another instance is running.";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!app.init()) {
|
||||
|
|
|
@ -241,6 +241,10 @@ MainApplication::init()
|
|||
lrcInstance_->accountModel().autoTransferFromTrusted = allowTransferFromTrusted;
|
||||
lrcInstance_->accountModel().autoTransferSizeThreshold = acceptTransferBelow;
|
||||
|
||||
auto startMinimizedSetting = settingsManager_->getValue(Settings::Key::StartMinimized).toBool();
|
||||
// The presence of start URI should override the startMinimized setting for this instance.
|
||||
set_startMinimized(startMinimizedSetting && runOptions_[Option::StartUri].isNull());
|
||||
|
||||
initQmlLayer();
|
||||
|
||||
settingsManager_->setValue(Settings::Key::StartMinimized,
|
||||
|
@ -257,6 +261,20 @@ MainApplication::restoreApp()
|
|||
Q_EMIT lrcInstance_->restoreAppRequested();
|
||||
}
|
||||
|
||||
void
|
||||
MainApplication::handleUriAction(const QString& arg)
|
||||
{
|
||||
QString uri {};
|
||||
if (arg.isEmpty() && !runOptions_[Option::StartUri].isNull()) {
|
||||
uri = runOptions_[Option::StartUri].toString();
|
||||
qDebug() << "URI action invoked by run option" << uri;
|
||||
} else {
|
||||
uri = arg;
|
||||
qDebug() << "URI action invoked by secondary instance" << uri;
|
||||
}
|
||||
// TODO: implement URI protocol handling.
|
||||
}
|
||||
|
||||
void
|
||||
MainApplication::initLrc(const QString& downloadUrl, ConnectivityMonitor* cm, bool logDaemon)
|
||||
{
|
||||
|
@ -290,6 +308,13 @@ MainApplication::initLrc(const QString& downloadUrl, ConnectivityMonitor* cm, bo
|
|||
void
|
||||
MainApplication::parseArguments()
|
||||
{
|
||||
// See if the app is being started with a URI.
|
||||
for (const auto& arg : QApplication::arguments()) {
|
||||
if (arg.startsWith("jami:")) {
|
||||
runOptions_[Option::StartUri] = arg;
|
||||
}
|
||||
}
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
|
|
@ -58,7 +58,7 @@ class MainApplication : public QApplication
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(MainApplication)
|
||||
|
||||
QML_RO_PROPERTY(bool, startMinimized)
|
||||
public:
|
||||
explicit MainApplication(int& argc, char** argv);
|
||||
~MainApplication();
|
||||
|
@ -66,6 +66,8 @@ public:
|
|||
bool init();
|
||||
void restoreApp();
|
||||
|
||||
Q_INVOKABLE void handleUriAction(const QString& uri = {});
|
||||
|
||||
enum class Option {
|
||||
StartMinimized = 0,
|
||||
Debug,
|
||||
|
@ -73,7 +75,8 @@ public:
|
|||
DebugToFile,
|
||||
UpdateUrl,
|
||||
MuteJamid,
|
||||
TerminationRequested
|
||||
TerminationRequested,
|
||||
StartUri
|
||||
};
|
||||
QVariant getOpt(const Option opt)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue