阶段保存
This commit is contained in:
parent
f555fe5c20
commit
8fc9d1bbc4
|
@ -8,6 +8,7 @@
|
|||
#include <QDebug>
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 备份还原操作类型
|
||||
*/
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <QRegularExpression>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file alias="/images/data_backup.svg">resource/images/data_backup.svg</file>
|
||||
<file alias="/images/data_restore.svg">resource/images/data_restore.svg</file>
|
||||
<file alias="/images/ghost_image.svg">resource/images/ghost_image.svg</file>
|
||||
<file alias="/images/system_restore.svg">resource/images/sysem_restore.svg</file>
|
||||
<file alias="/images/system_backup.png">resource/images/system_backup.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -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);
|
||||
}
|
|
@ -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 <QLabel>
|
||||
#include <QMouseEvent>
|
||||
|
||||
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
|
|
@ -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 <QPainter>
|
||||
#include <QStyleOption>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <QWidget>
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
|
||||
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
|
|
@ -0,0 +1,55 @@
|
|||
#include "myiconbutton.h"
|
||||
#include <QFontMetrics>
|
||||
#include <QHBoxLayout>
|
||||
#include <QStyleOptionButton>
|
||||
#include <QPainter>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef MYICONBUTTON_H
|
||||
#define MYICONBUTTON_H
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
|
||||
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
|
|
@ -0,0 +1,48 @@
|
|||
#include "myiconlabel.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QIcon>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef MYICONLABEL_H
|
||||
#define MYICONLABEL_H
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
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
|
|
@ -0,0 +1,88 @@
|
|||
|
||||
#include "functypeconverter.h"
|
||||
|
||||
FuncTypeConverter::FuncTypeConverter()
|
||||
{
|
||||
m_metaModule = QMetaEnum::fromType<FuncTypeConverter::FunType>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef FUNCTYPECONVERTER_H
|
||||
#define FUNCTYPECONVERTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMetaEnum>
|
||||
|
||||
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
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* @brief 由于当前仅用于主题变化时,备份还原工具的一些图标跟随变化,此处暂时先简单封装。后续根据使用情况另行优化。
|
||||
*/
|
||||
|
||||
#include "gsettingswrapper.h"
|
||||
#include <QIcon>
|
||||
#include <QLabel>
|
||||
#include <QGSettings/qgsettings.h>
|
||||
|
||||
#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<QLabel *>(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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef GSETTINGSWRAPPER_H
|
||||
#define GSETTINGSWRAPPER_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QSize>
|
||||
class QWidget;
|
||||
|
||||
/**
|
||||
* @brief 由于当前仅用于主题变化时,备份还原工具的一些图标跟随变化,此处暂时先简单封装。后续根据使用情况另行优化。
|
||||
*/
|
||||
class GSettingsWrapper
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 绑定连接UKui风格的主题
|
||||
* @param QWidget *, 跟随风格变化的窗体对象指针
|
||||
*/
|
||||
static void connectUkuiStyleSchema(QWidget * labelPtr, QSize size = QSize(24, 24));
|
||||
};
|
||||
|
||||
#endif // GSETTINGSWRAPPER_H
|
|
@ -0,0 +1,62 @@
|
|||
#include "imageutil.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef IMAGEUTIL_H
|
||||
#define IMAGEUTIL_H
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
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
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
#include "leftsiderbarwidget.h"
|
||||
#include <QDebug>
|
||||
#include <QGSettings>
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef LEFTSIDERBARWIDGET_H
|
||||
#define LEFTSIDERBARWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QObject>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QButtonGroup>
|
||||
#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
|
|
@ -1,11 +1,196 @@
|
|||
#include "maindialog.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QLibraryInfo>
|
||||
#include <QTextCodec>
|
||||
#include <QTranslator>
|
||||
#include <QCommandLineParser>
|
||||
#include <QtDBus>
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopWidget>
|
||||
#include <KWindowEffects>
|
||||
|
||||
#include <unistd.h>
|
||||
#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<QDBusVariant> 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());
|
||||
}
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
#include "maindialog.h"
|
||||
#include "ui_maindialog.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QProcess>
|
||||
#include <KWindowSystem>
|
||||
#include <unistd.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
#define MAINDIALOG_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QPushButton>
|
||||
#include <QToolButton>
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QStackedWidget>
|
||||
#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
|
||||
|
|
|
@ -6,16 +6,32 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
<width>960</width>
|
||||
<height>640</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>960</width>
|
||||
<height>640</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>960</width>
|
||||
<height>640</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainDialog</string>
|
||||
<string/>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget"/>
|
||||
<widget class="QMenuBar" name="menubar"/>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
#include "systembackup.h"
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef SYSTEMBACKUP_H
|
||||
#define SYSTEMBACKUP_H
|
||||
|
||||
#include <QStackedWidget>
|
||||
|
||||
class SystemBackup : public QStackedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SystemBackup(QWidget *parent = nullptr);
|
||||
~SystemBackup();
|
||||
|
||||
private:
|
||||
void initFirstWidget();
|
||||
};
|
||||
|
||||
#endif // SYSTEMBACKUP_H
|
|
@ -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 <QCoreApplication>
|
||||
#include <QDataStream>
|
||||
#include <QTime>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <QLibrary>
|
||||
#include <qt_windows.h>
|
||||
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
|
||||
static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
||||
#endif
|
||||
#if defined(Q_OS_UNIX)
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#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)
|
||||
}
|
|
@ -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 <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include <QDir>
|
||||
|
||||
#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
|
|
@ -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.
|
||||
*/
|
|
@ -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 <QFile>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QVector>
|
||||
#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<Qt::HANDLE> rmutexes;
|
||||
QString mutexname;
|
||||
|
||||
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
|
||||
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
|
||||
|
||||
#endif
|
||||
LockMode m_lock_mode;
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
|
@ -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 <QWidget>
|
||||
#include <Qt>
|
||||
|
||||
|
||||
/*!
|
||||
\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
|
||||
*/
|
|
@ -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 <QApplication>
|
||||
|
||||
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
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 32 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 57 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 34 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 80 KiB |
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Yue Lan <lanyue@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xatom-helper.h"
|
||||
|
||||
#include <QX11Info>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
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<ulong>(data[0]);
|
||||
corners.topRight = static_cast<ulong>(data[1 * sizeof(ulong)]);
|
||||
corners.bottomLeft = static_cast<ulong>(data[2 * sizeof(ulong)]);
|
||||
corners.bottomRight = static_cast<ulong>(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:
|
||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Yue Lan <lanyue@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef XATOMHELPER_H
|
||||
#define XATOMHELPER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
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
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.11.0, 2021-08-16T15:03:50. -->
|
||||
<!-- Written by QtCreator 4.11.0, 2021-09-08T20:34:30. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
@ -64,7 +64,7 @@
|
|||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{5440484b-1916-43f8-99de-3fbc4fe13c66}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/zhaominyong/workspace/kylin-backup-tools-new/build-yhkylin-backup-tool-unknown-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
|
|
Loading…
Reference in New Issue