From 17bd206e18996f5fbef000e860f155935b049e4f Mon Sep 17 00:00:00 2001
From: zty199 <1282441920@qq.com>
Date: Mon, 30 Nov 2020 02:22:28 +0800
Subject: [PATCH] Improve Features

Support tray icon;
Fix few bugs about confliction between fullscreen mode and fixsize
option.
---
 spark-webapp-runtime/help/help.html           |   2 +
 spark-webapp-runtime/main.cpp                 |  38 ++++--
 spark-webapp-runtime/mainwindow.cpp           | 110 +++++++++++++++---
 spark-webapp-runtime/mainwindow.h             |  11 ++
 .../spark-webapp-runtime_zh_CN.qm             | Bin 2571 -> 2827 bytes
 .../spark-webapp-runtime_zh_CN.ts             |  56 ++++++---
 spark-webapp-runtime/widget.cpp               |   9 +-
 spark-webapp-runtime/widget.h                 |   3 +-
 8 files changed, 178 insertions(+), 51 deletions(-)

diff --git a/spark-webapp-runtime/help/help.html b/spark-webapp-runtime/help/help.html
index 6cc2913..81730ec 100644
--- a/spark-webapp-runtime/help/help.html
+++ b/spark-webapp-runtime/help/help.html
@@ -28,6 +28,7 @@
                   -u, --url <url>        设置要打开的目标 URL。默认为空。
                   -w, --width <width>    设置应用的窗口宽度。默认为 1024。
                   -H, --height <height>  设置应用的窗口高度。默认为 768。
+                  -T, --tray             启用托盘图标。默认不启用。
                   --full-screen          以全屏模式运行。默认关闭该功能。
                   --fix-size             固定窗口大小。默认关闭该功能。
                   --hide-buttons         隐藏控制按钮。默认关闭该功能。
@@ -64,6 +65,7 @@
                   -u, --url <url>        The target URL. Default is Blank.
                   -w, --width <width>    The Width of Application. Default is 1024.
                   -H, --height <height>  The Height of Application. Default is 768.
+                  -T, --tray             Enable Tray Icon. Default is false.
                   --full-screen          Run in Fullscreen Mode. Default is false.
                   --fix-size             Fix Window Size. Default is false.
                   --hide-buttons         Hide Control Buttons. Default is false.
diff --git a/spark-webapp-runtime/main.cpp b/spark-webapp-runtime/main.cpp
index 84cd894..7c0d809 100644
--- a/spark-webapp-runtime/main.cpp
+++ b/spark-webapp-runtime/main.cpp
@@ -20,8 +20,8 @@ int main(int argc, char *argv[])
     DApplication a(argc, argv);
 
     a.loadTranslator();
-
     a.setAttribute(Qt::AA_UseHighDpiPixmaps);
+
     a.setApplicationVersion(QString::number(CURRENT_VER));
     a.setOrganizationName("spark-union");       // 添加组织名称,和商店主体的文件夹同在 ~/.local/share/spark-union 文件夹下
     a.setApplicationName("SparkWebAppRuntime"); // 这里不要翻译,否则 ~/.local/share 中文件夹名也会被翻译
@@ -86,6 +86,10 @@ int main(int argc, char *argv[])
                                  QString::number(DEFAULT_HEIGHT));
     parser.addOption(optHeight);
 
+    QCommandLineOption optTray(QStringList() << "T" << "tray",
+                                  QObject::tr("Enable Tray Icon. Default is false."));
+    parser.addOption(optTray);
+
     QCommandLineOption optFullScreen("full-screen",
                                   QObject::tr("Run in Fullscreen Mode. Default is false."));
     parser.addOption(optFullScreen);
@@ -143,6 +147,7 @@ int main(int argc, char *argv[])
     QString szUrl = DEFAULT_URL;
     int width = DEFAULT_WIDTH;
     int height = DEFAULT_HEIGHT;
+    bool tray = false;
     bool fullScreen = false;
     bool fixSize = false;
     bool hideButtons = false;
@@ -168,6 +173,7 @@ int main(int argc, char *argv[])
                 szUrl = settings.value("SparkWebAppRuntime/URL", DEFAULT_TITLE).toString();
                 width = settings.value("SparkWebAppRuntime/Width", DEFAULT_WIDTH).toUInt();
                 height = settings.value("SparkWebAppRuntime/Height", DEFAULT_HEIGHT).toUInt();
+                tray = settings.value("SparkWebAppRunTime/Tray", false).toBool();
                 fullScreen = settings.value("SparkWebAppRunTime/FullScreen", false).toBool();
                 fixSize = settings.value("SparkWebAppRunTime/FixSize", false).toBool();
                 hideButtons = settings.value("SparkWebAppRunTime/HideButtons", false).toBool();
@@ -202,6 +208,10 @@ int main(int argc, char *argv[])
         height = parser.value(optHeight).toInt();
     }
 
+    if (parser.isSet(optTray))
+    {
+        tray = true;
+    }
     if (parser.isSet(optFullScreen))
     {
         fullScreen = true;
@@ -238,7 +248,7 @@ int main(int argc, char *argv[])
     }
 #endif
 
-    // 没设置 -p 并且参数个数>1 并且第一个参数不是-开始的
+    // 没设置 -p 并且参数个数 > 1 并且第一个参数不是 - 开始的
     if (!parser.isSet(optParser) && argc > 1 && !QString(argv[1]).startsWith("-"))
     {
         // 按照固定顺序级别最优先
@@ -261,35 +271,39 @@ int main(int argc, char *argv[])
 
         if (argc > 5)
         {
-            fullScreen = true;
+            tray = true;
         }
         if (argc > 6)
         {
-            fixSize = true;
+            fullScreen = true;
         }
         if (argc > 7)
+        {
+            fixSize = true;
+        }
+        if (argc > 8)
         {
             hideButtons = true;
         }
 
-        if (argc > 8)
+        if (argc > 9)
         {
             szIcon = QString(argv[7]);
         }
-        if (argc > 9)
+        if (argc > 10)
         {
             szDesc = QString("%1<br/><br/>%2").arg(QString(argv[8])).arg(szDefaultDesc);
         }
-        if (argc > 10)
+        if (argc > 11)
         {
             szRootPath = QString(argv[9]);
         }
-        if (argc > 11)
+        if (argc > 12)
         {
             u16Port = QString(argv[10]).toUInt();
         }
 #if SSL_SERVER
-        if (argc > 12)
+        if (argc > 13)
         {
             u16sslPort = QString(argv[11]).toUInt();
         }
@@ -298,10 +312,12 @@ int main(int argc, char *argv[])
 
     if(fixSize)
     {
-        fullScreen = false; //  固定窗口大小时禁用全屏模式,避免标题栏按钮 BUG
+        fullScreen = false;             // 固定窗口大小时禁用全屏模式,避免标题栏按钮 BUG
     }
 
-    MainWindow w(szTitle, szUrl, width, height, fullScreen, fixSize, hideButtons, dialog);
+    a.setQuitOnLastWindowClosed(!tray); // 启用托盘时,退出程序后服务不终止
+
+    MainWindow w(szTitle, szUrl, width, height, tray, fullScreen, fixSize, hideButtons, dialog);
 
 #if SSL_SERVER
     if (!szRootPath.isEmpty() && u16Port > 0 && u16sslPort > 0)
diff --git a/spark-webapp-runtime/mainwindow.cpp b/spark-webapp-runtime/mainwindow.cpp
index ed1aaa3..0bb2716 100644
--- a/spark-webapp-runtime/mainwindow.cpp
+++ b/spark-webapp-runtime/mainwindow.cpp
@@ -19,6 +19,7 @@ MainWindow::MainWindow(QString szTitle,
                        QString szUrl,
                        int nWidth,
                        int nHeight,
+                       bool tray,
                        bool nFullScreen,
                        bool nFixSize,
                        bool nHideButtons,
@@ -27,6 +28,7 @@ MainWindow::MainWindow(QString szTitle,
     : DMainWindow(parent)
     , m_widget(new Widget(szUrl))
     , m_dialog(dialog)
+    , m_tray(new QSystemTrayIcon)
     , btnBack(new DToolButton(titlebar()))
     , btnForward(new DToolButton(titlebar()))
     , btnRefresh(new DToolButton(titlebar()))
@@ -34,12 +36,19 @@ MainWindow::MainWindow(QString szTitle,
     , m_fullScreen(new QAction(tr("Full Screen")))
     , m_fixSize(new QAction(tr("Fix Size")))
     , m_hideButtons(new QAction(tr("Hide Buttons")))
+    , t_menu(new QMenu)
+    , t_show(new QAction(tr("Show MainWindow")))
+    , t_about(new QAction(tr("About")))
+    , t_exit(new QAction(tr("Exit")))
     , bar(new DProgressBar)
     , message(new DFloatingMessage(DFloatingMessage::ResidentType))
     , process(new QProcess)
+    , mtray(tray)
+    , mFixSize(nFixSize)
     , m_width(nWidth)
     , m_height(nHeight)
 {
+    /* 初始化 MainWindow */
     setCentralWidget(m_widget);
     centralWidget()->layout()->setContentsMargins(0, 0, 0, 0);
 
@@ -72,17 +81,36 @@ MainWindow::MainWindow(QString szTitle,
     m_hideButtons->setCheckable(true);
     m_hideButtons->setChecked(nHideButtons);
     m_hideButtons->setDisabled(nHideButtons);
-    m_menu->addAction(m_fullScreen);
-    m_menu->addAction(m_fixSize);
-    m_menu->addAction(m_hideButtons);
+    /* 命令行设置参数后 GUI 中隐藏对应选项 */
+    if(!nFixSize)
+    {
+        m_menu->addAction(m_fullScreen);
+        m_menu->addAction(m_fixSize);
+    }
+    if(!nHideButtons)
+    {
+        m_menu->addAction(m_hideButtons);
+    }
     titlebar()->setMenu(m_menu);
 
     titlebar()->setAutoHideOnFullscreen(true);
 
-    fullScreen();
     fixSize();
     hideButtons();
 
+    /* 初始化 TrayIcon */
+    t_menu->addAction(t_show);
+    t_menu->addAction(t_about);
+    t_menu->addAction(t_exit);
+    m_tray->setContextMenu(t_menu);
+    m_tray->setToolTip(szTitle);
+    m_tray->setIcon(QIcon(":/images/spark-webapp-runtime.svg"));
+
+    if(tray)
+    {
+        m_tray->show(); // 启用托盘时显示
+    }
+
     connect(btnBack, &DToolButton::clicked, this, [&]()
     {
         m_widget->goBack();
@@ -109,6 +137,22 @@ MainWindow::MainWindow(QString szTitle,
         hideButtons();
     });
 
+    connect(t_show, &QAction::triggered, this, [=]()
+    {
+        this->activateWindow();
+        fixSize();
+    });
+    connect(t_about, &QAction::triggered, this, [=]()
+    {
+        m_dialog->activateWindow();
+        m_dialog->show();
+    });
+    connect(t_exit, &QAction::triggered, this, [=]()
+    {
+        exit(0);
+    });
+    connect(m_tray, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);
+
     connect(m_widget->getPage()->profile(), &QWebEngineProfile::downloadRequested, this, &MainWindow::on_downloadStart);
 }
 
@@ -117,6 +161,7 @@ MainWindow::~MainWindow()
     emit sigQuit();
     delete m_widget;
     delete m_dialog;
+    delete m_tray;
 }
 
 void MainWindow::setIcon(QString szIconPath)
@@ -126,6 +171,7 @@ void MainWindow::setIcon(QString szIconPath)
     {
         titlebar()->setIcon(QIcon(szIconPath));
         setWindowIcon(QIcon(szIconPath));
+        m_tray->setIcon(QIcon(szIconPath));
         qDebug() << szIconPath << "is Set!";
     }
     else
@@ -138,11 +184,19 @@ void MainWindow::fullScreen()
 {
     if(m_fullScreen->isChecked())
     {
+        m_fixSize->setChecked(false);
+        m_fixSize->setDisabled(true);
+        m_menu->update();
         showFullScreen();
         DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-information").pixmap(64, 64), QString(tr("%1Fullscreen Mode")).arg("    "));
     }
     else
     {
+        if(!mFixSize)
+        {
+            m_fixSize->setDisabled(false);  // 命令行参数没有固定窗口大小时,窗口模式下允许手动选择固定窗口大小
+        }
+        m_menu->update();
         showNormal();
         DMessageManager::instance()->sendMessage(this, QIcon::fromTheme("dialog-information").pixmap(64, 64), QString(tr("%1Windowed Mode")).arg("    "));
     }
@@ -152,13 +206,20 @@ void MainWindow::fixSize()
 {
     if(m_fixSize->isChecked())
     {
-        setFixedSize(this->width(), this->height());
+        m_fullScreen->setChecked(false);
+        m_fullScreen->setDisabled(true);
+        m_menu->update();
+        setFixedSize(this->size());
+        /* 存在 BUG: 启用托盘图标后,若手动选择固定窗口大小,并且关闭窗口,再次打开时会丢失最大化按钮,且无法恢复。 */
     }
     else
     {
+        m_fullScreen->setDisabled(false);
+        m_menu->update();
         setMinimumSize(m_width, m_height);
         setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
     }
+    fullScreen();
 }
 
 void MainWindow::hideButtons()
@@ -182,14 +243,13 @@ QString MainWindow::saveAs(QString fileName)
     QString saveFile = QFileDialog::getSaveFileName(this, tr("Save As"), QDir::homePath() + "/Downloads/" + fileName);
     if(!saveFile.isEmpty())
     {
-        //  判断上层目录是否可写入
-        if(QFileInfo(QFileInfo(saveFile).absolutePath()).permissions().testFlag(QFile::WriteUser))
+        if(QFileInfo(QFileInfo(saveFile).absolutePath()).permissions().testFlag(QFile::WriteUser))  // 判断上层目录是否可写入
         {
             return saveFile;
         }
         else
         {
-            saveAs(fileName);
+            return saveAs(fileName);
         }
     }
     return nullptr;
@@ -197,9 +257,9 @@ QString MainWindow::saveAs(QString fileName)
 
 void MainWindow::keyPressEvent(QKeyEvent *event)
 {
-    if(m_fixSize->isEnabled())
+    if(!m_fixSize->isChecked()) // 固定窗口大小时禁止全屏
     {
-        if(event->key() == Qt::Key_F11)
+        if(event->key() == Qt::Key_F11) // 绑定键盘快捷键 F11
         {
             m_fullScreen->trigger();
             m_menu->update();
@@ -210,23 +270,41 @@ void MainWindow::keyPressEvent(QKeyEvent *event)
 
 void MainWindow::closeEvent(QCloseEvent *event)
 {
-    m_dialog->close();
+    if(!mtray)
+    {
+        m_dialog->close();  // 不启用托盘时,关闭主窗口则关闭关于窗口
+    }
     event->accept();
 }
 
+void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
+{
+    switch(reason)
+    {
+        /* 响应托盘点击事件 */
+        case QSystemTrayIcon::Trigger:
+            this->activateWindow();
+            fixSize();
+            break;
+        default:
+            break;
+    }
+}
+
 void MainWindow::on_downloadStart(QWebEngineDownloadItem *item)
 
 {
     QString fileName = QFileInfo(item->path()).fileName();
-    if(saveAs(fileName).isEmpty())
+    QString filePath = saveAs(fileName);
+    if(filePath.isEmpty())
     {
         return;
     }
-    item->setPath(saveAs(fileName));
-    QString filePath = QFileInfo(item->path()).absoluteFilePath();
+    item->setPath(filePath);
+    filePath = QFileInfo(item->path()).absoluteFilePath();
 
     connect(item, &QWebEngineDownloadItem::downloadProgress, this, &MainWindow::on_downloadProgress);
-    connect(item, &QWebEngineDownloadItem::finished, this, [=]
+    connect(item, &QWebEngineDownloadItem::finished, this, [=]()
     {
         on_downloadFinish(filePath);
     });
@@ -263,7 +341,7 @@ void MainWindow::on_downloadFinish(QString filePath)
     message->setWidget(button);
     DMessageManager::instance()->sendMessage(this, message);
 
-    connect(button, &DPushButton::clicked, this, [=]
+    connect(button, &DPushButton::clicked, this, [=]()
     {
         process->start("dde-file-manager --show-item " + filePath);
         message->hide();
diff --git a/spark-webapp-runtime/mainwindow.h b/spark-webapp-runtime/mainwindow.h
index a808ca5..df74ee2 100644
--- a/spark-webapp-runtime/mainwindow.h
+++ b/spark-webapp-runtime/mainwindow.h
@@ -7,6 +7,7 @@
 #include <DProgressBar>
 #include <DFloatingMessage>
 
+#include <QSystemTrayIcon>
 #include <QProcess>
 
 #include "widget.h"
@@ -23,6 +24,7 @@ public:
                QString szUrl = DEFAULT_URL,
                int nWidth = DEFAULT_WIDTH,
                int nHeight = DEFAULT_HEIGHT,
+               bool tray = false,
                bool nFullScreen = false,
                bool nFixSize = false,
                bool nHideButtons = false,
@@ -35,6 +37,7 @@ public:
 private:
     Widget *m_widget;
     DAboutDialog *m_dialog;
+    QSystemTrayIcon *m_tray;
 
     DToolButton *btnBack;
     DToolButton *btnForward;
@@ -45,11 +48,17 @@ private:
     QAction *m_fixSize;
     QAction *m_hideButtons;
 
+    QMenu *t_menu;
+    QAction *t_show;
+    QAction *t_about;
+    QAction *t_exit;
+
     DProgressBar *bar;
     DFloatingMessage *message;
 
     QProcess *process;
 
+    bool mtray, mFixSize;
     int m_width, m_height;
 
     void fullScreen();
@@ -62,6 +71,8 @@ private:
     void closeEvent(QCloseEvent *event);
 
 private slots:
+    void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
+
     void on_downloadStart(QWebEngineDownloadItem *item);
     void on_downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
     void on_downloadFinish(QString filePath);
diff --git a/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.qm b/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.qm
index 57fdbc20a25466af5bf64680f702ba9aded18fc4..dca0c2b7b8efbcc7dd7cfdaef9e27dda2587f5ce 100644
GIT binary patch
delta 463
zcmeAc=@zTE*^we~>iwLlXBB1kCoJ51*NK6Fk%NKdJPQK@!&3&<w0%JS0tSvB_ZS#h
z*coIu_%SfBUSn{db_6KDmtpDBt3Y`k#=OOP3=C`+7`HA;1<Kp8Fz)`xz`()J;v$pB
zz`*pJ<?w1CpWTerTeTdh{xfUhZc(8AX4akchx~yCXR+?;16sh^z<RE)kAZ<Xi1oT>
z98jS(>&H9q7#KL2*`~NZ0&1|~;OKt{G;kBg$)tTix|~z&0?+|K6+I=Ff$ER*%woI+
z<n8BG5f%pWbNS@lK@L;pGv@gZRIklvw-4wb=GA<Qx32?=_wcD)_;?QJ(i*;xV()-1
zoWrj#!3T8EP5yxXWS~JQnLy&@WG2RgA}oQ$etjGu%h-UJ)iEi*v}CdXlZY_O1ctz0
za0wRIicFBW=;R}e&s4b5>?*DNtV?~SC&5+l2WRA$EBGd6=7neGrR0}`4B5PjNuAMD
zDn!3jBPpWnM%cd$b_1q)H@cVj@q)w*nBcmVUGox?a#9sSiV`aoJd^YDCOfdIY`(~B
G#RdQcAbR@%

delta 283
zcmeAc>lUfE*^we~>iwLlXBB1kCoJ51*NK6F;ROS0+CByb#y|#+ANLp-nAI6%H~29y
zuzX`!y7VegelKI*Vm$^1)(?zZ7o`Hl<5(DX|6^ca*Jp8&$zxz(N?<v>8pvl0V@=#G
z3RK_By7Q1f(3~#TU420FSQfBe_lyIIzhV7Yf9D+o1BWu(6!%9!0UHjE{)a#Vv^h>D
z?E^aC1E<&pkcAAKJtdcc{0g2~jJJU5@AIk%3j_Ibd~)s}hq&??^ZW<$m+;x`13BO{
z-{S4-fZ}WTE_^%(bl4oek7DnD4%)-7FTn?N$WQ)&{$!vzEtxDpvpFX#F&><3#Pob~
NAhSB-=8G&=Yyjx0P-_4H

diff --git a/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.ts b/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.ts
index 81c1349..e7bf3a0 100644
--- a/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.ts
+++ b/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.ts
@@ -4,52 +4,67 @@
 <context>
     <name>MainWindow</name>
     <message>
-        <location filename="../mainwindow.cpp" line="34"/>
+        <location filename="../mainwindow.cpp" line="36"/>
         <source>Full Screen</source>
         <translation>全屏显示</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="35"/>
+        <location filename="../mainwindow.cpp" line="37"/>
         <source>Fix Size</source>
         <translation>固定大小</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="36"/>
+        <location filename="../mainwindow.cpp" line="38"/>
         <source>Hide Buttons</source>
         <translation>隐藏按钮</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="142"/>
+        <location filename="../mainwindow.cpp" line="40"/>
+        <source>Show MainWindow</source>
+        <translation>显示主界面</translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="41"/>
+        <source>About</source>
+        <translation>关于</translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="42"/>
+        <source>Exit</source>
+        <translation>退出</translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="191"/>
         <source>%1Fullscreen Mode</source>
         <translation>%1全屏模式</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="147"/>
+        <location filename="../mainwindow.cpp" line="201"/>
         <source>%1Windowed Mode</source>
         <translation>%1窗口模式</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="182"/>
+        <location filename="../mainwindow.cpp" line="243"/>
         <source>Save As</source>
         <translation>另存为</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="236"/>
+        <location filename="../mainwindow.cpp" line="314"/>
         <source>%1Start downloading %2</source>
         <translation>%1开始下载 %2</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="258"/>
+        <location filename="../mainwindow.cpp" line="336"/>
         <source>Open</source>
         <translation>打开</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="262"/>
+        <location filename="../mainwindow.cpp" line="340"/>
         <source>download finished.</source>
         <translation>下载完成。</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="262"/>
+        <location filename="../mainwindow.cpp" line="340"/>
         <source>Show in file manager?</source>
         <translation>是否在文件管理器中显示?</translation>
     </message>
@@ -103,46 +118,51 @@
     </message>
     <message>
         <location filename="../main.cpp" line="90"/>
+        <source>Enable Tray Icon. Default is false.</source>
+        <translation>启用托盘图标。默认不启用。</translation>
+    </message>
+    <message>
+        <location filename="../main.cpp" line="94"/>
         <source>Run in Fullscreen Mode. Default is false.</source>
         <translation>以全屏模式运行。默认关闭该功能。</translation>
     </message>
     <message>
-        <location filename="../main.cpp" line="94"/>
+        <location filename="../main.cpp" line="98"/>
         <source>Fix Window Size. Default is false.</source>
         <translation>固定窗口大小。默认关闭该功能。</translation>
     </message>
     <message>
-        <location filename="../main.cpp" line="98"/>
+        <location filename="../main.cpp" line="102"/>
         <source>Hide Control Buttons. Default is false.</source>
         <translation>隐藏控制按钮。默认关闭该此功能。</translation>
     </message>
     <message>
-        <location filename="../main.cpp" line="102"/>
+        <location filename="../main.cpp" line="106"/>
         <source>The ICON of Application.</source>
         <translation>设置应用的图标。</translation>
     </message>
     <message>
-        <location filename="../main.cpp" line="108"/>
+        <location filename="../main.cpp" line="112"/>
         <source>The Description of Application.</source>
         <translation>设置应用的描述信息。</translation>
     </message>
     <message>
-        <location filename="../main.cpp" line="114"/>
+        <location filename="../main.cpp" line="118"/>
         <source>The Configuration file of Application.</source>
         <translation>设置应用的配置文件。</translation>
     </message>
     <message>
-        <location filename="../main.cpp" line="120"/>
+        <location filename="../main.cpp" line="124"/>
         <source>The root path of the program web service.</source>
         <translation>设置内置 WebServer 的根路径。</translation>
     </message>
     <message>
-        <location filename="../main.cpp" line="127"/>
+        <location filename="../main.cpp" line="131"/>
         <source>The port number of the program web service.</source>
         <translation>设置内置 WebServer 的监听端口号。</translation>
     </message>
     <message>
-        <location filename="../main.cpp" line="134"/>
+        <location filename="../main.cpp" line="138"/>
         <source>The ssl port number of the program web service.</source>
         <translation>设置内置 WebServer 的 SSL 协议的监听端口号。</translation>
     </message>
diff --git a/spark-webapp-runtime/widget.cpp b/spark-webapp-runtime/widget.cpp
index d861dc1..cf77e31 100644
--- a/spark-webapp-runtime/widget.cpp
+++ b/spark-webapp-runtime/widget.cpp
@@ -3,7 +3,6 @@
 Widget::Widget(QString szUrl, QWidget *parent)
     : QWidget(parent)
     , m_webEngineView(new QWebEngineView)
-    , m_page(new WebEnginePage)
     , m_szUrl(szUrl)
     , m_spinner(new DSpinner)
     , main(new QHBoxLayout)
@@ -16,7 +15,9 @@ Widget::Widget(QString szUrl, QWidget *parent)
     m_webEngineView->setEnabled(true);
     m_webEngineView->setAutoFillBackground(false);
     m_webEngineView->setZoomFactor(1);
-    m_webEngineView->setPage(m_page);
+
+    WebEnginePage *page = new WebEnginePage;
+    m_webEngineView->setPage(page);
 
     m_webEngineView->setUrl(QUrl(nullptr));
     if (!m_szUrl.isEmpty())
@@ -32,9 +33,9 @@ Widget::~Widget()
 {
 }
 
-WebEnginePage *Widget::getPage()
+QWebEnginePage *Widget::getPage()
 {
-    return m_page;
+    return this->m_webEngineView->page();
 }
 
 void Widget::goBack()
diff --git a/spark-webapp-runtime/widget.h b/spark-webapp-runtime/widget.h
index c0748c2..5c6f174 100644
--- a/spark-webapp-runtime/widget.h
+++ b/spark-webapp-runtime/widget.h
@@ -21,14 +21,13 @@ public:
     explicit Widget(QString szUrl = nullptr, QWidget *parent = nullptr);
     ~Widget();
 
-    WebEnginePage *getPage();
+    QWebEnginePage *getPage();
     void goBack();
     void goForward();
     void refresh();
 
 private:
     QWebEngineView *m_webEngineView;
-    WebEnginePage *m_page;
     QString m_szUrl;
     DSpinner *m_spinner;