minimize to system tray (#1601)

This commit is contained in:
jachin 2020-12-19 16:18:25 +08:00 committed by GitHub
parent 44a11ce5bb
commit cb14461f58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 226 additions and 13 deletions

View File

@ -7,6 +7,7 @@ using namespace vnotex;
#define READSTR(key) readString(appObj, userObj, (key)) #define READSTR(key) readString(appObj, userObj, (key))
#define READINT(key) readInt(appObj, userObj, (key)) #define READINT(key) readInt(appObj, userObj, (key))
#define READBOOL(key) readBool(appObj, userObj, (key))
QStringList CoreConfig::s_availableLocales; QStringList CoreConfig::s_availableLocales;
@ -40,6 +41,10 @@ void CoreConfig::init(const QJsonObject &p_app,
if (m_toolBarIconSize <= 0) { if (m_toolBarIconSize <= 0) {
m_toolBarIconSize = 16; m_toolBarIconSize = 16;
} }
if (!isUndefinedKey(appObj, userObj, "minimize_to_system_tray")) {
m_minimizeToSystemTray = READBOOL(QStringLiteral("minimize_to_system_tray")) ? 1 : 0;
}
} }
QJsonObject CoreConfig::toJson() const QJsonObject CoreConfig::toJson() const
@ -49,6 +54,9 @@ QJsonObject CoreConfig::toJson() const
obj[QStringLiteral("locale")] = m_locale; obj[QStringLiteral("locale")] = m_locale;
obj[QStringLiteral("shortcuts")] = saveShortcuts(); obj[QStringLiteral("shortcuts")] = saveShortcuts();
obj[QStringLiteral("toolbar_icon_size")] = m_toolBarIconSize; obj[QStringLiteral("toolbar_icon_size")] = m_toolBarIconSize;
if (m_minimizeToSystemTray != -1) {
obj[QStringLiteral("minimize_to_system_tray")] = m_minimizeToSystemTray > 0;
}
return obj; return obj;
} }
@ -122,3 +130,11 @@ void CoreConfig::setToolBarIconSize(int p_size)
Q_ASSERT(p_size > 0); Q_ASSERT(p_size > 0);
updateConfig(m_toolBarIconSize, p_size, this); updateConfig(m_toolBarIconSize, p_size, this);
} }
int CoreConfig::getMinimizeToSystemTray() const {
return m_minimizeToSystemTray;
}
void CoreConfig::setMinimizeToSystemTray(bool state){
updateConfig(m_minimizeToSystemTray, int(state), this);
}

View File

@ -48,6 +48,9 @@ namespace vnotex
int getToolBarIconSize() const; int getToolBarIconSize() const;
void setToolBarIconSize(int p_size); void setToolBarIconSize(int p_size);
int getMinimizeToSystemTray() const;
void setMinimizeToSystemTray(bool state);
static const QStringList &getAvailableLocales(); static const QStringList &getAvailableLocales();
private: private:
@ -67,6 +70,12 @@ namespace vnotex
// Icon size of MainWindow tool bar. // Icon size of MainWindow tool bar.
int m_toolBarIconSize = 16; int m_toolBarIconSize = 16;
// Whether to minimize to tray.
// -1 for prompting for user;
// 0 for disabling minimizing to system tray;
// 1 for enabling minimizing to system tray;
int m_minimizeToSystemTray = -1;
static QStringList s_availableLocales; static QStringList s_availableLocales;
}; };
} // ns vnotex } // ns vnotex

View File

@ -131,6 +131,12 @@ int EditorConfig::getToolBarIconSize() const
return m_toolBarIconSize; return m_toolBarIconSize;
} }
void EditorConfig::setToolBarIconSize(int p_size)
{
Q_ASSERT(p_size > 0);
updateConfig(m_toolBarIconSize, p_size, this);
}
const QString &EditorConfig::getShortcut(Shortcut p_shortcut) const const QString &EditorConfig::getShortcut(Shortcut p_shortcut) const
{ {
Q_ASSERT(p_shortcut < Shortcut::MaxShortcut); Q_ASSERT(p_shortcut < Shortcut::MaxShortcut);

View File

@ -75,6 +75,7 @@ namespace vnotex
QJsonObject toJson() const Q_DECL_OVERRIDE; QJsonObject toJson() const Q_DECL_OVERRIDE;
int getToolBarIconSize() const; int getToolBarIconSize() const;
void setToolBarIconSize(int p_size);
EditorConfig::AutoSavePolicy getAutoSavePolicy() const; EditorConfig::AutoSavePolicy getAutoSavePolicy() const;
void setAutoSavePolicy(EditorConfig::AutoSavePolicy p_policy); void setAutoSavePolicy(EditorConfig::AutoSavePolicy p_policy);

View File

@ -126,6 +126,16 @@ namespace vnotex
return read(p_default, p_user, p_key).toDouble(); return read(p_default, p_user, p_key).toDouble();
} }
static bool isUndefinedKey(const QJsonObject &p_default,
const QJsonObject &p_user,
const QString &p_key)
{
if (p_user.find(p_key) == p_user.end() && p_default.find(p_key) == p_default.end()) {
return true;
}
return false;
}
template <typename T> template <typename T>
static void updateConfig(T &p_cur, static void updateConfig(T &p_cur,
const T &p_new, const T &p_new,

View File

@ -23,6 +23,8 @@ bool SingleInstanceGuard::tryRun()
// this will attach to the old segment, then exit, freeing the old segment. // this will attach to the old segment, then exit, freeing the old segment.
if (m_sharedMemory.attach()) { if (m_sharedMemory.attach()) {
qInfo() << "another instance is running"; qInfo() << "another instance is running";
// So try to show it?
showInstance();
return false; return false;
} }

View File

@ -1,6 +1,7 @@
#include "vnotex.h" #include "vnotex.h"
#include <QDateTime> #include <QDateTime>
#include <QRandomGenerator>
#include <widgets/mainwindow.h> #include <widgets/mainwindow.h>
#include "notebookmgr.h" #include "notebookmgr.h"
@ -12,6 +13,7 @@
#include <utils/docsutils.h> #include <utils/docsutils.h>
using namespace vnotex; using namespace vnotex;
VNoteX::VNoteX(QObject *p_parent) VNoteX::VNoteX(QObject *p_parent)
@ -19,9 +21,7 @@ VNoteX::VNoteX(QObject *p_parent)
m_mainWindow(nullptr), m_mainWindow(nullptr),
m_notebookMgr(nullptr) m_notebookMgr(nullptr)
{ {
qsrand(QDateTime::currentDateTime().toTime_t()); m_instanceId = QRandomGenerator::global()->generate64();
m_instanceId = qrand();
initThemeMgr(); initThemeMgr();

View File

@ -21,6 +21,7 @@
#include <core/exception.h> #include <core/exception.h>
#include <widgets/messageboxhelper.h> #include <widgets/messageboxhelper.h>
#include <QProcess>
using namespace vnotex; using namespace vnotex;
@ -119,7 +120,7 @@ int main(int argc, char *argv[])
loadTranslators(app); loadTranslators(app);
MainWindow window; MainWindow window(nullptr);
window.show(); window.show();
VNoteX::getInst().getThemeMgr().setBaseBackground(window.palette().color(QPalette::Base)); VNoteX::getInst().getThemeMgr().setBaseBackground(window.palette().color(QPalette::Base));
@ -127,6 +128,13 @@ int main(int argc, char *argv[])
window.kickOffOnStart(); window.kickOffOnStart();
int ret = app.exec(); int ret = app.exec();
if (ret == RESTART_EXIT_CODE) {
// Ask to restart VNote.
guard.exit();
QProcess::startDetached(qApp->applicationFilePath(), QStringList());
return 0;
}
return ret; return ret;
} }

View File

@ -5,6 +5,7 @@ equals(QT_MAJOR_VERSION, 5):lessThan(QT_MINOR_VERSION, 12): error("requires Qt 5
QT += core gui widgets webenginewidgets webchannel network svg printsupport QT += core gui widgets webenginewidgets webchannel network svg printsupport
CONFIG -= qtquickcompiler CONFIG -= qtquickcompiler
unix:!macx:CONFIG += use_gold_linker
# Enable message log in release build # Enable message log in release build
DEFINES += QT_MESSAGELOGCONTEXT DEFINES += QT_MESSAGELOGCONTEXT

View File

@ -3,6 +3,7 @@
#include <QComboBox> #include <QComboBox>
#include <QFormLayout> #include <QFormLayout>
#include <QTimer> #include <QTimer>
#include <QSpinBox>
#include <widgets/widgetsfactory.h> #include <widgets/widgetsfactory.h>
#include <core/editorconfig.h> #include <core/editorconfig.h>
@ -34,6 +35,21 @@ void EditorPage::setupUI()
connect(m_autoSavePolicyComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), connect(m_autoSavePolicyComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &EditorPage::pageIsChanged); this, &EditorPage::pageIsChanged);
} }
{
m_toolBarIconSizeSpinBox = WidgetsFactory::createSpinBox(this);
m_toolBarIconSizeSpinBox->setToolTip(tr("Icon size of the editor tool bar"));
m_toolBarIconSizeSpinBox->setRange(1, 48);
m_toolBarIconSizeSpinBox->setSingleStep(1);
const QString label(tr("Toolbar icon size:"));
mainLayout->addRow(label, m_toolBarIconSizeSpinBox);
addSearchItem(label, m_toolBarIconSizeSpinBox->toolTip(), m_toolBarIconSizeSpinBox);
connect(m_toolBarIconSizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
this, &EditorPage::pageIsChanged);
}
} }
void EditorPage::loadInternal() void EditorPage::loadInternal()
@ -45,6 +61,8 @@ void EditorPage::loadInternal()
Q_ASSERT(idx != -1); Q_ASSERT(idx != -1);
m_autoSavePolicyComboBox->setCurrentIndex(idx); m_autoSavePolicyComboBox->setCurrentIndex(idx);
} }
m_toolBarIconSizeSpinBox->setValue(editorConfig.getToolBarIconSize());
} }
void EditorPage::saveInternal() void EditorPage::saveInternal()
@ -56,6 +74,8 @@ void EditorPage::saveInternal()
editorConfig.setAutoSavePolicy(static_cast<EditorConfig::AutoSavePolicy>(policy)); editorConfig.setAutoSavePolicy(static_cast<EditorConfig::AutoSavePolicy>(policy));
} }
editorConfig.setToolBarIconSize(m_toolBarIconSizeSpinBox->value());
notifyEditorConfigChange(); notifyEditorConfigChange();
} }

View File

@ -4,6 +4,7 @@
#include "settingspage.h" #include "settingspage.h"
class QComboBox; class QComboBox;
class QSpinBox;
namespace vnotex namespace vnotex
{ {
@ -27,6 +28,7 @@ namespace vnotex
void setupUI(); void setupUI();
QComboBox *m_autoSavePolicyComboBox = nullptr; QComboBox *m_autoSavePolicyComboBox = nullptr;
QSpinBox *m_toolBarIconSizeSpinBox = nullptr;
}; };
} }

View File

@ -2,6 +2,7 @@
#include <QComboBox> #include <QComboBox>
#include <QFormLayout> #include <QFormLayout>
#include <QCheckBox>
#include <widgets/widgetsfactory.h> #include <widgets/widgetsfactory.h>
#include <core/coreconfig.h> #include <core/coreconfig.h>
@ -55,6 +56,17 @@ void GeneralPage::setupUI()
this, &GeneralPage::pageIsChanged); this, &GeneralPage::pageIsChanged);
} }
#endif #endif
#if not defined(Q_OS_MACOS)
{
m_systemTrayCheckBox = WidgetsFactory::createCheckBox("System tray");
mainLayout->addRow(m_systemTrayCheckBox);
connect(m_systemTrayCheckBox, &QCheckBox::stateChanged,
this, &GeneralPage::pageIsChanged);
}
#endif
} }
void GeneralPage::loadInternal() void GeneralPage::loadInternal()
@ -73,6 +85,12 @@ void GeneralPage::loadInternal()
Q_ASSERT(idx != -1); Q_ASSERT(idx != -1);
m_openGLComboBox->setCurrentIndex(idx); m_openGLComboBox->setCurrentIndex(idx);
} }
if(m_systemTrayCheckBox){
auto toTray = coreConfig.getMinimizeToSystemTray();
if(toTray)
m_systemTrayCheckBox->setChecked(true);
}
} }
void GeneralPage::saveInternal() void GeneralPage::saveInternal()
@ -89,6 +107,10 @@ void GeneralPage::saveInternal()
int opt = m_openGLComboBox->currentData().toInt(); int opt = m_openGLComboBox->currentData().toInt();
sessionConfig.setOpenGL(static_cast<SessionConfig::OpenGL>(opt)); sessionConfig.setOpenGL(static_cast<SessionConfig::OpenGL>(opt));
} }
if(m_systemTrayCheckBox) {
coreConfig.setMinimizeToSystemTray(m_systemTrayCheckBox->isChecked());
}
} }
QString GeneralPage::title() const QString GeneralPage::title() const

View File

@ -4,6 +4,7 @@
#include "settingspage.h" #include "settingspage.h"
class QComboBox; class QComboBox;
class QCheckBox;
namespace vnotex namespace vnotex
{ {
@ -26,6 +27,9 @@ namespace vnotex
QComboBox *m_localeComboBox = nullptr; QComboBox *m_localeComboBox = nullptr;
QComboBox *m_openGLComboBox = nullptr; QComboBox *m_openGLComboBox = nullptr;
QCheckBox *m_systemTrayCheckBox = nullptr;
}; };
} }

View File

@ -15,6 +15,9 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QApplication> #include <QApplication>
#include <QShortcut> #include <QShortcut>
#include <QSystemTrayIcon>
#include <QMenu>
#include <QIcon>
#include "toolbox.h" #include "toolbox.h"
#include "notebookexplorer.h" #include "notebookexplorer.h"
@ -32,6 +35,7 @@
#include "outlineviewer.h" #include "outlineviewer.h"
#include <utils/widgetutils.h> #include <utils/widgetutils.h>
#include "navigationmodemgr.h" #include "navigationmodemgr.h"
#include <widgets/messageboxhelper.h>
#include <vtoolbar.h> #include <vtoolbar.h>
@ -46,6 +50,8 @@ MainWindow::MainWindow(QWidget *p_parent)
setupUI(); setupUI();
initSystemTrayIcon();
setupShortcuts(); setupShortcuts();
loadStateAndGeometry(); loadStateAndGeometry();
@ -54,6 +60,9 @@ MainWindow::MainWindow(QWidget *p_parent)
QApplication::setQuitOnLastWindowClosed(false); QApplication::setQuitOnLastWindowClosed(false);
#endif #endif
// The signal is particularly useful if your application has
// to do some last-second cleanup.
// Note that no user interaction is possible in this state.
connect(qApp, &QCoreApplication::aboutToQuit, connect(qApp, &QCoreApplication::aboutToQuit,
this, &MainWindow::closeOnQuit); this, &MainWindow::closeOnQuit);
} }
@ -282,10 +291,45 @@ void MainWindow::closeEvent(QCloseEvent *p_event)
{ {
// TODO: support minimized to system tray. // TODO: support minimized to system tray.
auto toTray = ConfigMgr::getInst().getCoreConfig().getMinimizeToSystemTray();
bool isExit = m_requestQuit;
m_requestQuit = 0;
if (isVisible()) { if (isVisible()) {
saveStateAndGeometry(); saveStateAndGeometry();
} }
#if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
// Do not support minimized to tray on macOS.
if (!isExit) {
p_event->accept();
return;
}
#endif
if(!isExit && toTray == -1){
int ret = MessageBoxHelper::questionYesNo(MessageBoxHelper::Question,
tr("Close VNote"),
tr("Do you want to minimize VNote to system tray "
"instead of quitting it when closing VNote?"),
tr("You could change the option in Settings later."),
this);
if (ret == QMessageBox::Yes) {
ConfigMgr::getInst().getCoreConfig().setMinimizeToSystemTray(true);
hide();
} else if (ret == QMessageBox::No) {
ConfigMgr::getInst().getCoreConfig().setMinimizeToSystemTray(false);
isExit = true;
} else {
p_event->ignore();
return;
}
}
if(isExit || toTray == 0 || !m_trayIcon->isVisible()){
// really to quit, process workspace
// TODO: process workspace
// Signal out the close event. // Signal out the close event.
auto event = QSharedPointer<Event>::create(); auto event = QSharedPointer<Event>::create();
event->m_response = true; event->m_response = true;
@ -297,6 +341,11 @@ void MainWindow::closeEvent(QCloseEvent *p_event)
} }
QMainWindow::closeEvent(p_event); QMainWindow::closeEvent(p_event);
qApp->quit();
}else {
hide();
p_event->ignore();
}
} }
void MainWindow::saveStateAndGeometry() void MainWindow::saveStateAndGeometry()
@ -485,3 +534,43 @@ void MainWindow::setStayOnTop(bool p_enabled)
show(); show();
} }
} }
void MainWindow::initSystemTrayIcon(){
QMenu *menu = new QMenu(this);
QAction *showMainWindowAct = menu->addAction(tr("Show VNote"));
connect(showMainWindowAct, &QAction::triggered,
this, &MainWindow::show);
QAction *exitAct = menu->addAction(tr("Quit"));
connect(exitAct, &QAction::triggered,
this, [this](){
this->m_requestQuit = 1;
this->close();
});
QIcon sysIcon(":/vnotex/data/core/logo/vnote.png");
#if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
sysIcon.setIsMask(true);
#endif
m_trayIcon = new QSystemTrayIcon(sysIcon, this);
m_trayIcon->setToolTip(tr("VNote"));
m_trayIcon->setContextMenu(menu);
connect(m_trayIcon, &QSystemTrayIcon::activated,
this, [this](QSystemTrayIcon::ActivationReason p_reason){
#if !defined(Q_OS_MACOS) && !defined(Q_OS_MAC)
if (p_reason == QSystemTrayIcon::Trigger) {
this->show();
this->activateWindow();
}
#endif
});
m_trayIcon->show();
}
void MainWindow::restart(){
QCoreApplication::exit(RESTART_EXIT_CODE);
}

View File

@ -7,7 +7,10 @@
#include "toolbarhelper.h" #include "toolbarhelper.h"
#include "statusbarhelper.h" #include "statusbarhelper.h"
#define RESTART_EXIT_CODE 1000
class QDockWidget; class QDockWidget;
class QSystemTrayIcon;
namespace vnotex namespace vnotex
{ {
@ -42,6 +45,8 @@ namespace vnotex
void setStayOnTop(bool p_enabled); void setStayOnTop(bool p_enabled);
void restart();
signals: signals:
void mainWindowStarted(); void mainWindowStarted();
@ -100,6 +105,14 @@ namespace vnotex
void setupShortcuts(); void setupShortcuts();
// Init system tray and correspondign context menu.
void initSystemTrayIcon();
// Tray icon.
QSystemTrayIcon *m_trayIcon;
bool m_requestQuit = false;
ToolBarHelper m_toolBarHelper; ToolBarHelper m_toolBarHelper;
StatusBarHelper m_statusBarHelper; StatusBarHelper m_statusBarHelper;
@ -117,6 +130,7 @@ namespace vnotex
QVector<QDockWidget *> m_docks; QVector<QDockWidget *> m_docks;
bool m_layoutReset = false; bool m_layoutReset = false;
}; };
} // ns vnotex } // ns vnotex

View File

@ -305,6 +305,14 @@ QToolBar *ToolBarHelper::setupSettingsToolBar(MainWindow *p_win, QToolBar *p_too
[p_win]() { [p_win]() {
p_win->resetStateAndGeometry(); p_win->resetStateAndGeometry();
}); });
menu->addSeparator();
menu->addAction(MainWindow::tr("Restart"),
menu,
[p_win]() {
p_win->restart();
});
} }
// Help. // Help.

View File

@ -13,6 +13,7 @@
class QLayout; class QLayout;
class QSplitter; class QSplitter;
class QTimer;
namespace vnotex namespace vnotex
{ {

View File

@ -410,7 +410,7 @@ QAction *ViewWindow::addAction(QToolBar *p_toolBar, ViewWindowToolBarHelper::Act
act = ViewWindowToolBarHelper::addAction(p_toolBar, p_action); act = ViewWindowToolBarHelper::addAction(p_toolBar, p_action);
connect(act, &QAction::triggered, connect(act, &QAction::triggered,
this, [this]() { this, [this]() {
if (m_findAndReplace && m_findAndReplace->isVisible()) { if (findAndReplaceWidgetVisible()) {
hideFindAndReplaceWidget(); hideFindAndReplaceWidget();
} else { } else {
showFindAndReplaceWidget(); showFindAndReplaceWidget();