From ea7ea20844faa4a879b46dbac7462cd3641511a3 Mon Sep 17 00:00:00 2001 From: zhangyuanyuan1 Date: Thu, 20 Jul 2023 11:31:46 +0800 Subject: [PATCH] vpn mainwindow --- src-vpn/frontend/vpnobject.cpp | 236 +++++++++++++++++++++++--- src-vpn/frontend/vpnobject.h | 29 +++- src-vpn/kylin-vpn-dbus/kylinvpndbus.h | 4 +- src-vpn/main.cpp | 2 +- 4 files changed, 241 insertions(+), 30 deletions(-) diff --git a/src-vpn/frontend/vpnobject.cpp b/src-vpn/frontend/vpnobject.cpp index 8959d72a..cc00fdd1 100644 --- a/src-vpn/frontend/vpnobject.cpp +++ b/src-vpn/frontend/vpnobject.cpp @@ -1,21 +1,27 @@ #include "vpnobject.h" #include #include +#include +#include +#include +#include +#include +#include "windowmanager/windowmanager.h" +#include "kysdk/kysdk-system/libkysysinfo.h" #include "ukuistylehelper/ukuistylehelper.h" #define MAINWINDOW_WIDTH 420 #define MAINWINDOW_HEIGHT 476 +const QString v10Sp1 = "V10SP1"; +const QString intel = "V10SP1-edu"; -vpnObject::vpnObject(QMainWindow *parent) : QMainWindow(parent) +VpnObject::VpnObject(QMainWindow *parent) : QMainWindow(parent) { - initUI(); - initTrayIcon(); - initDbusConnnect(); - this->setFixedSize(MAINWINDOW_WIDTH, MAINWINDOW_HEIGHT); + firstlyStart(); } -vpnObject::~vpnObject() +VpnObject::~VpnObject() { if (m_vpnGsettings != nullptr) { delete m_vpnGsettings; @@ -23,7 +29,193 @@ vpnObject::~vpnObject() } } -void vpnObject::initUI() +void VpnObject::showMainWindow() +{ + if (!m_loadFinished) { + m_secondaryStartTimer->stop(); + secondaryStart(); + } + + resetWindowPosition(); //设置窗体位置 + setWindowProperties(); + kdk::UkuiStyleHelper::self()->removeHeader(this); //去除窗管标题栏,传入参数为QWidget* + this->show(); + this->raise(); + this->activateWindow(); +} + +void VpnObject::hideMainWindow() +{ + this->hide(); +} + +/** + * @brief VpnObject::keyPressEvent 按esc键关闭主界面 + * @param event + */ +void VpnObject::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape) { + hideMainWindow(); + } + return QWidget::keyPressEvent(event); +} + +bool VpnObject::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::ActivationChange) { + if(QApplication::activeWindow() != this) { + hideMainWindow(); + } + } + return QMainWindow::eventFilter(watched,event); +} + +/** + * @brief MainWindow::firstlyStart 一级启动,执行重要且不耗时的启动操作 + */ +void VpnObject::firstlyStart() +{ + initWindowProperties(); + initUI(); + initTrayIcon(); + initDbusConnnect(); + initPlatform(); + installEventFilter(this); + + m_secondaryStartTimer = new QTimer(this); + connect(m_secondaryStartTimer, &QTimer::timeout, this, [ = ]() { + m_secondaryStartTimer->stop(); + secondaryStart();//满足条件后执行比较耗时的二级启动 + }); + m_secondaryStartTimer->start(5 * 1000); +} + +/** + * @brief VpnObject::secondaryStart 二级启动,可以将较耗时的初始化操作放到此处执行 + */ +void VpnObject::secondaryStart() +{ + if (m_loadFinished) { + return; + } + m_loadFinished = true; +} + +/** + * @brief VpnObject::initPlatform 初始化平台信息 + */ +void VpnObject::initPlatform() +{ + char* projectName = kdk_system_get_projectName(); + QString strProjectName(projectName); + free(projectName); + projectName = NULL; + if(v10Sp1.compare(strProjectName,Qt::CaseInsensitive) == 0) { + unsigned int feature = kdk_system_get_productFeatures(); + if (feature == 3) { + m_isShowInCenter = true; + } + } else if (intel.compare(strProjectName,Qt::CaseInsensitive) == 0) { + m_isShowInCenter = true; + } + qDebug() << "projectName" << projectName << m_isShowInCenter; +} + +void VpnObject::initWindowProperties() +{ + this->setFixedSize(MAINWINDOW_WIDTH, MAINWINDOW_HEIGHT); + this->setAttribute(Qt::WA_TranslucentBackground, true); //透明 + this->setFocusPolicy(Qt::NoFocus); + QString platform = QGuiApplication::platformName(); + if(!platform.startsWith(QLatin1String("wayland"),Qt::CaseInsensitive)) + { + QPainterPath path; + auto rect = this->rect(); + path.addRect(rect); + KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon())); //背景模糊 + } +} + +/** + * 设置主界面跳过任务栏和分页器的属性,隐藏再次展示有可能辉冲刷掉该属性,需要展示时重新设置 + */ +void VpnObject::setWindowProperties() +{ + QString platform = QGuiApplication::platformName(); + if(!platform.startsWith(QLatin1String("wayland"),Qt::CaseInsensitive)) + { + const KWindowInfo info(this->winId(), NET::WMState); + if (!info.hasState(NET::SkipTaskbar) || !info.hasState(NET::SkipPager)) { + KWindowSystem::setState(this->winId(), NET::SkipTaskbar | NET::SkipPager); + } + } +} + +/** + * @brief VpnObject::resetWindowPosition 重新计算窗口位置 + */ +void VpnObject::resetWindowPosition() +{ + if (m_isShowInCenter) { + QRect availableGeometry = qApp->primaryScreen()->availableGeometry(); + QRect rect((availableGeometry.width() - this->width())/2, (availableGeometry.height() - this->height())/2, + this->width(), this->height()); + kdk::WindowManager::setGeometry(this->windowHandle(), rect); + return; + } + +#define MARGIN 4 +#define PANEL_TOP 1 +#define PANEL_LEFT 2 +#define PANEL_RIGHT 3 + if (!m_positionInterface) { + m_positionInterface = new QDBusInterface("org.ukui.panel", + "/panel/position", + "org.ukui.panel", + QDBusConnection::sessionBus()); + } + QRect rect; + QDBusReply reply = m_positionInterface->call("GetPrimaryScreenGeometry"); + //reply获取的参数共5个,分别是 主屏可用区域的起点x坐标,主屏可用区域的起点y坐标,主屏可用区域的宽度,主屏可用区域高度,任务栏位置 + if (!m_positionInterface->isValid() || !reply.isValid() || reply.value().size() < 5) { + qCritical() << QDBusConnection::sessionBus().lastError().message(); + kdk::WindowManager::setGeometry(this->windowHandle(), QRect(0, 0, this->width(), this->height())); + return; + } + QVariantList position_list = reply.value(); + int position = position_list.at(4).toInt(); + switch(position){ + case PANEL_TOP: + //任务栏位于上方 + rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN, + position_list.at(1).toInt() + MARGIN, + this->width(), this->height()); + break; + //任务栏位于左边 + case PANEL_LEFT: + rect = QRect(position_list.at(0).toInt() + MARGIN, + position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN, + this->width(), this->height()); + break; + //任务栏位于右边 + case PANEL_RIGHT: + rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN, + position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN, + this->width(), this->height()); + break; + //任务栏位于下方 + default: + rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN, + position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN, + this->width(), this->height()); + break; + } + kdk::WindowManager::setGeometry(this->windowHandle(), rect); + //qDebug() << " Position of ukui-panel is " << position << "; Position of mainwindow is " << this->geometry() << "." << Q_FUNC_INFO << __LINE__; +} + +void VpnObject::initUI() { vpnWidget = new QWidget(this); QPalette pal = qApp->palette(); @@ -32,17 +224,17 @@ void vpnObject::initUI() this->setCentralWidget(vpnWidget); } -void vpnObject::initTrayIcon() +void VpnObject::initTrayIcon() { m_vpnTrayIcon = new QSystemTrayIcon(this); m_vpnTrayIcon->setToolTip(QString(tr("vpn tool"))); m_vpnTrayIcon->setIcon(QIcon::fromTheme("ukui-vpn-symbolic")); m_vpnTrayIcon->setVisible(true); initVpnIconVisible(); - connect(m_vpnTrayIcon, &QSystemTrayIcon::activated, this, &vpnObject::onTrayIconActivated); + connect(m_vpnTrayIcon, &QSystemTrayIcon::activated, this, &VpnObject::onTrayIconActivated); } -void vpnObject::initVpnIconVisible() +void VpnObject::initVpnIconVisible() { if (QGSettings::isSchemaInstalled(QByteArray(GSETTINGS_VPNICON_VISIBLE))) { m_vpnGsettings = new QGSettings(QByteArray(GSETTINGS_VPNICON_VISIBLE)); @@ -56,16 +248,16 @@ void vpnObject::initVpnIconVisible() } /** - * @brief vpnObject::onTrayIconActivated 点击托盘图标的槽函数 + * @brief VpnObject::onTrayIconActivated 点击托盘图标的槽函数 */ -void vpnObject::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason) +void VpnObject::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason) { switch(reason) { case QSystemTrayIcon::Trigger: if(this->isActiveWindow()) { - this->hide(); + hideMainWindow(); } else { - onShowMainWindow(); + showMainWindow(); } break; @@ -74,16 +266,14 @@ void vpnObject::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason) } } -void vpnObject::onShowMainWindow() +void VpnObject::onShowMainWindow() { - //去除窗管标题栏,传入参数为QWidget* - kdk::UkuiStyleHelper::self()->removeHeader(this); - this->show(); - this->raise(); - this->activateWindow(); + if(QApplication::activeWindow() != this) { + this->showMainWindow(); + } } -void vpnObject::initDbusConnnect() +void VpnObject::initDbusConnnect() { //模式切换 QDBusConnection::sessionBus().connect(QString("com.kylin.statusmanager.interface"), @@ -92,11 +282,11 @@ void vpnObject::initDbusConnnect() QString("mode_change_signal"), this, SLOT(onTabletModeChanged(bool))); } -void vpnObject::onTabletModeChanged(bool mode) +void VpnObject::onTabletModeChanged(bool mode) { qDebug() << "TabletMode change" << mode; Q_UNUSED(mode) //模式切换时,隐藏主界面 - this->hide(); + hideMainWindow(); } diff --git a/src-vpn/frontend/vpnobject.h b/src-vpn/frontend/vpnobject.h index 01e1feea..32370762 100644 --- a/src-vpn/frontend/vpnobject.h +++ b/src-vpn/frontend/vpnobject.h @@ -8,20 +8,42 @@ #include #include #include +#include #define VISIBLE "visible" #define GSETTINGS_VPNICON_VISIBLE "org.ukui.kylin-nm.vpnicon" //const QByteArray GSETTINGS_VPNICON_VISIBLE = "org.ukui.kylin-nm.vpnicon"; -class vpnObject : public QMainWindow +class VpnObject : public QMainWindow { Q_OBJECT public: - explicit vpnObject(QMainWindow *parent = nullptr); - ~vpnObject(); + explicit VpnObject(QMainWindow *parent = nullptr); + ~VpnObject(); + + void showMainWindow(); + void hideMainWindow(); + +protected: + void keyPressEvent(QKeyEvent *event) override; + bool eventFilter(QObject *watched, QEvent *event) override; private: + bool m_loadFinished = false; //是否二级启动已执行完 + QTimer * m_secondaryStartTimer = nullptr; //执行二级启动的倒计时 + QDBusInterface * m_positionInterface = nullptr; + + //一级启动 + void firstlyStart(); + //二级启动 + void secondaryStart(); + void initPlatform(); + void initWindowProperties(); + void setWindowProperties(); + //获取和重置窗口位置 + void resetWindowPosition(); + void initUI(); void initTrayIcon(); void initVpnIconVisible(); @@ -36,7 +58,6 @@ private: QGSettings * StyleSettings = nullptr; double tran =1; - QDBusInterface * m_positionInterface = nullptr; bool m_isShowInCenter = false; public Q_SLOTS: diff --git a/src-vpn/kylin-vpn-dbus/kylinvpndbus.h b/src-vpn/kylin-vpn-dbus/kylinvpndbus.h index f7bc3309..4ddce295 100644 --- a/src-vpn/kylin-vpn-dbus/kylinvpndbus.h +++ b/src-vpn/kylin-vpn-dbus/kylinvpndbus.h @@ -18,8 +18,8 @@ class KylinVpnDbus : public QObject public: explicit KylinVpnDbus(QObject *parent = nullptr); ~KylinVpnDbus() = default; - inline vpnObject *parent() const - { return static_cast(QObject::parent()); } + inline VpnObject *parent() const + { return static_cast(QObject::parent()); } private: KyNetworkManager* m_manager; diff --git a/src-vpn/main.cpp b/src-vpn/main.cpp index 5ce8caec..066bdc93 100644 --- a/src-vpn/main.cpp +++ b/src-vpn/main.cpp @@ -120,7 +120,7 @@ int main(int argc, char *argv[]) // ::usleep(1000); // } - vpnObject vpnobject; + VpnObject vpnobject; a.setActivationWindow(&vpnobject); vpnobject.setProperty("useStyleWindowManager", false); //禁用拖动 a.setWindowIcon(QIcon::fromTheme("ukui-vpn-symbolic"));