diff --git a/backup-daemon/main.cpp b/backup-daemon/main.cpp index 717413c..d6ce657 100755 --- a/backup-daemon/main.cpp +++ b/backup-daemon/main.cpp @@ -8,6 +8,7 @@ #include #include "../common/reflect.h" #include "mymountproxy.h" + // test end int main(int argc, char *argv[]) @@ -25,16 +26,17 @@ int main(int argc, char *argv[]) qInstallMessageHandler(Utils::customMessageHandler); // test begin - //MyMountProxy * proxy = (MyMountProxy*)Reflect::createObject("MyMountProxy"); - //proxy->mountBackupPartition(); - qDebug() << QString("测试 begin"); - BackupWrapper backupWrapper; - backupWrapper.m_backupName = "赵民勇test"; - backupWrapper.m_backupPaths << "/"; - backupWrapper.m_backupExcludePaths = Utils::getFromExcludePathsFile(); - MyBackupManager manager; - manager.goBackup(backupWrapper); + +// MyMountProxy * proxy = (MyMountProxy*)Reflect::createObject("MyMountProxy"); +// proxy->mountBackupPartition(); + +// BackupWrapper backupWrapper; +// backupWrapper.m_backupName = "赵民勇test"; +// backupWrapper.m_backupPaths << "/"; +// backupWrapper.m_backupExcludePaths = Utils::getFromExcludePathsFile(); +// MyBackupManager manager; +// manager.goBackup(backupWrapper); qDebug() << QString("测试 end"); // test end diff --git a/backup-daemon/systembackupproxy.cpp b/backup-daemon/systembackupproxy.cpp index 606a392..841de11 100755 --- a/backup-daemon/systembackupproxy.cpp +++ b/backup-daemon/systembackupproxy.cpp @@ -180,17 +180,20 @@ QStringList SystemBackupProxy::getRsyncArgs(SystemBackupScene scene) case SystemBackupScene::SYSTEM_BACKUP : args << "-avAXW"; args << "--progress"; + args << "--no-inc-recursive"; args << "--ignore-missing-args"; break ; case SystemBackupScene::INC_SYSTEM_BACKUP : args << "-avAXr"; args << "--progress"; + args << "--no-inc-recursive"; args << "--ignore-missing-args"; args << QString("--link-dest=../../%1/data").arg(m_backupWrapper.m_baseUuid); break ; case SystemBackupScene::INC_SYSTEM_BACKUP_AT_BASE : args << "-avAXr"; args << "--progress"; + args << "--no-inc-recursive"; args << "--ignore-missing-args"; args << "--delete"; break ; @@ -356,7 +359,10 @@ bool SystemBackupProxy::backupEfi() } args << efiPath; - args << m_destPath; + QString destPath = m_destPath + "/boot"; + destPath.replace("//", "/"); + Utils::mkpath(destPath); + args << destPath; m_p = new RsyncPathToDirProcess(this); bool result = m_p->start(args); diff --git a/common/mydefine.h b/common/mydefine.h index 5b32eef..1abb676 100755 --- a/common/mydefine.h +++ b/common/mydefine.h @@ -34,8 +34,11 @@ #define BACKUP_PARSE_STATE_INC_SUCCESS_STRTING "inc backup finished" #define BACKUP_PARSE_STATE_INC_FAIL_STRTING "inc backup unfinished" +#define THEME_YHKYLIN_BACKUP_TOOLS "yhkylin-backup-tools" + #define PID_STRING_LEN 1024 + /** * @brief 备份还原操作类型 */ diff --git a/common/utils.cpp b/common/utils.cpp index f487c7c..1ee5d12 100755 --- a/common/utils.cpp +++ b/common/utils.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -257,6 +256,8 @@ void Utils::excludeFstabBindPath(QStringList &excludes) continue ; if (line.startsWith("UUID=")) continue ; + if (line.startsWith("/dev/")) + continue ; if (line.isEmpty()) continue ; if (!line.contains("bind")) @@ -273,9 +274,9 @@ void Utils::excludeFstabBindPath(QStringList &excludes) continue; fields << field; } - // 配置文件/etc/fstab每行6个域,第二个域为挂载路径 + // 配置文件/etc/fstab每行6个域,第二个域为挂载路径, 第一个域就是待排除路径 if (6 == fields.size()) - excludes << fields.at(1); + excludes << fields.at(0); } file.close(); @@ -299,7 +300,7 @@ bool Utils::generateExcludePathsFile() QTextStream in(&excludePathFile); in << "/backup" << endl; //分区 - in << "/boot/efi" << endl; + // in << "/boot/efi" << endl; in << "/cdrom" << endl; in << "/dev" << endl; // efi原始目录在/boot/efi,备份到目标目录为/efi下,再还原时已经单独处理了,批量还原时应该屏蔽此目录 @@ -353,13 +354,9 @@ bool Utils::isDirExist(const QString& fullDirName) */ QStringList Utils::getFromExcludePathsFile() { - QString excludeFile = Utils::m_sysRootPath + EXCLUDE_FILE_PATH; - excludeFile.replace("//", "/"); - QFile excludePathFile(excludeFile); - if (!excludePathFile.open(QIODevice::ReadOnly)) { QStringList list; list << "/backup"; - list << "/boot/efi"; + // list << "/boot/efi"; list << "/cdrom"; list << "/dev"; list << "/efi"; @@ -386,16 +383,6 @@ QStringList Utils::getFromExcludePathsFile() } return list; - } - - QTextStream out(&excludePathFile); - QString strAll = out.readAll(); - excludePathFile.close(); - - QStringList list = strAll.split("\n"); - list.removeAll(QString("")); - - return list; } /** diff --git a/kybackup/app.qrc b/kybackup/app.qrc new file mode 100644 index 0000000..57bad45 --- /dev/null +++ b/kybackup/app.qrc @@ -0,0 +1,9 @@ + + + resource/images/data_backup.svg + resource/images/data_restore.svg + resource/images/ghost_image.svg + resource/images/sysem_restore.svg + resource/images/system_backup.png + + diff --git a/kybackup/component/clicklabel.cpp b/kybackup/component/clicklabel.cpp new file mode 100644 index 0000000..3060ebd --- /dev/null +++ b/kybackup/component/clicklabel.cpp @@ -0,0 +1,36 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "clicklabel.h" + +ClickLabel::ClickLabel(const QString &text, QWidget *parent) +{ + setText(text); + adjustSize(); +} + +ClickLabel::~ClickLabel() +{ +} + +void ClickLabel::mousePressEvent(QMouseEvent *event){ + if (event->button() == Qt::LeftButton) + emit clicked(); +// QLabel::mousePressEvent(event); +} diff --git a/kybackup/component/clicklabel.h b/kybackup/component/clicklabel.h new file mode 100644 index 0000000..3625b29 --- /dev/null +++ b/kybackup/component/clicklabel.h @@ -0,0 +1,41 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CLICKLABEL_H +#define CLICKLABEL_H + +#include +#include + +class ClickLabel : public QLabel +{ + Q_OBJECT + +public: + explicit ClickLabel(const QString &text, QWidget *parent = 0); + ~ClickLabel(); + +protected: + void mousePressEvent(QMouseEvent * event); + +signals: + void clicked(); +}; + +#endif // CLICKLABEL_H diff --git a/kybackup/component/hoverwidget.cpp b/kybackup/component/hoverwidget.cpp new file mode 100644 index 0000000..3499fd4 --- /dev/null +++ b/kybackup/component/hoverwidget.cpp @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "hoverwidget.h" + +#include +#include + +#include + +ResHoverWidget::ResHoverWidget(QString mname, QWidget *parent) : + QWidget(parent), + _name(mname) +{ + setAttribute(Qt::WA_DeleteOnClose); +} + +ResHoverWidget::~ResHoverWidget() +{ +} + +void ResHoverWidget::enterEvent(QEvent *event){ + emit enterWidget(_name); + + QWidget::enterEvent(event); +} + +void ResHoverWidget::leaveEvent(QEvent *event){ + emit leaveWidget(_name); + + QWidget::leaveEvent(event); +} + +void ResHoverWidget::mousePressEvent(QMouseEvent *event){ + + if (event->button() == Qt::LeftButton){ + emit widgetClicked(_name); + } + + QWidget::mousePressEvent(event); +} + +//子类化一个QWidget,为了能够使用样式表,则需要提供paintEvent事件。 +//这是因为QWidget的paintEvent()是空的,而样式表要通过paint被绘制到窗口中。 +void ResHoverWidget::paintEvent(QPaintEvent *event){ + Q_UNUSED(event) + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} diff --git a/kybackup/component/hoverwidget.h b/kybackup/component/hoverwidget.h new file mode 100644 index 0000000..56076d2 --- /dev/null +++ b/kybackup/component/hoverwidget.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef HOVERWIDGET_H +#define HOVERWIDGET_H + +#include +#include +#include + +class ResHoverWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ResHoverWidget(QString mname, QWidget *parent = 0); + ~ResHoverWidget(); + +public: + QString _name; + +protected: + virtual void enterEvent(QEvent * event); + virtual void leaveEvent(QEvent * event); + virtual void paintEvent(QPaintEvent * event); + + virtual void mousePressEvent(QMouseEvent * event); + +Q_SIGNALS: + void enterWidget(QString name); + void leaveWidget(QString name); + + void widgetClicked(QString name); +}; + +#endif // HOVERWIDGET_H diff --git a/kybackup/component/myiconbutton.cpp b/kybackup/component/myiconbutton.cpp new file mode 100644 index 0000000..45980b1 --- /dev/null +++ b/kybackup/component/myiconbutton.cpp @@ -0,0 +1,55 @@ +#include "myiconbutton.h" +#include +#include +#include +#include + +MyIconButton::MyIconButton(QWidget *parent) : + QPushButton(parent) +{ + m_iconButton = new QPushButton(this); + m_iconButton->setCheckable(false); + m_iconButton->setFixedSize(QSize(24, 24)); + m_iconButton->setFocusPolicy(Qt::NoFocus); + m_iconButton->setFlat(true); +// m_iconButton->setStyleSheet("QPushButton:checked{border: none;}" +// "QPushButton:!checked{border: none;}"); + + m_textLabel = new QLabel(this); + QSizePolicy textLabelPolicy = m_textLabel->sizePolicy(); + textLabelPolicy.setHorizontalPolicy(QSizePolicy::Fixed); + textLabelPolicy.setVerticalPolicy(QSizePolicy::Fixed); + m_textLabel->setSizePolicy(textLabelPolicy); + m_textLabel->setScaledContents(true); + + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->setContentsMargins(8, 0, 0, 0); + hLayout->addWidget(m_iconButton, Qt::AlignCenter); + hLayout->addWidget(m_textLabel); + hLayout->addStretch(); + setLayout(hLayout); + + connect(m_iconButton, &QPushButton::clicked, this, &QPushButton::click); +} + +MyIconButton::~MyIconButton() +{} + +void MyIconButton::setThemeIcon(const QString &themeIconName) +{ + m_themeIconName = themeIconName; + m_iconButton->setIcon(QIcon::fromTheme(themeIconName)); +} + +void MyIconButton::setDesplayText(const QString &text) +{ + m_textLabel->setFixedWidth(this->width() - 40); + QFontMetrics fontMetrics(m_textLabel->font()); + int fontSize = fontMetrics.width(text); + if (fontSize > m_textLabel->width()) { + m_textLabel->setText(fontMetrics.elidedText(text, Qt::ElideRight, m_textLabel->width())); + } else { + m_textLabel->setText(text); + } +} + diff --git a/kybackup/component/myiconbutton.h b/kybackup/component/myiconbutton.h new file mode 100644 index 0000000..d8cca2c --- /dev/null +++ b/kybackup/component/myiconbutton.h @@ -0,0 +1,24 @@ +#ifndef MYICONBUTTON_H +#define MYICONBUTTON_H + +#include +#include + +class MyIconButton : public QPushButton +{ + Q_OBJECT +public: + explicit MyIconButton(QWidget *parent = nullptr); + ~MyIconButton(); + + void setThemeIcon(const QString &themeIconName); + + void setDesplayText(const QString &text); + +private: + QPushButton *m_iconButton; + QLabel *m_textLabel; + QString m_themeIconName; +}; + +#endif // MYICONBUTTON_H diff --git a/kybackup/component/myiconlabel.cpp b/kybackup/component/myiconlabel.cpp new file mode 100644 index 0000000..f82754e --- /dev/null +++ b/kybackup/component/myiconlabel.cpp @@ -0,0 +1,48 @@ +#include "myiconlabel.h" +#include +#include + +MyIconLabel::MyIconLabel(QWidget *parent /*= nullptr*/) : + QLabel(parent) +{ + m_iconLabel = new QLabel(this); + // m_iconLabel->setFixedSize(QSize(24, 24)); + // border:1px solid black; + const QString greySheetStyle = "min-width: 36px; min-height: 36px;max-width:36px; max-height: 36px;border-radius: 18px; background:grey"; + m_iconLabel->setStyleSheet(greySheetStyle); + + m_textLabel = new QLabel(this); + QSizePolicy textLabelPolicy = m_textLabel->sizePolicy(); + textLabelPolicy.setHorizontalPolicy(QSizePolicy::Fixed); + textLabelPolicy.setVerticalPolicy(QSizePolicy::Fixed); + m_textLabel->setSizePolicy(textLabelPolicy); + m_textLabel->setScaledContents(true); + + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->setContentsMargins(8, 0, 0, 0); + hLayout->addWidget(m_iconLabel, Qt::AlignCenter); + hLayout->addWidget(m_textLabel); + hLayout->addStretch(); + setLayout(hLayout); +} + +MyIconLabel::~MyIconLabel() +{} + +void MyIconLabel::setThemeIcon(const QString &themeIconName) +{ + m_themeIconName = themeIconName; + m_textLabel->setPixmap(QIcon::fromTheme(themeIconName).pixmap(QSize(24,24))); +} + +void MyIconLabel::setDesplayText(const QString &text) +{ + m_textLabel->setFixedWidth(this->width() - 40); + QFontMetrics fontMetrics(m_textLabel->font()); + int fontSize = fontMetrics.width(text); + if (fontSize > m_textLabel->width()) { + m_textLabel->setText(fontMetrics.elidedText(text, Qt::ElideRight, m_textLabel->width())); + } else { + m_textLabel->setText(text); + } +} diff --git a/kybackup/component/myiconlabel.h b/kybackup/component/myiconlabel.h new file mode 100644 index 0000000..ce81657 --- /dev/null +++ b/kybackup/component/myiconlabel.h @@ -0,0 +1,23 @@ +#ifndef MYICONLABEL_H +#define MYICONLABEL_H + +#include + +class MyIconLabel : public QLabel +{ + Q_OBJECT +public: + explicit MyIconLabel(QWidget *parent = nullptr); + virtual ~MyIconLabel(); + + void setThemeIcon(const QString &themeIconName); + + void setDesplayText(const QString &text); + +private: + QLabel *m_iconLabel; + QLabel *m_textLabel; + QString m_themeIconName; +}; + +#endif // MYICONLABEL_H diff --git a/kybackup/functypeconverter.cpp b/kybackup/functypeconverter.cpp new file mode 100644 index 0000000..f839dd5 --- /dev/null +++ b/kybackup/functypeconverter.cpp @@ -0,0 +1,88 @@ + +#include "functypeconverter.h" + +FuncTypeConverter::FuncTypeConverter() +{ + m_metaModule = QMetaEnum::fromType(); +} + +FuncTypeConverter::~FuncTypeConverter() +{ +} + +QString FuncTypeConverter::keycodeTokeystring(int code){ + //未匹配到则返回空 + return m_metaModule.valueToKey(code); +} + +int FuncTypeConverter::keystringTokeycode(QString string){ + //QString to const char * + QByteArray ba = string.toUpper().toLocal8Bit(); const char * str = ba.data(); + return m_metaModule.keyToValue(str); +} + +/** + * @brief 功能编码对应的功能名称 + * @param code 功能编码 + * @return 功能名称 + */ +QString FuncTypeConverter::keycodeTokeyi18nstring(int code) +{ + QString nameString; + switch (code) { + case BACKUP_SYSTEM: + nameString = tr("System Backup"); + break; + case RESTORE_SYSTEM: + nameString = tr("System Recovery"); + break; + case BACKUP_DATA: + nameString = tr("Data Backup"); + break; + case RESTORE_DATA: + nameString = tr("Data Recovery"); + break; + case OPERATION_LOG: + nameString = tr("Log Records"); + break; + case GHOST_IMAGE: + nameString = tr("Ghost Image"); + break; + default: + break; + } + return nameString; +} + +/** + * @brief 功能编码对应的主题图标名称 + * @param code 功能编码 + * @return 主题图标名称 + */ +QString FuncTypeConverter::keycodeToThemeIconString(int code) +{ + QString nameString; + switch (code) { + case BACKUP_SYSTEM: + nameString = tr("ukui-bf-system-backup-symbolic"); + break; + case RESTORE_SYSTEM: + nameString = tr("ukui-bf-system-restore-symbolic"); + break; + case BACKUP_DATA: + nameString = tr("ukui-bf-data-backup-symbolic"); + break; + case RESTORE_DATA: + nameString = tr("ukui-bf-data-restore-symbolic"); + break; + case OPERATION_LOG: + nameString = tr("ukui-bf-operation-log-symbolic"); + break; + case GHOST_IMAGE: + nameString = tr("ukui-bf-ghost-mirror-symbolic"); + break; + default: + break; + } + return nameString; +} diff --git a/kybackup/functypeconverter.h b/kybackup/functypeconverter.h new file mode 100644 index 0000000..d551457 --- /dev/null +++ b/kybackup/functypeconverter.h @@ -0,0 +1,52 @@ +#ifndef FUNCTYPECONVERTER_H +#define FUNCTYPECONVERTER_H + +#include +#include + +class FuncTypeConverter : public QObject +{ + Q_OBJECT + +public: + explicit FuncTypeConverter(); + ~FuncTypeConverter(); + +public: + // 枚举值对应的枚举变量名 + QString keycodeTokeystring(int code); + // 枚举变量名对应的枚举值 + int keystringTokeycode(QString string); + /** + * @brief 功能编码对应的功能名称 + * @param code 功能编码 + * @return 功能名称 + */ + QString keycodeTokeyi18nstring(int code); + /** + * @brief 功能编码对应的主题图标名称 + * @param code 功能编码 + * @return 主题图标名称 + */ + QString keycodeToThemeIconString(int code); + +public: + QMetaEnum m_metaModule; + + /** + * @brief 主界面功能类型 + */ + enum FunType{ + BACKUP_SYSTEM, + RESTORE_SYSTEM, + BACKUP_DATA, + RESTORE_DATA, + OPERATION_LOG, + GHOST_IMAGE, + TOTALMODULES, + }; + Q_ENUM(FunType) + +}; + +#endif // FUNCTYPECONVERTER_H diff --git a/kybackup/gsettingswrapper.cpp b/kybackup/gsettingswrapper.cpp new file mode 100644 index 0000000..785096f --- /dev/null +++ b/kybackup/gsettingswrapper.cpp @@ -0,0 +1,42 @@ +/** + * @brief 由于当前仅用于主题变化时,备份还原工具的一些图标跟随变化,此处暂时先简单封装。后续根据使用情况另行优化。 + */ + +#include "gsettingswrapper.h" +#include +#include +#include + +#define FITTHEMEWINDOW "org.ukui.style" + +/** + * @brief 绑定连接UKui风格的主题 + * @param QWidget *, 跟随风格变化的窗体对象指针 + */ +void GSettingsWrapper::connectUkuiStyleSchema(QWidget * widgetPtr, QSize size) +{ + if (widgetPtr != nullptr && QGSettings::isSchemaInstalled(FITTHEMEWINDOW)) { + // c++11后能确保多线程并发场景的局部静态对象的唯一性 + static QGSettings *pGsettingThemeData = new QGSettings(FITTHEMEWINDOW); + + QObject::connect(pGsettingThemeData, &QGSettings::changed, [=](const QString &key) { + if (key == "iconThemeName") { + QIcon titleIcon = QIcon::fromTheme("yhkylin-backup-tools"); + if (widgetPtr->inherits("QLabel")) { + QLabel *labelPtr = qobject_cast(widgetPtr); + const QPixmap * pixmapPtr = labelPtr->pixmap(); + if (pixmapPtr != nullptr) { + //labelPtr->setPixmap(titleIcon.pixmap(titleIcon.actualSize(pixmapPtr->size()))); + labelPtr->setPixmap(titleIcon.pixmap(titleIcon.actualSize(size))); + } else { + labelPtr->setPixmap(titleIcon.pixmap(titleIcon.actualSize(QSize(24, 24)))); + } + } else { + widgetPtr->setWindowIcon(titleIcon); + } + } + }); + } +} + + diff --git a/kybackup/gsettingswrapper.h b/kybackup/gsettingswrapper.h new file mode 100644 index 0000000..1584027 --- /dev/null +++ b/kybackup/gsettingswrapper.h @@ -0,0 +1,21 @@ +#ifndef GSETTINGSWRAPPER_H +#define GSETTINGSWRAPPER_H + +#include +#include +class QWidget; + +/** + * @brief 由于当前仅用于主题变化时,备份还原工具的一些图标跟随变化,此处暂时先简单封装。后续根据使用情况另行优化。 + */ +class GSettingsWrapper +{ +public: + /** + * @brief 绑定连接UKui风格的主题 + * @param QWidget *, 跟随风格变化的窗体对象指针 + */ + static void connectUkuiStyleSchema(QWidget * labelPtr, QSize size = QSize(24, 24)); +}; + +#endif // GSETTINGSWRAPPER_H diff --git a/kybackup/imageutil.cpp b/kybackup/imageutil.cpp new file mode 100644 index 0000000..034db6d --- /dev/null +++ b/kybackup/imageutil.cpp @@ -0,0 +1,62 @@ +#include "imageutil.h" + +#include +#include + +const QPixmap ImageUtil::loadSvg(const QString &path, const QString color, int size) +{ + int origSize = size; + const auto ratio = qApp->devicePixelRatio(); + if ( 2 == ratio) { + size += origSize; + } else if (3 == ratio) { + size += origSize; + } + QPixmap pixmap(size, size); + QSvgRenderer renderer(path); + pixmap.fill(Qt::transparent); + + QPainter painter; + painter.begin(&pixmap); + renderer.render(&painter); + painter.end(); + + pixmap.setDevicePixelRatio(ratio); + return drawSymbolicColoredPixmap(pixmap, color); +} + +QPixmap ImageUtil::drawSymbolicColoredPixmap(const QPixmap &source, QString cgColor) +{ + QImage img = source.toImage(); + for (int x = 0; x < img.width(); x++) { + for (int y = 0; y < img.height(); y++) { + auto color = img.pixelColor(x, y); + if (color.alpha() > 0) { + if ( "white" == cgColor) { + color.setRed(255); + color.setGreen(255); + color.setBlue(255); + img.setPixelColor(x, y, color); + } else if( "black" == cgColor) { + color.setRed(0); + color.setGreen(0); + color.setBlue(0); + img.setPixelColor(x, y, color); + } else if ("gray"== cgColor) { + color.setRed(152); + color.setGreen(163); + color.setBlue(164); + img.setPixelColor(x, y, color); + } else if ("blue" == cgColor){ + color.setRed(61); + color.setGreen(107); + color.setBlue(229); + img.setPixelColor(x, y, color); + } else { + return source; + } + } + } + } + return QPixmap::fromImage(img); +} diff --git a/kybackup/imageutil.h b/kybackup/imageutil.h new file mode 100644 index 0000000..7b8e154 --- /dev/null +++ b/kybackup/imageutil.h @@ -0,0 +1,14 @@ +#ifndef IMAGEUTIL_H +#define IMAGEUTIL_H + +#include +#include + +class ImageUtil +{ +public: + static const QPixmap loadSvg(const QString &path, const QString color, int size = 16); + static QPixmap drawSymbolicColoredPixmap(const QPixmap &source, QString cgColor); +}; + +#endif // IMAGEUTIL_H diff --git a/kybackup/kybackup.pro b/kybackup/kybackup.pro index 0619882..bfb7206 100644 --- a/kybackup/kybackup.pro +++ b/kybackup/kybackup.pro @@ -1,10 +1,22 @@ -QT += core gui +QT += core gui svg QT += dbus +QT += network + +# 适配窗口管理器圆角阴影 +QT += KWindowSystem x11extras greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 +# 适配窗口管理器圆角阴影 +LIBS +=-lpthread +LIBS +=-lX11 + +# 配置gsettings +CONFIG += link_pkgconfig +PKGCONFIG += gsettings-qt + # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the @@ -17,17 +29,59 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 HEADERS += \ + ../common/mydefine.h \ + ../common/mylittleparse.h \ + ../common/utils.h \ backup_manager_interface.h \ - maindialog.h + component/clicklabel.h \ + component/hoverwidget.h \ + component/myiconbutton.h \ + component/myiconlabel.h \ + functypeconverter.h \ + gsettingswrapper.h \ + imageutil.h \ + leftsiderbarwidget.h \ + maindialog.h \ + module/systembackup.h \ + qtsingleapplication/qtlocalpeer.h \ + qtsingleapplication/qtlockedfile.h \ + qtsingleapplication/qtsingleapplication.h \ + xatom-helper.h SOURCES += \ + ../common/mydefine.cpp \ + ../common/mylittleparse.cpp \ + ../common/utils.cpp \ backup_manager_interface.cpp \ + component/clicklabel.cpp \ + component/hoverwidget.cpp \ + component/myiconbutton.cpp \ + component/myiconlabel.cpp \ + functypeconverter.cpp \ + gsettingswrapper.cpp \ + imageutil.cpp \ + leftsiderbarwidget.cpp \ main.cpp \ - maindialog.cpp + maindialog.cpp \ + module/systembackup.cpp \ + qtsingleapplication/qtlocalpeer.cpp \ + qtsingleapplication/qtlockedfile.cpp \ + qtsingleapplication/qtlockedfile_unix.cpp \ + qtsingleapplication/qtsingleapplication.cpp \ + xatom-helper.cpp FORMS += \ maindialog.ui +TRANSLATIONS += qt_zh_CN.ts + +# !system(lrelease qt_zh_CN.ts): error("Failed to generate qm") +# system(cp qt_zh_CN.qm images) + +RESOURCES += \ + app.qrc + + # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin diff --git a/kybackup/leftsiderbarwidget.cpp b/kybackup/leftsiderbarwidget.cpp new file mode 100644 index 0000000..31ea723 --- /dev/null +++ b/kybackup/leftsiderbarwidget.cpp @@ -0,0 +1,92 @@ +#include "leftsiderbarwidget.h" +#include +#include +#include +#include +#include "../common/mydefine.h" +#include "component/myiconbutton.h" + +LeftsiderbarWidget::LeftsiderbarWidget(QWidget *parent, StartMode mode) + : QWidget(parent) +{ + m_leftSideBarVLayout = new QVBoxLayout(); + m_leftSideBarVLayout->setObjectName(QString::fromUtf8("m_leftSideBarVLayout")); + m_leftSideBarVLayout->setContentsMargins(5,0,0,0); + setLayout(m_leftSideBarVLayout); + m_leftSideBarVLayout->setSpacing(5); + + QWidget *titleWidget = new QWidget(this); + m_leftSideBarVLayout->addWidget(titleWidget); + + QHBoxLayout * titleLayout = new QHBoxLayout(); + m_mTitleIcon = new QLabel(); + m_titleLabel = new QLabel(tr("Backup and Restore")); + titleWidget->setLayout(titleLayout); + titleLayout->addWidget(m_mTitleIcon); + titleLayout->addWidget(m_titleLabel); + + m_mTitleIcon->setFixedSize(24, 24); + QIcon titleIcon = QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS); + m_mTitleIcon->setPixmap(titleIcon.pixmap(titleIcon.actualSize(QSize(24, 24)))); + m_titleLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + m_leftSideBarVLayout->addSpacing(10); + + // 功能列表 + int funcNum = FuncTypeConverter::FunType::TOTALMODULES; + if (StartMode::livecd == mode) + funcNum = 2; + m_funcGroup = new QButtonGroup(this); + FuncTypeConverter kvConverter; + for (int type = 0; type < funcNum; ++type) { + QString themeIconName = kvConverter.keycodeToThemeIconString(type); + QString mnamei18nString = kvConverter.keycodeTokeyi18nstring(type); //设置TEXT + + + MyIconButton *funcButton = new MyIconButton(this); + QString btnName = "btn" + QString::number(type + 1); + funcButton->setObjectName(btnName); + funcButton->setFixedSize(180, 40); + funcButton->setDesplayText(mnamei18nString); + funcButton->setThemeIcon(themeIconName); + funcButton->setToolTip(mnamei18nString); + funcButton->setCheckable(true); + // 設置無邊框,跟隨背景色 + funcButton->setFlat(true); + // 設置了setStyleSheet,不能再跟隨主題,捨棄此種方式 +// funcButton->setStyleSheet("QPushButton:hover{background-color: rgba(55,144,250,0.30);border-radius: 4px;}" +// "QPushButton:checked{background-color: palette(highlight);border-radius: 4px;}" +// "QPushButton:!checked{border: none;}"); + m_funcGroup->addButton(funcButton, type); + + + m_leftSideBarVLayout->addWidget(funcButton); + } + + + m_leftSideBarVLayout->addSpacing(8); + + m_leftSideBarVLayout->addStretch(); +} + +LeftsiderbarWidget::~LeftsiderbarWidget() +{ + +} + + +void LeftsiderbarWidget::paintEvent(QPaintEvent *event) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + p.setPen(Qt::NoPen); + QColor color = palette().color(QPalette::Window); + color.setAlpha(transparency); + QPalette pal(this->palette()); + pal.setColor(QPalette::Window,QColor(color)); + this->setPalette(pal); + QBrush brush =QBrush(color); + p.setBrush(brush); + p.drawRoundedRect(opt.rect,0,0); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} diff --git a/kybackup/leftsiderbarwidget.h b/kybackup/leftsiderbarwidget.h new file mode 100644 index 0000000..2b04049 --- /dev/null +++ b/kybackup/leftsiderbarwidget.h @@ -0,0 +1,34 @@ +#ifndef LEFTSIDERBARWIDGET_H +#define LEFTSIDERBARWIDGET_H + +#include +#include +#include +#include +#include +#include +#include "functypeconverter.h" + + +class LeftsiderbarWidget : public QWidget +{ + Q_OBJECT +public: + // 启动模式,不同模式启动时展示的功能模块不同 + enum StartMode { + normal, + livecd + }; + LeftsiderbarWidget(QWidget *parent = nullptr, StartMode mode = StartMode::normal); + ~LeftsiderbarWidget(); + void paintEvent(QPaintEvent *event); +private: + int transparency = 0; + + QVBoxLayout *m_leftSideBarVLayout = nullptr; + QLabel *m_mTitleIcon = nullptr; + QLabel *m_titleLabel = nullptr; + QButtonGroup *m_funcGroup = nullptr; +}; + +#endif // LEFTSIDERBARWIDGET_H diff --git a/kybackup/main.cpp b/kybackup/main.cpp index 3f69fa1..9426980 100644 --- a/kybackup/main.cpp +++ b/kybackup/main.cpp @@ -1,11 +1,196 @@ #include "maindialog.h" #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "qtsingleapplication/qtsingleapplication.h" +#include "../common/utils.h" +#include "xatom-helper.h" + +// 声明 +void initApp(QApplication& a); +bool isManager(); +void centerToScreen(QWidget* widget); int main(int argc, char *argv[]) { - QApplication a(argc, argv); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); +#endif + + QtSingleApplication a ("kybackup",argc, argv); + initApp(a); + + // 当前只支持管理员用户使用备份还原工具 + if (!isManager()) { + QMessageBox box(QMessageBox::Warning, QObject::tr("Warning"), QObject::tr("This tool can only be used by administrator.")); + box.setStandardButtons(QMessageBox::Ok); + box.setButtonText(QMessageBox::Ok, QObject::tr("OK")); + QIcon titleIcon = QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS); + box.setWindowIcon(titleIcon); + box.exec(); + return EXIT_FAILURE; + } + + if (a.isRunning()) { + QString strUid = QString::number(getuid()); + QString ack = a.sendMessage(strUid, 3000); + + if (strUid != ack) { + QMessageBox box(QMessageBox::Critical, QObject::tr("Error"), QObject::tr("Another user had opened kybackup, you can not start it again.")); + box.setStandardButtons(QMessageBox::Ok); + box.setButtonText(QMessageBox::Ok, QObject::tr("OK")); + QIcon titleIcon = QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS); + box.setWindowIcon(titleIcon); + box.exec(); + } + + return EXIT_SUCCESS; + } + MainDialog w; + // 居中窗口 + centerToScreen(&w); + // 窗口背景透明化;setWindowOpacity可使得窗口及其上控件都透明或半透明-w.setWindowOpacity(0.7); + w.setAttribute(Qt::WA_TranslucentBackground); + // 使得窗口无边框 + // w.setWindowFlag(Qt::FramelessWindowHint); + // 指示窗口管理器模糊给定窗口后面指定区域的背景(毛玻璃化背景) + KWindowEffects::enableBlurBehind(w.winId(),true); + + // 添加窗管协议 + MotifWmHints hints; + hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; + hints.functions = MWM_FUNC_ALL; + hints.decorations = MWM_DECOR_BORDER; + XAtomHelper::getInstance()->setWindowMotifHint(w.winId(), hints); + + a.setWindowIcon(QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS)); + a.setActivationWindow(&w, true); + + //如果是第一个实例,则绑定,方便下次调用 + QObject::connect(&a,SIGNAL(messageReceived(const QString&)),&w,SLOT(sltMessageReceived(const QString&))); + w.show(); return a.exec(); } + +/** + * @brief 应用初始化 + * @param a + * @note new出来的两个QTranslator不用删除,需要整个生命周期内有效,应用结束由操作系统收回即可 + */ +void initApp(QApplication& a) +{ + //前端向后端传递QString参数,若参数中含有中文则保证不会乱码 + QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); + + //区分中英文 + QString locale = QLocale::system().name(); + //QT自身标准的翻译 +#ifndef QT_NO_TRANSLATION + QString translatorFileName = QLatin1String("qt_"); + translatorFileName += locale; + QTranslator *selfTransOfQt = new QTranslator(); + if (selfTransOfQt->load(translatorFileName, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + a.installTranslator(selfTransOfQt); + else + qDebug() << "load qt translator file failed!"; +#endif + + //应用内的翻译 + QTranslator *translator = new QTranslator(); + if (locale == "zh_CN") { + //中文需要翻译 + if (!translator->load(":/qm/images/qt_zh_CN.qm")) //qtcreator启动后看到在资源目录下 + qDebug() << "load translator file failed!"; + else + a.installTranslator(translator); + } + + // 命令行参数 + QCoreApplication::setApplicationName(QObject::tr("kybackup")); + QCoreApplication::setApplicationVersion("4.0.14"); + + /* + QCommandLineParser parser; + parser.setApplicationDescription("kybackup helper"); + parser.addHelpOption(); + parser.addVersionOption(); + // 启动后进入的页面 + QCommandLineOption functionOption(QStringList() << "r" << "restore", QCoreApplication::translate("restore", "system restore")); + parser.addOption(functionOption); + parser.process(a); + bool isRestore = parser.isSet(functionOption); + */ + + QString qsAppPath = QCoreApplication::applicationDirPath(); + Utils::initSysRootPath(qsAppPath); +} + +/** + * @brief 判断启动账号是否管理员账号 + * @return true-相当于是;false-不是 + */ +bool isManager() +{ + QString rootPath = Utils::getSysRootPath(); + // 只正常启动程序时需校验是否管理员账号启动 + if ("/" != rootPath) + return true; + + uid_t uid = getuid(); + // root用户 + if (0 == uid) + return true; + + QString sid = QString::number(uid); + QString userObject = "/org/freedesktop/Accounts/User" + sid; + + // 创建QDBusInterface + QDBusInterface iface("org.freedesktop.Accounts", userObject, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); + if (!iface.isValid()) { + qDebug() << qPrintable(QDBusConnection::systemBus().lastError().message()); + exit(1); + } + + int result = 0; + QDBusReply reply = iface.call("Get", QString("org.freedesktop.Accounts.User"), QString("AccountType")); + if (reply.isValid()) { + QVariant val = reply.value().variant(); + result = val.toInt(); + } + + return 0 == result ? false : true; +} + +/** + * @brief 居中显示窗口 + * @param widget + */ +void centerToScreen(QWidget* widget) +{ + if (!widget) + return; + QDesktopWidget* m = QApplication::desktop(); + // QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos())); + QRect desk_rect = m->screenGeometry(widget); + int desk_x = desk_rect.width(); + int desk_y = desk_rect.height(); + int x = widget->width(); + int y = widget->height(); + widget->move(desk_x / 2 - x / 2 + desk_rect.left(), desk_y / 2 - y / 2 + desk_rect.top()); +} diff --git a/kybackup/maindialog.cpp b/kybackup/maindialog.cpp index 181884a..dc1bf45 100644 --- a/kybackup/maindialog.cpp +++ b/kybackup/maindialog.cpp @@ -1,11 +1,21 @@ #include "maindialog.h" #include "ui_maindialog.h" +#include +#include +#include +#include + +#include "../common/mydefine.h" +#include "module/systembackup.h" + MainDialog::MainDialog(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainDialog) { ui->setupUi(this); + initUI(); + initConnect(); } MainDialog::~MainDialog() @@ -13,3 +23,180 @@ MainDialog::~MainDialog() delete ui; } +void MainDialog::initUI() +{ + m_totalHLayout = new QHBoxLayout(this); + m_totalHLayout->setSpacing(0); + m_totalHLayout->setObjectName(QString::fromUtf8("m_totalHLayout")); + m_totalHLayout->setContentsMargins(0, 0, 0, 0); + this->setLayout(m_totalHLayout); + + m_leftSiderBarWidget = new LeftsiderbarWidget(ui->centralwidget); + m_leftSiderBarWidget->setObjectName(QString::fromUtf8("m_leftSiderBarWidget")); + m_leftSiderBarWidget->setGeometry(QRect(0, 0, 200, 640)); + + m_totalHLayout->addWidget(m_leftSiderBarWidget); + + m_rightVLayout = new QVBoxLayout(); + m_rightVLayout->setObjectName(QString::fromUtf8("m_rightVLayout")); + m_rightVLayout->setContentsMargins(0, 0, 0, 0); + + m_titleWidget = new QWidget(ui->centralwidget); + m_titleWidget->setObjectName(QString::fromUtf8("m_titleWidget")); + m_titleWidget->setGeometry(QRect(201, 0, 760, 40)); + m_rightVLayout->addWidget(m_titleWidget); + + // m_stackedWidget = new QStackedWidget(ui->centralwidget); + m_stackedWidget = new SystemBackup(ui->centralwidget); + m_stackedWidget->setObjectName(QString::fromUtf8("m_stackedWidget")); + m_stackedWidget->setGeometry(QRect(201, 40, 760, 600)); + m_rightVLayout->addWidget(m_stackedWidget); + + m_totalHLayout->addLayout(m_rightVLayout); + + initTileBar(); + initStyleSheet(); +} + +void MainDialog::initTileBar() +{ + m_titleLayout = new QHBoxLayout; + m_titleWidget->setLayout(m_titleLayout); + m_titleLayout->setContentsMargins(8, 4, 4, 0); + m_titleLayout->setSpacing(0); + + m_menuOptionBtn = new QToolButton(m_titleWidget); + m_minBtn = new QPushButton(m_titleWidget); + m_closeBtn = new QPushButton(m_titleWidget); + + m_menuOptionBtn->setToolTip(tr("Main menu")); + m_minBtn->setToolTip(tr("Minimize")); + m_closeBtn->setToolTip(tr("Close")); + + m_menuOptionBtn->setFixedSize(30, 30); + m_minBtn->setFixedSize(30, 30); + m_closeBtn->setFixedSize(30, 30); + + QMenu* backupMain = new QMenu(this); + backupMain->setObjectName("mainMenu"); + m_menuOptionBtn->setMenu(backupMain); + + QAction* backupTheme = new QAction(tr("Theme"),this); + backupMain->addAction(backupTheme); + QMenu* selectTheme = new QMenu(this); + selectTheme->setObjectName("selectTheme"); + backupTheme->setMenu(selectTheme); + QAction* defaultTheme = new QAction(tr("DefaultTheme"),this); + selectTheme->addAction(defaultTheme); + QAction* darkTheme = new QAction(tr("DarkTheme"),this); + selectTheme->addAction(darkTheme); + QAction* lightTheme = new QAction(tr("LightTheme"),this); + selectTheme->addAction(lightTheme); + + m_backupHelp = new QAction(tr("Help"),this); + backupMain->addAction(m_backupHelp); + m_backupAbout = new QAction(tr("About"),this); + backupMain->addAction(m_backupAbout); + m_backupExit = new QAction(tr("Exit"),this); + backupMain->addAction(m_backupExit); + + m_titleLayout->addStretch(); + m_titleLayout->addWidget(m_menuOptionBtn); + m_titleLayout->addSpacing(4); + m_titleLayout->addWidget(m_minBtn); + m_titleLayout->addSpacing(4); + m_titleLayout->addWidget(m_closeBtn); +} + +void MainDialog::initStyleSheet() +{ + // 主窗口 + // qApp->setWindowIcon(QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS)); + this->setWindowTitle(tr("Backup and Restore")); + + // 工作区(此处代码加不加一个样,注释掉,留着学习,知道有这么回事) + //ui->centralwidget->setStyleSheet("QWidget#centralWidget{background: palette(base); border-radius: 6px;}"); + //ui->centralwidget->setAttribute(Qt::WA_TranslucentBackground); + + // 右侧title + // setStyleSheet方式設置樣式不能跟隨主題 + // m_titleWidget->setStyleSheet("QWidget#m_titleWidget{background-color:palette(base)}"); + m_titleWidget->setAutoFillBackground(true); + QPalette palette = m_titleWidget->palette(); + palette.setColor(QPalette::Background, palette.color(QPalette::Base)); + m_titleWidget->setPalette(palette); + + // m_menuOptionBtn->setStyleSheet("background-color: palette(base);"); + m_menuOptionBtn->setProperty("isWindowButton", 0x1); + m_menuOptionBtn->setProperty("useIconHighlightEffect", 0x2); + m_menuOptionBtn->setIcon(QIcon::fromTheme("open-menu-symbolic")); + m_menuOptionBtn->setAutoRaise(true); + m_menuOptionBtn->setPopupMode(QToolButton::InstantPopup); + // m_menuOptionBtn->setProperty("setIconHighlightEffectDefaultColor", m_closeBtn->palette().color(QPalette::Active, QPalette::Base)); + + m_minBtn->setProperty("isWindowButton", 0x1); + m_minBtn->setProperty("useIconHighlightEffect", 0x2); + m_minBtn->setFlat(true); + m_minBtn->setIcon(QIcon::fromTheme("window-minimize-symbolic")); + // m_minBtn->setProperty("setIconHighlightEffectDefaultColor", m_closeBtn->palette().color(QPalette::Active, QPalette::Base)); + + m_closeBtn->setProperty("isWindowButton", 0x2); + m_closeBtn->setProperty("useIconHighlightEffect", 0x8); + m_closeBtn->setFlat(true); + m_closeBtn->setIcon(QIcon::fromTheme("window-close-symbolic")); + // m_closeBtn->setProperty("setIconHighlightEffectDefaultColor", m_closeBtn->palette().color(QPalette::Active, QPalette::Base)); + + + // 右侧内容区域 + // m_stackedWidget->setStyleSheet("QStackedWidget#m_stackedWidget{background: palette(base); border-bottom-left-radius: 6px; border-bottom-right-radius: 6px;}"); + m_stackedWidget->setAutoFillBackground(true); + palette = m_stackedWidget->palette(); + palette.setColor(QPalette::Background, palette.color(QPalette::Base)); + m_stackedWidget->setPalette(palette); +} + +void MainDialog::initConnect() +{ + // 标题栏右侧按钮区域 + // 退出 + connect(m_backupExit, &QAction::triggered, this, &MainDialog::closeBtn); + + // 关于 + connect(m_backupAbout, &QAction::triggered, this, [=] { + // UkccAbout *ukcc = new UkccAbout(this); + // ukcc->exec(); + }); + + connect(m_backupHelp, &QAction::triggered, this, [=] { + QProcess process(this); + process.startDetached("kylin-user-guide -A kybackup"); + }); + + //最小化按钮 + connect(m_minBtn, &QPushButton::clicked, this, &MainDialog::showMinimized); + + //关闭按钮 + connect(m_closeBtn, &QPushButton::clicked, this, &MainDialog::closeBtn); +} + +/** + * @brief 多例启动信息槽 + * @param msg 信息,里面存放新启动实例的账户id + */ +void MainDialog::sltMessageReceived(const QString &msg) +{ + QString user = QString::number(getuid()); + if (msg == user) { +// this->setWindowFlag(Qt::WindowStaysOnTopHint,true); +// this->setWindowFlag(Qt::WindowStaysOnTopHint,false); + KWindowSystem::forceActiveWindow(this->winId()); + this->show(); + } +} + +void MainDialog::closeBtn() +{ + this->close(); + qApp->quit(); +} + diff --git a/kybackup/maindialog.h b/kybackup/maindialog.h index 6ab6e2b..cf993f3 100644 --- a/kybackup/maindialog.h +++ b/kybackup/maindialog.h @@ -2,6 +2,12 @@ #define MAINDIALOG_H #include +#include +#include +#include +#include +#include +#include "leftsiderbarwidget.h" QT_BEGIN_NAMESPACE namespace Ui { class MainDialog; } @@ -15,7 +21,35 @@ public: MainDialog(QWidget *parent = nullptr); ~MainDialog(); +public slots: + void sltMessageReceived(const QString &msg); + void closeBtn(); + private: + void initUI(); + void initTileBar(); + void initStyleSheet(); + void initConnect(); +private: + // 总体布局部分 + QHBoxLayout *m_totalHLayout = nullptr; + LeftsiderbarWidget *m_leftSiderBarWidget = nullptr; + QVBoxLayout *m_rightVLayout = nullptr; + QWidget *m_titleWidget = nullptr; + QStackedWidget *m_stackedWidget = nullptr; + + // 标题栏部分 + QHBoxLayout *m_titleLayout = nullptr; + QToolButton *m_menuOptionBtn = nullptr; + QPushButton *m_minBtn = nullptr; + QPushButton *m_closeBtn = nullptr; + + QAction *m_backupHelp = nullptr; + QAction *m_backupAbout = nullptr; + QAction *m_backupExit = nullptr; + + // 右侧内容展示部分 + Ui::MainDialog *ui; }; #endif // MAINDIALOG_H diff --git a/kybackup/maindialog.ui b/kybackup/maindialog.ui index 97e9edd..b22059b 100644 --- a/kybackup/maindialog.ui +++ b/kybackup/maindialog.ui @@ -6,16 +6,32 @@ 0 0 - 800 - 600 + 960 + 640 + + + 0 + 0 + + + + + 960 + 640 + + + + + 960 + 640 + + - MainDialog + - - diff --git a/kybackup/module/systembackup.cpp b/kybackup/module/systembackup.cpp new file mode 100644 index 0000000..82d1b12 --- /dev/null +++ b/kybackup/module/systembackup.cpp @@ -0,0 +1,80 @@ +#include "systembackup.h" +#include +#include + +#include "component/myiconlabel.h" + +SystemBackup::SystemBackup(QWidget *parent /*= nullptr*/) : + QStackedWidget(parent) +{ + initFirstWidget(); +} + +SystemBackup::~SystemBackup() +{} + +void SystemBackup::initFirstWidget() +{ + QWidget *first = new QWidget; + + QLabel *imageBackup_firstPage = new QLabel(first); + imageBackup_firstPage->setGeometry(421, 120, 300, 326); + QPixmap pixmap(":/images/system_backup.png"); + imageBackup_firstPage->setPixmap(pixmap); + imageBackup_firstPage->setScaledContents(true); + + QLabel *labelBackup_firstPage = new QLabel(tr("System Backup"), first); + // labelBackup_firstPage->setGeometry(40, 120, 300, 48); + labelBackup_firstPage->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + labelBackup_firstPage->setFixedHeight(48); + labelBackup_firstPage->move(41, 120); + // 默认水平左对齐,上下居中对齐;故不需要设置 + // labelBackup_firstPage->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + // labelBackup_firstPage->setText(tr("System Backup")); + QFont font; + font.setBold(true); + font.setPixelSize(36); + labelBackup_firstPage->setFont(font); + labelBackup_firstPage->adjustSize(); + labelBackup_firstPage->setAttribute(Qt::WA_TranslucentBackground); + + QLabel *labelNote_firstPage = new QLabel(first); + labelNote_firstPage->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + labelNote_firstPage->setFixedHeight(24); + labelNote_firstPage->move(41, 180); + labelNote_firstPage->setText(tr("Can be restored when files are damaged or lost")); + font.setBold(false); + font.setPixelSize(18); + labelNote_firstPage->setFont(font); + labelNote_firstPage->adjustSize(); + labelNote_firstPage->setAttribute(Qt::WA_TranslucentBackground); + + MyIconLabel *iconMultiBackup_firstPage = new MyIconLabel(first); + iconMultiBackup_firstPage->setGeometry(41, 244, 150, 36); + iconMultiBackup_firstPage->setThemeIcon("ukui-bf-many-spot-symbolic"); + iconMultiBackup_firstPage->setDesplayText(tr("Multi-Spot")); + iconMultiBackup_firstPage->setEnabled(false); + + MyIconLabel *iconSmallSize_firstPage = new MyIconLabel(first); + iconSmallSize_firstPage->setGeometry(201, 244, 150, 36); + iconSmallSize_firstPage->setThemeIcon("ukui-bf-many-spot-symbolic"); + iconSmallSize_firstPage->setDesplayText(tr("Small Size")); + iconSmallSize_firstPage->setEnabled(false); + + MyIconLabel *iconSecurity_firstPage = new MyIconLabel(first); + iconSecurity_firstPage->setGeometry(41, 296, 150, 36); + iconSecurity_firstPage->setThemeIcon("ukui-bf-many-spot-symbolic"); + iconSecurity_firstPage->setDesplayText(tr("Security")); + iconSecurity_firstPage->setEnabled(false); + + MyIconLabel *iconSimple_firstPage = new MyIconLabel(first); + iconSimple_firstPage->setGeometry(201, 296, 150, 36); + iconSimple_firstPage->setThemeIcon("ukui-bf-many-spot-symbolic"); + iconSimple_firstPage->setDesplayText(tr("Simple")); + iconSimple_firstPage->setEnabled(false); + + QPushButton *beginBackup = new QPushButton(this); + // beginBackup->setGeometry(); + + addWidget(first); +} diff --git a/kybackup/module/systembackup.h b/kybackup/module/systembackup.h new file mode 100644 index 0000000..6ba4bfc --- /dev/null +++ b/kybackup/module/systembackup.h @@ -0,0 +1,17 @@ +#ifndef SYSTEMBACKUP_H +#define SYSTEMBACKUP_H + +#include + +class SystemBackup : public QStackedWidget +{ + Q_OBJECT +public: + explicit SystemBackup(QWidget *parent = nullptr); + ~SystemBackup(); + +private: + void initFirstWidget(); +}; + +#endif // SYSTEMBACKUP_H diff --git a/kybackup/qtsingleapplication/qtlocalpeer.cpp b/kybackup/qtsingleapplication/qtlocalpeer.cpp new file mode 100644 index 0000000..a2bcb39 --- /dev/null +++ b/kybackup/qtsingleapplication/qtlocalpeer.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qtlocalpeer.h" +#include +#include +#include + +#if defined(Q_OS_WIN) +#include +#include +typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); +static PProcessIdToSessionId pProcessIdToSessionId = 0; +#endif +#if defined(Q_OS_UNIX) +#include +#include +#include +#include +#include +#endif + +namespace QtLP_Private { +#include "qtlockedfile.cpp" +#if defined(Q_OS_WIN) +#include "qtlockedfile_win.cpp" +#else +#include "qtlockedfile_unix.cpp" +#endif +} + +const char* QtLocalPeer::ack = "uid:"; + +QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) + : QObject(parent), id(appId) +{ + QString prefix = id; + if (id.isEmpty()) { + id = QCoreApplication::applicationFilePath(); +#if defined(Q_OS_WIN) + id = id.toLower(); +#endif + prefix = id.section(QLatin1Char('/'), -1); + } + prefix.remove(QRegExp("[^a-zA-Z]")); + // prefix.truncate(6); + + QByteArray idc = id.toUtf8(); + quint16 idNum = qChecksum(idc.constData(), idc.size()); + socketName = QLatin1String("qtsingleapp-") + prefix + + QLatin1Char('-') + QString::number(idNum, 16); + +#if defined(Q_OS_WIN) + if (!pProcessIdToSessionId) { + QLibrary lib("kernel32"); + pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); + } + if (pProcessIdToSessionId) { + DWORD sessionId = 0; + pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); + socketName += QLatin1Char('-') + QString::number(sessionId, 16); + } +#else + // socketName += QLatin1Char('-') + QString::number(::getuid(), 16); +#endif + + server = new QLocalServer(this); + QString lockName = QDir(QDir::tempPath()).absolutePath() + + QLatin1Char('/') + socketName + + QLatin1String("-lockfile"); + createFile(lockName); + lockFile.setFileName(lockName); + lockFile.open(QIODevice::ReadWrite); +} + +bool QtLocalPeer::createFile(const QString& fileName) +{ +#if defined(Q_OS_UNIX) + QFile file(fileName); + if (file.exists()) { + chmod(fileName.toStdString().data(), S_IRWXU | S_IRWXG | S_IRWXO); + } + + int lock_file_fd = ::open(fileName.toStdString().data(), O_CREAT | O_RDWR, 0666); + if (0 > lock_file_fd) { + return false; + } + fchmod(lock_file_fd, S_IRWXU | S_IRWXG | S_IRWXO); + ::close(lock_file_fd); +#endif + return true; +} + +bool QtLocalPeer::isClient() +{ + if (lockFile.isLocked()) + return false; + + if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) + return true; + + bool res = server->listen(socketName); +#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) + // ### Workaround + if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { + QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName); + res = server->listen(socketName); + } +#endif + if (!res) + qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); + QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection())); + return false; +} + + +QString QtLocalPeer::sendMessage(const QString &message, int timeout) +{ + if (!isClient()) + return ""; + + QLocalSocket socket; + bool connOk = false; + for(int i = 0; i < 2; i++) { + // Try twice, in case the other instance is just starting up + socket.connectToServer(socketName); + connOk = socket.waitForConnected(timeout/2); + if (connOk || i) + break; + int ms = 250; +#if defined(Q_OS_WIN) + Sleep(DWORD(ms)); +#else + struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; + nanosleep(&ts, NULL); +#endif + } + if (!connOk) + return ""; + + QByteArray uMsg(message.toUtf8()); + QDataStream ds(&socket); + ds.writeBytes(uMsg.constData(), uMsg.size()); + bool res = socket.waitForBytesWritten(timeout); + QByteArray ackMsg; + if (res) { + res &= socket.waitForReadyRead(timeout); // wait for ack + if (res) { + // res &= (socket.read(qstrlen(ack)) == ack); + ackMsg = socket.readAll(); + } + } + socket.disconnectFromServer(); + return QString::fromUtf8(ackMsg); +} + + +void QtLocalPeer::receiveConnection() +{ + QLocalSocket* socket = server->nextPendingConnection(); + if (!socket) + return; + + while (socket->bytesAvailable() < (int)sizeof(quint32)) + socket->waitForReadyRead(); + QDataStream ds(socket); + QByteArray uMsg; + quint32 remaining; + ds >> remaining; + uMsg.resize(remaining); + int got = 0; + char* uMsgBuf = uMsg.data(); + do { + got = ds.readRawData(uMsgBuf, remaining); + remaining -= got; + uMsgBuf += got; + } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); + if (got < 0) { + qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); + delete socket; + return; + } + QString message(QString::fromUtf8(uMsg)); + // socket->write(ack, qstrlen(ack)); + QString sendMsg = QString::number(::getuid()); + QByteArray msg = sendMsg.toUtf8(); + socket->write(msg); + socket->waitForBytesWritten(1000); + socket->waitForDisconnected(1000); // make sure client reads ack + delete socket; + emit messageReceived(message); //### (might take a long time to return) +} diff --git a/kybackup/qtsingleapplication/qtlocalpeer.h b/kybackup/qtsingleapplication/qtlocalpeer.h new file mode 100644 index 0000000..acc01e8 --- /dev/null +++ b/kybackup/qtsingleapplication/qtlocalpeer.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTLOCALPEER_H +#define QTLOCALPEER_H + +#include +#include +#include + +#include "qtlockedfile.h" + +class QtLocalPeer : public QObject +{ + Q_OBJECT + +public: + QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); + bool isClient(); + QString sendMessage(const QString &message, int timeout); + QString applicationId() const + { return id; } + +Q_SIGNALS: + void messageReceived(const QString &message); + +protected Q_SLOTS: + void receiveConnection(); + +protected: + bool createFile(const QString& fileName); + + QString id; + QString socketName; + QLocalServer* server; + QtLP_Private::QtLockedFile lockFile; + +private: + static const char* ack; +}; + +#endif // QTLOCALPEER_H diff --git a/kybackup/qtsingleapplication/qtlockedfile.cpp b/kybackup/qtsingleapplication/qtlockedfile.cpp new file mode 100644 index 0000000..c142a86 --- /dev/null +++ b/kybackup/qtsingleapplication/qtlockedfile.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtlockedfile.h" + +/*! + \class QtLockedFile + + \brief The QtLockedFile class extends QFile with advisory locking + functions. + + A file may be locked in read or write mode. Multiple instances of + \e QtLockedFile, created in multiple processes running on the same + machine, may have a file locked in read mode. Exactly one instance + may have it locked in write mode. A read and a write lock cannot + exist simultaneously on the same file. + + The file locks are advisory. This means that nothing prevents + another process from manipulating a locked file using QFile or + file system functions offered by the OS. Serialization is only + guaranteed if all processes that access the file use + QLockedFile. Also, while holding a lock on a file, a process + must not open the same file again (through any API), or locks + can be unexpectedly lost. + + The lock provided by an instance of \e QtLockedFile is released + whenever the program terminates. This is true even when the + program crashes and no destructors are called. +*/ + +/*! \enum QtLockedFile::LockMode + + This enum describes the available lock modes. + + \value ReadLock A read lock. + \value WriteLock A write lock. + \value NoLock Neither a read lock nor a write lock. +*/ + +/*! + Constructs an unlocked \e QtLockedFile object. This constructor + behaves in the same way as \e QFile::QFile(). + + \sa QFile::QFile() +*/ +QtLockedFile::QtLockedFile() + : QFile() +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + +/*! + Constructs an unlocked QtLockedFile object with file \a name. This + constructor behaves in the same way as \e QFile::QFile(const + QString&). + + \sa QFile::QFile() +*/ +QtLockedFile::QtLockedFile(const QString &name) + : QFile(name) +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + +/*! + Opens the file in OpenMode \a mode. + + This is identical to QFile::open(), with the one exception that the + Truncate mode flag is disallowed. Truncation would conflict with the + advisory file locking, since the file would be modified before the + write lock is obtained. If truncation is required, use resize(0) + after obtaining the write lock. + + Returns true if successful; otherwise false. + + \sa QFile::open(), QFile::resize() +*/ +bool QtLockedFile::open(OpenMode mode) +{ + if (mode & QIODevice::Truncate) { + qWarning("QtLockedFile::open(): Truncate mode not allowed."); + return false; + } + return QFile::open(mode); +} + +/*! + Returns \e true if this object has a in read or write lock; + otherwise returns \e false. + + \sa lockMode() +*/ +bool QtLockedFile::isLocked() const +{ + return m_lock_mode != NoLock; +} + +/*! + Returns the type of lock currently held by this object, or \e + QtLockedFile::NoLock. + + \sa isLocked() +*/ +QtLockedFile::LockMode QtLockedFile::lockMode() const +{ + return m_lock_mode; +} + +/*! + \fn bool QtLockedFile::lock(LockMode mode, bool block = true) + + Obtains a lock of type \a mode. The file must be opened before it + can be locked. + + If \a block is true, this function will block until the lock is + aquired. If \a block is false, this function returns \e false + immediately if the lock cannot be aquired. + + If this object already has a lock of type \a mode, this function + returns \e true immediately. If this object has a lock of a + different type than \a mode, the lock is first released and then a + new lock is obtained. + + This function returns \e true if, after it executes, the file is + locked by this object, and \e false otherwise. + + \sa unlock(), isLocked(), lockMode() +*/ + +/*! + \fn bool QtLockedFile::unlock() + + Releases a lock. + + If the object has no lock, this function returns immediately. + + This function returns \e true if, after it executes, the file is + not locked by this object, and \e false otherwise. + + \sa lock(), isLocked(), lockMode() +*/ + +/*! + \fn QtLockedFile::~QtLockedFile() + + Destroys the \e QtLockedFile object. If any locks were held, they + are released. +*/ diff --git a/kybackup/qtsingleapplication/qtlockedfile.h b/kybackup/qtsingleapplication/qtlockedfile.h new file mode 100644 index 0000000..84c18e5 --- /dev/null +++ b/kybackup/qtsingleapplication/qtlockedfile.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTLOCKEDFILE_H +#define QTLOCKEDFILE_H + +#include +#ifdef Q_OS_WIN +#include +#endif + +#if defined(Q_OS_WIN) +# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) +# define QT_QTLOCKEDFILE_EXPORT +# elif defined(QT_QTLOCKEDFILE_IMPORT) +# if defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# endif +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) +# elif defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTLOCKEDFILE_EXPORT +#endif + +namespace QtLP_Private { + +class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile +{ +public: + enum LockMode { NoLock = 0, ReadLock, WriteLock }; + + QtLockedFile(); + QtLockedFile(const QString &name); + ~QtLockedFile(); + + bool open(OpenMode mode); + + bool lock(LockMode mode, bool block = true); + bool unlock(); + bool isLocked() const; + LockMode lockMode() const; + +private: +#ifdef Q_OS_WIN + Qt::HANDLE wmutex; + Qt::HANDLE rmutex; + QVector rmutexes; + QString mutexname; + + Qt::HANDLE getMutexHandle(int idx, bool doCreate); + bool waitMutex(Qt::HANDLE mutex, bool doBlock); + +#endif + LockMode m_lock_mode; +}; +} +#endif diff --git a/kybackup/qtsingleapplication/qtlockedfile_unix.cpp b/kybackup/qtsingleapplication/qtlockedfile_unix.cpp new file mode 100644 index 0000000..976c1b9 --- /dev/null +++ b/kybackup/qtsingleapplication/qtlockedfile_unix.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qtlockedfile.h" + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; + int cmd = block ? F_SETLKW : F_SETLK; + int ret = fcntl(handle(), cmd, &fl); + + if (ret == -1) { + if (errno != EINTR && errno != EAGAIN) + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + + m_lock_mode = mode; + return true; +} + + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_UNLCK; + int ret = fcntl(handle(), F_SETLKW, &fl); + + if (ret == -1) { + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + m_lock_mode = NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); +} + diff --git a/kybackup/qtsingleapplication/qtsingleapplication.cpp b/kybackup/qtsingleapplication/qtsingleapplication.cpp new file mode 100644 index 0000000..a206b79 --- /dev/null +++ b/kybackup/qtsingleapplication/qtsingleapplication.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qtsingleapplication.h" +#include "qtlocalpeer.h" +#include +#include + + +/*! + \class QtSingleApplication qtsingleapplication.h + \brief The QtSingleApplication class provides an API to detect and + communicate with running instances of an application. + + This class allows you to create applications where only one + instance should be running at a time. I.e., if the user tries to + launch another instance, the already running instance will be + activated instead. Another usecase is a client-server system, + where the first started instance will assume the role of server, + and the later instances will act as clients of that server. + + By default, the full path of the executable file is used to + determine whether two processes are instances of the same + application. You can also provide an explicit identifier string + that will be compared instead. + + The application should create the QtSingleApplication object early + in the startup phase, and call isRunning() to find out if another + instance of this application is already running. If isRunning() + returns false, it means that no other instance is running, and + this instance has assumed the role as the running instance. In + this case, the application should continue with the initialization + of the application user interface before entering the event loop + with exec(), as normal. + + The messageReceived() signal will be emitted when the running + application receives messages from another instance of the same + application. When a message is received it might be helpful to the + user to raise the application so that it becomes visible. To + facilitate this, QtSingleApplication provides the + setActivationWindow() function and the activateWindow() slot. + + If isRunning() returns true, another instance is already + running. It may be alerted to the fact that another instance has + started by using the sendMessage() function. Also data such as + startup parameters (e.g. the name of the file the user wanted this + new instance to open) can be passed to the running instance with + this function. Then, the application should terminate (or enter + client mode). + + If isRunning() returns true, but sendMessage() fails, that is an + indication that the running instance is frozen. + + Here's an example that shows how to convert an existing + application to use QtSingleApplication. It is very simple and does + not make use of all QtSingleApplication's functionality (see the + examples for that). + + \code + // Original + int main(int argc, char **argv) + { + QApplication app(argc, argv); + + MyMainWidget mmw; + mmw.show(); + return app.exec(); + } + + // Single instance + int main(int argc, char **argv) + { + QtSingleApplication app(argc, argv); + + if (app.isRunning()) + return !app.sendMessage(someDataString); + + MyMainWidget mmw; + app.setActivationWindow(&mmw); + mmw.show(); + return app.exec(); + } + \endcode + + Once this QtSingleApplication instance is destroyed (normally when + the process exits or crashes), when the user next attempts to run the + application this instance will not, of course, be encountered. The + next instance to call isRunning() or sendMessage() will assume the + role as the new running instance. + + For console (non-GUI) applications, QtSingleCoreApplication may be + used instead of this class, to avoid the dependency on the QtGui + library. + + \sa QtSingleCoreApplication +*/ + + +void QtSingleApplication::sysInit(const QString &appId) +{ + actWin = 0; + peer = new QtLocalPeer(this, appId); + connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); +} + + +/*! + Creates a QtSingleApplication object. The application identifier + will be QCoreApplication::applicationFilePath(). \a argc, \a + argv, and \a GUIenabled are passed on to the QAppliation constructor. + + If you are creating a console application (i.e. setting \a + GUIenabled to false), you may consider using + QtSingleCoreApplication instead. +*/ + +QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled) + : QApplication(argc, argv, GUIenabled) +{ + sysInit(); +} + + +/*! + Creates a QtSingleApplication object with the application + identifier \a appId. \a argc and \a argv are passed on to the + QAppliation constructor. +*/ + +QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) + : QApplication(argc, argv) +{ + sysInit(appId); +} + +#if QT_VERSION < 0x050000 + +/*! + Creates a QtSingleApplication object. The application identifier + will be QCoreApplication::applicationFilePath(). \a argc, \a + argv, and \a type are passed on to the QAppliation constructor. +*/ +QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type) + : QApplication(argc, argv, type) +{ + sysInit(); +} + + +# if defined(Q_WS_X11) +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be QCoreApplication::applicationFilePath(). \a dpy, \a visual, + and \a cmap are passed on to the QApplication constructor. +*/ +QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, visual, cmap) +{ + sysInit(); +} + +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a + argv, \a visual, and \a cmap are passed on to the QApplication + constructor. +*/ +QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, argc, argv, visual, cmap) +{ + sysInit(); +} + +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be \a appId. \a dpy, \a argc, \a + argv, \a visual, and \a cmap are passed on to the QApplication + constructor. +*/ +QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, argc, argv, visual, cmap) +{ + sysInit(appId); +} +# endif // Q_WS_X11 +#endif // QT_VERSION < 0x050000 + + +/*! + Returns true if another instance of this application is running; + otherwise false. + + This function does not find instances of this application that are + being run by a different user (on Windows: that are running in + another session). + + \sa sendMessage() +*/ + +bool QtSingleApplication::isRunning() +{ + return peer->isClient(); +} + + +/*! + Tries to send the text \a message to the currently running + instance. The QtSingleApplication object in the running instance + will emit the messageReceived() signal when it receives the + message. + + This function returns true if the message has been sent to, and + processed by, the current instance. If there is no instance + currently running, or if the running instance fails to process the + message within \a timeout milliseconds, this function return false. + + \sa isRunning(), messageReceived() +*/ +QString QtSingleApplication::sendMessage(const QString &message, int timeout) +{ + return peer->sendMessage(message, timeout); +} + + +/*! + Returns the application identifier. Two processes with the same + identifier will be regarded as instances of the same application. +*/ +QString QtSingleApplication::id() const +{ + return peer->applicationId(); +} + + +/*! + Sets the activation window of this application to \a aw. The + activation window is the widget that will be activated by + activateWindow(). This is typically the application's main window. + + If \a activateOnMessage is true (the default), the window will be + activated automatically every time a message is received, just prior + to the messageReceived() signal being emitted. + + \sa activateWindow(), messageReceived() +*/ + + +void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) +{ + actWin = aw; + if (activateOnMessage) + connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); + else + disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); +} + + +/*! + Returns the applications activation window if one has been set by + calling setActivationWindow(), otherwise returns 0. + + \sa setActivationWindow() +*/ + +QWidget* QtSingleApplication::activationWindow() const +{ + return actWin; +} + + +/*! + De-minimizes, raises, and activates this application's activation window. + This function does nothing if no activation window has been set. + + This is a convenience function to show the user that this + application instance has been activated when he has tried to start + another instance. + + This function should typically be called in response to the + messageReceived() signal. By default, that will happen + automatically, if an activation window has been set. + + \sa setActivationWindow(), messageReceived(), initialize() +*/ +void QtSingleApplication::activateWindow() +{ + if (actWin) { + actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); + actWin->raise(); + actWin->activateWindow(); + actWin->show(); + } +} + + +/*! + \fn void QtSingleApplication::messageReceived(const QString& message) + + This signal is emitted when the current instance receives a \a + message from another instance of this application. + + \sa sendMessage(), setActivationWindow(), activateWindow() +*/ + + +/*! + \fn void QtSingleApplication::initialize(bool dummy = true) + + \obsolete +*/ diff --git a/kybackup/qtsingleapplication/qtsingleapplication.h b/kybackup/qtsingleapplication/qtsingleapplication.h new file mode 100644 index 0000000..9cd774c --- /dev/null +++ b/kybackup/qtsingleapplication/qtsingleapplication.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTSINGLEAPPLICATION_H +#define QTSINGLEAPPLICATION_H + + +#include + +class QtLocalPeer; + +#if defined(Q_OS_WIN) +# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT) +# define QT_QTSINGLEAPPLICATION_EXPORT +# elif defined(QT_QTSINGLEAPPLICATION_IMPORT) +# if defined(QT_QTSINGLEAPPLICATION_EXPORT) +# undef QT_QTSINGLEAPPLICATION_EXPORT +# endif +# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport) +# elif defined(QT_QTSINGLEAPPLICATION_EXPORT) +# undef QT_QTSINGLEAPPLICATION_EXPORT +# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTSINGLEAPPLICATION_EXPORT +#endif + +class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication +{ + Q_OBJECT + +public: + QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); + QtSingleApplication(const QString &id, int &argc, char **argv); +#if QT_VERSION < 0x050000 + QtSingleApplication(int &argc, char **argv, Type type); +# if defined(Q_WS_X11) + QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); + QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0); + QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); +# endif // Q_WS_X11 +#endif // QT_VERSION < 0x050000 + + bool isRunning(); + QString id() const; + + void setActivationWindow(QWidget* aw, bool activateOnMessage = true); + QWidget* activationWindow() const; + + // Obsolete: + void initialize(bool dummy = true) + { isRunning(); Q_UNUSED(dummy) } + +public Q_SLOTS: + QString sendMessage(const QString &message, int timeout = 5000); + void activateWindow(); + + +Q_SIGNALS: + void messageReceived(const QString &message); + + +private: + void sysInit(const QString &appId = QString()); + QtLocalPeer *peer; + QWidget *actWin; +}; + +#endif // QTSINGLEAPPLICATION_H diff --git a/kybackup/resource/images/data_backup.svg b/kybackup/resource/images/data_backup.svg new file mode 100644 index 0000000..cbeefc4 --- /dev/null +++ b/kybackup/resource/images/data_backup.svg @@ -0,0 +1,12 @@ + + + pic_sjbf + + + + + + + + + \ No newline at end of file diff --git a/kybackup/resource/images/data_restore.svg b/kybackup/resource/images/data_restore.svg new file mode 100644 index 0000000..1385777 --- /dev/null +++ b/kybackup/resource/images/data_restore.svg @@ -0,0 +1,12 @@ + + + pic_sjhy + + + + + + + + + \ No newline at end of file diff --git a/kybackup/resource/images/ghost_image.svg b/kybackup/resource/images/ghost_image.svg new file mode 100644 index 0000000..4192f30 --- /dev/null +++ b/kybackup/resource/images/ghost_image.svg @@ -0,0 +1,12 @@ + + + pic_Ghost + + + + + + + + + \ No newline at end of file diff --git a/kybackup/resource/images/sysem_restore.svg b/kybackup/resource/images/sysem_restore.svg new file mode 100644 index 0000000..353b105 --- /dev/null +++ b/kybackup/resource/images/sysem_restore.svg @@ -0,0 +1,12 @@ + + + pic_xthy + + + + + + + + + \ No newline at end of file diff --git a/kybackup/resource/images/system_backup.png b/kybackup/resource/images/system_backup.png new file mode 100644 index 0000000..1f00087 Binary files /dev/null and b/kybackup/resource/images/system_backup.png differ diff --git a/kybackup/xatom-helper.cpp b/kybackup/xatom-helper.cpp new file mode 100644 index 0000000..9987181 --- /dev/null +++ b/kybackup/xatom-helper.cpp @@ -0,0 +1,214 @@ +/* + * KWin Style UKUI + * + * Copyright (C) 2020, KylinSoft Co., Ltd. + * + * 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 3 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, see . + * + * Authors: Yue Lan + * + */ + +#include "xatom-helper.h" + +#include +#include +#include +#include +#include + +static XAtomHelper* global_instance = nullptr; + +XAtomHelper* XAtomHelper::getInstance() +{ + if (!global_instance) + global_instance = new XAtomHelper; + return global_instance; +} + +bool XAtomHelper::isFrameLessWindow(int winId) +{ + auto hints = getInstance()->getWindowMotifHint(winId); + if (hints.flags == MWM_HINTS_DECORATIONS && hints.functions == 1) { + return true; + } + return false; +} + +bool XAtomHelper::isWindowDecorateBorderOnly(int winId) +{ + return isWindowMotifHintDecorateBorderOnly(getInstance()->getWindowMotifHint(winId)); +} + +bool XAtomHelper::isWindowMotifHintDecorateBorderOnly(const MotifWmHints& hint) +{ + bool isDeco = false; + if (hint.flags & MWM_HINTS_DECORATIONS && hint.flags != MWM_HINTS_DECORATIONS) { + if (hint.decorations == MWM_DECOR_BORDER) + isDeco = true; + } + return isDeco; +} + +bool XAtomHelper::isUKUICsdSupported() +{ + // fixme: + return false; +} + +bool XAtomHelper::isUKUIDecorationWindow(int winId) +{ + if (m_ukuiDecorationAtion == None) + return false; + + Atom type; + int format; + ulong nitems; + ulong bytes_after; + uchar* data; + + bool isUKUIDecoration = false; + + XGetWindowProperty(QX11Info::display(), winId, m_ukuiDecorationAtion, + 0, LONG_MAX, false, + m_ukuiDecorationAtion, &type, + &format, &nitems, + &bytes_after, &data); + + if (type == m_ukuiDecorationAtion) { + if (nitems == 1) { + isUKUIDecoration = data[0]; + } + } + + return isUKUIDecoration; +} + +UnityCorners XAtomHelper::getWindowBorderRadius(int winId) +{ + UnityCorners corners; + + Atom type; + int format; + ulong nitems; + ulong bytes_after; + uchar* data; + + if (m_unityBorderRadiusAtom != None) { + XGetWindowProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, + 0, LONG_MAX, false, + XA_CARDINAL, &type, + &format, &nitems, + &bytes_after, &data); + + if (type == XA_CARDINAL) { + if (nitems == 4) { + corners.topLeft = static_cast(data[0]); + corners.topRight = static_cast(data[1 * sizeof(ulong)]); + corners.bottomLeft = static_cast(data[2 * sizeof(ulong)]); + corners.bottomRight = static_cast(data[3 * sizeof(ulong)]); + } + XFree(data); + } + } + + return corners; +} + +void XAtomHelper::setWindowBorderRadius(int winId, const UnityCorners& data) +{ + if (m_unityBorderRadiusAtom == None) + return; + + ulong corners[4] = { data.topLeft, data.topRight, data.bottomLeft, data.bottomRight }; + + XChangeProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, + 32, XCB_PROP_MODE_REPLACE, (const unsigned char*)&corners, sizeof(corners) / sizeof(corners[0])); +} + +void XAtomHelper::setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight) +{ + if (m_unityBorderRadiusAtom == None) + return; + + ulong corners[4] = { (ulong)topLeft, (ulong)topRight, (ulong)bottomLeft, (ulong)bottomRight }; + + XChangeProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, + 32, XCB_PROP_MODE_REPLACE, (const unsigned char*)&corners, sizeof(corners) / sizeof(corners[0])); +} + +void XAtomHelper::setUKUIDecoraiontHint(int winId, bool set) +{ + if (m_ukuiDecorationAtion == None) + return; + + XChangeProperty(QX11Info::display(), winId, m_ukuiDecorationAtion, m_ukuiDecorationAtion, 32, XCB_PROP_MODE_REPLACE, (const unsigned char*)&set, 1); +} + +void XAtomHelper::setWindowMotifHint(int winId, const MotifWmHints& hints) +{ + if (m_unityBorderRadiusAtom == None) + return; + + XChangeProperty(QX11Info::display(), winId, m_motifWMHintsAtom, m_motifWMHintsAtom, + 32, XCB_PROP_MODE_REPLACE, (const unsigned char*)&hints, sizeof(MotifWmHints) / sizeof(ulong)); +} + +MotifWmHints XAtomHelper::getWindowMotifHint(int winId) +{ + MotifWmHints hints; + + if (m_unityBorderRadiusAtom == None) + return hints; + + uchar* data; + Atom type; + int format; + ulong nitems; + ulong bytes_after; + + XGetWindowProperty(QX11Info::display(), winId, m_motifWMHintsAtom, + 0, sizeof(MotifWmHints) / sizeof(long), false, AnyPropertyType, &type, + &format, &nitems, &bytes_after, &data); + + if (type == None) { + return hints; + } else { + hints = *(MotifWmHints*)data; + XFree(data); + } + return hints; +} + +XAtomHelper::XAtomHelper(QObject* parent) + : QObject(parent) +{ + if (!QX11Info::isPlatformX11()) + return; + + m_motifWMHintsAtom = XInternAtom(QX11Info::display(), "_MOTIF_WM_HINTS", true); + m_unityBorderRadiusAtom = XInternAtom(QX11Info::display(), "_UNITY_GTK_BORDER_RADIUS", false); + m_ukuiDecorationAtion = XInternAtom(QX11Info::display(), "_KWIN_UKUI_DECORAION", false); +} + +Atom XAtomHelper::registerUKUICsdNetWmSupportAtom() +{ + // fixme: + return None; +} + +void XAtomHelper::unregisterUKUICsdNetWmSupportAtom() +{ + // fixme: +} diff --git a/kybackup/xatom-helper.h b/kybackup/xatom-helper.h new file mode 100644 index 0000000..8fc9421 --- /dev/null +++ b/kybackup/xatom-helper.h @@ -0,0 +1,107 @@ +/* + * KWin Style UKUI + * + * Copyright (C) 2020, KylinSoft Co., Ltd. + * + * 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 3 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, see . + * + * Authors: Yue Lan + * + */ + +#ifndef XATOMHELPER_H +#define XATOMHELPER_H + +#include + +struct UnityCorners { + ulong topLeft = 0; + ulong topRight = 0; + ulong bottomLeft = 0; + ulong bottomRight = 0; +}; + +typedef struct { + ulong flags = 0; + ulong functions = 0; + ulong decorations = 0; + long input_mode = 0; + ulong status = 0; +} MotifWmHints, MwmHints; + +#define MWM_HINTS_FUNCTIONS (1L << 0) +#define MWM_HINTS_DECORATIONS (1L << 1) +#define MWM_HINTS_INPUT_MODE (1L << 2) +#define MWM_HINTS_STATUS (1L << 3) + +#define MWM_FUNC_ALL (1L << 0) +#define MWM_FUNC_RESIZE (1L << 1) +#define MWM_FUNC_MOVE (1L << 2) +#define MWM_FUNC_MINIMIZE (1L << 3) +#define MWM_FUNC_MAXIMIZE (1L << 4) +#define MWM_FUNC_CLOSE (1L << 5) + +#define MWM_DECOR_ALL (1L << 0) +#define MWM_DECOR_BORDER (1L << 1) +#define MWM_DECOR_RESIZEH (1L << 2) +#define MWM_DECOR_TITLE (1L << 3) +#define MWM_DECOR_MENU (1L << 4) +#define MWM_DECOR_MINIMIZE (1L << 5) +#define MWM_DECOR_MAXIMIZE (1L << 6) + +#define MWM_INPUT_MODELESS 0 +#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 +#define MWM_INPUT_SYSTEM_MODAL 2 +#define MWM_INPUT_FULL_APPLICATION_MODAL 3 +#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL + +#define MWM_TEAROFF_WINDOW (1L << 0) + +namespace UKUI { +class Decoration; +} + +class XAtomHelper : public QObject { + friend class UKUI::Decoration; + Q_OBJECT +public: + static XAtomHelper* getInstance(); + + static bool isFrameLessWindow(int winId); + + bool isWindowDecorateBorderOnly(int winId); + bool isWindowMotifHintDecorateBorderOnly(const MotifWmHints& hint); + bool isUKUICsdSupported(); + bool isUKUIDecorationWindow(int winId); + + UnityCorners getWindowBorderRadius(int winId); + void setWindowBorderRadius(int winId, const UnityCorners& data); + void setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight); + void setUKUIDecoraiontHint(int winId, bool set = true); + + void setWindowMotifHint(int winId, const MotifWmHints& hints); + MotifWmHints getWindowMotifHint(int winId); + +private: + explicit XAtomHelper(QObject* parent = nullptr); + + unsigned long registerUKUICsdNetWmSupportAtom(); + void unregisterUKUICsdNetWmSupportAtom(); + + unsigned long m_motifWMHintsAtom = 0l; + unsigned long m_unityBorderRadiusAtom = 0l; + unsigned long m_ukuiDecorationAtion = 0l; +}; + +#endif // XATOMHELPER_H diff --git a/yhkylin-backup-tool.pro.user b/yhkylin-backup-tool.pro.user index d30b5e5..2186499 100644 --- a/yhkylin-backup-tool.pro.user +++ b/yhkylin-backup-tool.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -64,7 +64,7 @@ {5440484b-1916-43f8-99de-3fbc4fe13c66} 0 0 - 0 + 1 /home/zhaominyong/workspace/kylin-backup-tools-new/build-yhkylin-backup-tool-unknown-Debug