mirror of
https://github.com/ONLYOFFICE/desktop-apps.git
synced 2026-04-07 14:09:22 +08:00
Merge pull request #1171 from ONLYOFFICE/patch/develop_r1
Patch/develop
This commit is contained in:
@ -244,7 +244,6 @@ core_windows {
|
||||
# RC_ICONS += ./res/icons/desktop_icons.ico
|
||||
|
||||
HEADERS += $$PWD/src/windows/platform_win/cwindowplatform.h \
|
||||
$$PWD/src/windows/platform_win/csnap.h \
|
||||
$$PWD/src/windows/platform_win/caption.h \
|
||||
$$PWD/src/platform_win/singleapplication.h \
|
||||
$$PWD/src/platform_win/filechooser.h \
|
||||
@ -253,7 +252,6 @@ core_windows {
|
||||
$$PWD/src/platform_win/resource.h
|
||||
|
||||
SOURCES += $$PWD/src/windows/platform_win/cwindowplatform.cpp \
|
||||
$$PWD/src/windows/platform_win/csnap.cpp \
|
||||
$$PWD/src/platform_win/singleapplication.cpp \
|
||||
$$PWD/src/platform_win/filechooser.cpp \
|
||||
$$PWD/src/platform_win/printdialog.cpp \
|
||||
|
||||
@ -70,7 +70,8 @@ enum MsgCommands {
|
||||
MSG_OtherError,
|
||||
MSG_RequestContentLenght,
|
||||
MSG_UnzipProgress,
|
||||
MSG_SetLanguage
|
||||
MSG_SetLanguage,
|
||||
MSG_StartReplacingService
|
||||
};
|
||||
|
||||
class CSocket
|
||||
|
||||
@ -68,6 +68,7 @@
|
||||
# define APP_LAUNCH_NAME "/DesktopEditors"
|
||||
# define APP_HELPER "/editors_helper"
|
||||
# define DAEMON_NAME "/updatesvc"
|
||||
# define DAEMON_NAME_OLD "/~updatesvc"
|
||||
# define SUBFOLDER "/desktopeditors"
|
||||
# define ARCHIVE_EXT _T(".tar.xz")
|
||||
# define ARCHIVE_PATTERN _T("*.tar.xz")
|
||||
@ -274,6 +275,12 @@ void CSvcManager::init()
|
||||
__UNLOCK
|
||||
break;
|
||||
|
||||
case MSG_StartReplacingService:
|
||||
__GLOBAL_LOCK
|
||||
startReplacingService(params[2] == _T("true"));
|
||||
__UNLOCK
|
||||
break;
|
||||
|
||||
case MSG_ClearTempFiles:
|
||||
clearTempFiles(params[1], params[2]);
|
||||
break;
|
||||
@ -629,3 +636,73 @@ void CSvcManager::startReplacingFiles(const tstring &packageType, const bool res
|
||||
restartService();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSvcManager::startReplacingService(const bool restartAfterUpdate)
|
||||
{
|
||||
tstring appPath = NS_File::appPath();
|
||||
tstring updPath = NS_File::parentPath(appPath) + UPDATE_PATH;
|
||||
tstring updSubPath = NS_File::fileExists(updPath + SUBFOLDER + APP_LAUNCH_NAME) ? updPath + SUBFOLDER : updPath;
|
||||
if (!NS_File::dirExists(updPath)) {
|
||||
NS_Logger::WriteLog(_TR("Update cancelled. Can't find folder:") + _T(" ") + updPath, true);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef DONT_VERIFY_SIGNATURE
|
||||
// Verify the signature of executable files
|
||||
if (!NS_File::verifyEmbeddedSignature(updSubPath + DAEMON_NAME)) {
|
||||
NS_Logger::WriteLog(_TR("Update cancelled. The file signature is missing:") + _T(" ") + updSubPath + DAEMON_NAME, true);
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Wait until the main app closes
|
||||
{
|
||||
#ifdef _WIN32
|
||||
tstring apps[] = {APP_LAUNCH_NAME2, APP_HELPER};
|
||||
#else
|
||||
tstring apps[] = {APP_LAUNCH_NAME, APP_HELPER};
|
||||
#endif
|
||||
for (int i = 0; i < sizeof(apps) / sizeof(apps[0]); i++) {
|
||||
int retries = 10;
|
||||
tstring app(apps[i]);
|
||||
app = app.substr(1);
|
||||
while (NS_File::isProcessRunning(app) && retries-- > 0)
|
||||
sleep(500);
|
||||
|
||||
if (NS_File::isProcessRunning(app)) {
|
||||
NS_Logger::WriteLog(_TR("Update cancelled. The program is not closed:") + _T(" ") + app, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rename updatesvc.exe to ~updatesvc.exe
|
||||
if (NS_File::fileExists(appPath + DAEMON_NAME) && !NS_File::replaceFile(appPath + DAEMON_NAME, appPath + DAEMON_NAME_OLD)) {
|
||||
NS_Logger::WriteLog(_TR("Update cancelled. Can't rename updatesvc.exe to ~updatesvc.exe:") + _T(" ") + NS_Utils::GetLastErrorAsString(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move updatesvc.exe to app path
|
||||
if (!NS_File::replaceFile(updSubPath + DAEMON_NAME, appPath + DAEMON_NAME)) {
|
||||
NS_Logger::WriteLog(_TR("Update cancelled. Can't replace file updatesvc.exe to app path:") + _T(" ") + NS_Utils::GetLastErrorAsString(), true);
|
||||
if (NS_File::fileExists(appPath + DAEMON_NAME_OLD) && !NS_File::replaceFile(appPath + DAEMON_NAME_OLD, appPath + DAEMON_NAME))
|
||||
NS_Logger::WriteLog(_TR("Can't restore file updatesvc.exe!"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Restart program
|
||||
if (restartAfterUpdate) {
|
||||
if (!NS_File::runProcess(appPath + APP_LAUNCH_NAME, _T("")))
|
||||
NS_Logger::WriteLog(_TR("An error occurred while restarting the program!"), true);
|
||||
}
|
||||
|
||||
// Remove Update dir
|
||||
NS_File::removeDirRecursively(updPath);
|
||||
|
||||
// Restart service
|
||||
#ifdef _WIN32
|
||||
restartService();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -65,6 +65,7 @@ private:
|
||||
void unzipIfNeeded(const tstring &filePath, const tstring &newVersion);
|
||||
void clearTempFiles(const tstring &prefix, const tstring &except = tstring());
|
||||
void startReplacingFiles(const tstring &packageType, const bool restartAfterUpdate);
|
||||
void startReplacingService(const bool restartAfterUpdate);
|
||||
|
||||
FnVoidVoid m_quit_callback = nullptr;
|
||||
tstring m_newVersion;
|
||||
|
||||
@ -35,12 +35,16 @@
|
||||
#include "classes/platform_linux/ctimer.h"
|
||||
#include "classes/csvcmanager.h"
|
||||
#include "classes/translator.h"
|
||||
#include "version.h"
|
||||
#include "../../src/defines.h"
|
||||
#include "../../src/prop/defines_p.h"
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
#include <locale>
|
||||
|
||||
#define DECL_VERSION __attribute__((section(".version_info"), unused))
|
||||
|
||||
volatile static const char DECL_VERSION version[] = VER_STRING;
|
||||
|
||||
void strToNum(const char *str, int &num)
|
||||
{
|
||||
@ -52,8 +56,6 @@ void strToNum(const char *str, int &num)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NS_File::setAppPath(argv[0]);
|
||||
|
||||
if (argc > 1) {
|
||||
if (strcmp(argv[1], "--run-as-app") == 0) {
|
||||
std::locale::global(std::locale(""));
|
||||
@ -75,11 +77,9 @@ int main(int argc, char *argv[])
|
||||
strToNum((const char*)buff, pid);
|
||||
});
|
||||
|
||||
// Checking for the completion of the main application:
|
||||
// updatevc needs to be terminated when the main application is using a socket
|
||||
// with the same address in the SingleApplication implementation and has been terminated incorrectly.
|
||||
// Termination on crash of the main application
|
||||
CTimer tmr;
|
||||
tmr.start(5000, [&app, &pid]() {
|
||||
tmr.start(30000, [&app, &pid]() {
|
||||
if (pid != -1 && kill(pid, 0) != 0)
|
||||
app.exit(0);
|
||||
});
|
||||
|
||||
@ -175,13 +175,6 @@ namespace NS_Utils
|
||||
|
||||
namespace NS_File
|
||||
{
|
||||
string app_path;
|
||||
|
||||
void setAppPath(const std::string &path)
|
||||
{
|
||||
app_path = parentPath(path);
|
||||
}
|
||||
|
||||
bool GetFilesList(const string &path, list<string> *lst, string &error, bool ignore_locked, bool folders_only)
|
||||
{
|
||||
DIR *dir = opendir(path.c_str());
|
||||
@ -451,7 +444,9 @@ namespace NS_File
|
||||
|
||||
string appPath()
|
||||
{
|
||||
return app_path;
|
||||
char path[PATH_MAX] = {0};
|
||||
ssize_t count = readlink("/proc/self/exe", path, PATH_MAX);
|
||||
return (count > 0) ? parentPath(string(path, count)) : "";
|
||||
}
|
||||
|
||||
// string getFileHash(const string &fileName)
|
||||
|
||||
@ -58,7 +58,6 @@ string GetAppLanguage();
|
||||
|
||||
namespace NS_File
|
||||
{
|
||||
void setAppPath(const string &path);
|
||||
bool GetFilesList(const string &path, list<string> *lst, string &error, bool ignore_locked = false, bool folders_only = false);
|
||||
bool readFile(const string &filePath, list<string> &linesList);
|
||||
bool writeToFile(const string &filePath, list<string> &linesList);
|
||||
|
||||
@ -3,17 +3,20 @@
|
||||
#box-title-tools QLabel {font-family: "Arial", "Helvetica", "Helvetica Neue", sans-serif;}
|
||||
#labelTitle {color: #444; font-weight: normal;}
|
||||
#iconuser {color: %1; background: #d9ffffff; font-size: 10px;}
|
||||
QPushButton[act=tool][hovered=true],
|
||||
QPushButton[act=tool]:hover {background-color: rgba(0,0,0,20%);}
|
||||
QPushButton#toolButtonClose:hover {background-color: #d42b2b;}
|
||||
QPushButton#toolButtonClose:pressed {background-color: #d75050;}
|
||||
|
||||
/* pretty */
|
||||
#mainPanel[window=pretty] QPushButton[act=tool][unix=false][hovered=true],
|
||||
#mainPanel[window=pretty] QPushButton[act=tool][unix=false]:hover {background-color: rgba(255,255,255,20%);}
|
||||
#mainPanel[window=pretty] QPushButton#toolButtonMinimize {image: url(:/minimize_light.svg);}
|
||||
#mainPanel[window=pretty] QPushButton#toolButtonClose {image: url(:/close_light.svg);}
|
||||
#mainPanel[window=pretty] QPushButton#toolButtonClose[unix=false]:hover {background-color: #d42b2b;}
|
||||
#mainPanel[window=pretty] QPushButton#toolButtonMaximize {image: url(:/restore_light.svg);}
|
||||
#mainPanel[window=pretty] QPushButton#toolButtonMaximize[class=min] {image: url(:/maximize_light.svg);}
|
||||
#mainPanel[window=pretty] QPushButton#toolButtonMaximize[unix=false][pressed=true] {background-color: rgba(255,255,255,20%);}
|
||||
#mainPanel[window=pretty] #labelTitle {color: #fff; font-size: 12px;}
|
||||
|
||||
/* dark style */
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
|
||||
QPushButton {/*background-color:#d9d9d9;*/ padding:0 20px; font-weight: normal; height: 22px; font-size: 12px;}
|
||||
QPushButton[act=tool] {/*background-origin: content;*/ border: none; margin: 0; padding: 0; border-radius:0;}
|
||||
QPushButton[act=tool][hovered=true],
|
||||
QPushButton[act=tool]:hover {background-color:#cecece;}
|
||||
QPushButton[act=tool][pressed=true],
|
||||
QPushButton[act=tool]:pressed {background-color:#b7b7b7;}
|
||||
|
||||
QPushButton#toolButtonMaximize,
|
||||
@ -78,9 +80,11 @@ QPushButton#toolButtonDownload {border-left: 0px; border-right: 1px solid #dfdfd
|
||||
|
||||
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonMinimize:hover,
|
||||
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonMaximize:hover,
|
||||
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonMaximize[hovered=true],
|
||||
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonDownload:hover {background-color: #555;}
|
||||
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonMinimize:pressed,
|
||||
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonMaximize:pressed,
|
||||
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonMaximize[pressed=true],
|
||||
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonDownload:pressed {background-color: #606060;}
|
||||
|
||||
/* Contrast-Dark*/
|
||||
@ -98,6 +102,7 @@ QPushButton#toolButtonDownload {border-left: 0px; border-right: 1px solid #dfdfd
|
||||
|
||||
#mainPanel[uitheme=theme-contrast-dark] QPushButton#toolButtonMinimize:hover,
|
||||
#mainPanel[uitheme=theme-contrast-dark] QPushButton#toolButtonMaximize:hover,
|
||||
#mainPanel[uitheme=theme-contrast-dark] QPushButton#toolButtonMaximize[hovered=true],
|
||||
#mainPanel[uitheme=theme-contrast-dark] QPushButton#toolButtonDownload:hover {background-color: #555;}
|
||||
|
||||
/***********************************/
|
||||
|
||||
@ -51,6 +51,9 @@
|
||||
#else
|
||||
# include <QProcess>
|
||||
# include <unistd.h>
|
||||
# include <spawn.h>
|
||||
# include <fcntl.h>
|
||||
# include <elf.h>
|
||||
# include "components/cmessage.h"
|
||||
# include "platform_linux/updatedialog.h"
|
||||
# define DAEMON_NAME "/updatesvc"
|
||||
@ -65,6 +68,7 @@
|
||||
#define CHECK_ON_STARTUP_MS 9000
|
||||
#define CMD_ARGUMENT_UPDATES_CHANNEL L"--updates-appcast-channel"
|
||||
#define CMD_ARGUMENT_UPDATES_INTERVAL L"--updates-interval"
|
||||
#define SERVICE_NAME APP_TITLE " Update Service"
|
||||
#ifndef URL_APPCAST_UPDATES
|
||||
# define URL_APPCAST_UPDATES ""
|
||||
#endif
|
||||
@ -210,19 +214,88 @@ auto runProcess(const tstring &fileName, const tstring &args, bool runAsAdmin =
|
||||
CloseHandle(shExInfo.hProcess);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
Q_UNUSED(runAsAdmin)
|
||||
QStringList _args = QString::fromStdString(args).split(" ");
|
||||
if (QProcess::startDetached(QString::fromStdString(fileName), _args))
|
||||
return true;
|
||||
const QStringList args_list = args.empty() ? QStringList() : QString::fromStdString(args).split(" ");
|
||||
char **_args = new char*[args_list.size() + 2];
|
||||
int i = 0;
|
||||
_args[i++] = const_cast<char*>(fileName.c_str());
|
||||
for (const auto &arg : args_list)
|
||||
_args[i++] = arg.toLocal8Bit().data();
|
||||
_args[i] = NULL;
|
||||
pid_t pid;
|
||||
posix_spawn_file_actions_t acts;
|
||||
posix_spawn_file_actions_init(&acts);
|
||||
posix_spawn_file_actions_addclosefrom_np(&acts, 0);
|
||||
int res = posix_spawn(&pid, fileName.c_str(), &acts, NULL, _args, environ);
|
||||
posix_spawn_file_actions_destroy(&acts);
|
||||
delete[] _args;
|
||||
return res == 0;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
auto getFileVersion(const tstring &filePath)->QString
|
||||
{
|
||||
QString ver;
|
||||
#ifdef _WIN32
|
||||
DWORD handle, size = GetFileVersionInfoSize(filePath.c_str(), &handle);
|
||||
if (size > 0) {
|
||||
BYTE *data = new BYTE[size];
|
||||
if (GetFileVersionInfo(filePath.c_str(), handle, size, (LPVOID)data)) {
|
||||
UINT len = 0;
|
||||
VS_FIXEDFILEINFO *verInfo = NULL;
|
||||
if (VerQueryValue((LPCVOID)data, L"\\", (LPVOID*)&verInfo, &len)) {
|
||||
if (verInfo->dwSignature == 0xfeef04bd) {
|
||||
ver = QString("%1.%2.%3.%4").arg(QString::number(HIWORD(verInfo->dwFileVersionMS)),
|
||||
QString::number(LOWORD(verInfo->dwFileVersionMS)),
|
||||
QString::number(HIWORD(verInfo->dwFileVersionLS)),
|
||||
QString::number(LOWORD(verInfo->dwFileVersionLS)));
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] data;
|
||||
}
|
||||
#else
|
||||
int fd = open(filePath.c_str(), O_RDONLY);
|
||||
if (fd != -1) {
|
||||
Elf64_Ehdr header;
|
||||
if (read(fd, &header, sizeof(header)) == sizeof(header)) {
|
||||
Elf64_Shdr section;
|
||||
off_t ofset = header.e_shoff + header.e_shentsize * header.e_shstrndx;
|
||||
if (lseek(fd, ofset, SEEK_SET) == ofset && read(fd, §ion, sizeof(section)) == sizeof(section)) {
|
||||
char *shstrtab = new char[section.sh_size];
|
||||
if (lseek(fd, section.sh_offset, SEEK_SET) == (off_t)section.sh_offset &&
|
||||
read(fd, shstrtab, section.sh_size) == (ssize_t)section.sh_size) {
|
||||
for (int i = 0; i < header.e_shnum; ++i) {
|
||||
ofset = header.e_shoff + i * header.e_shentsize;
|
||||
if (lseek(fd, ofset, SEEK_SET) == ofset && read(fd, §ion, sizeof(section)) == sizeof(section)) {
|
||||
if (strcmp(".version_info", shstrtab + section.sh_name) == 0) {
|
||||
if (lseek(fd, section.sh_offset, SEEK_SET) == (off_t)section.sh_offset) {
|
||||
char *version = new char[section.sh_size];
|
||||
if (read(fd, version, section.sh_size) == (ssize_t)section.sh_size)
|
||||
ver = QString(version);
|
||||
delete[] version;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] shstrtab;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
return ver;
|
||||
}
|
||||
|
||||
struct CUpdateManager::PackageData {
|
||||
QString fileName,
|
||||
fileType,
|
||||
fileSize,
|
||||
object,
|
||||
hash,
|
||||
version;
|
||||
wstring packageUrl,
|
||||
@ -231,6 +304,7 @@ struct CUpdateManager::PackageData {
|
||||
fileName.clear();
|
||||
fileType.clear();
|
||||
fileSize.clear();
|
||||
object.clear();
|
||||
hash.clear();
|
||||
version.clear();
|
||||
packageUrl.clear();
|
||||
@ -688,7 +762,8 @@ void CUpdateManager::handleAppClose()
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!m_socket->sendMessage(MSG_StartReplacingFiles, IsPackage(ISS) ? _T("iss") : IsPackage(MSI) ? _T("msi") :
|
||||
int cmd = (m_packageData->object == "app") ? MSG_StartReplacingFiles : MSG_StartReplacingService;
|
||||
if (!m_socket->sendMessage(cmd, IsPackage(ISS) ? _T("iss") : IsPackage(MSI) ? _T("msi") :
|
||||
IsPackage(Portable) ? _T("portable") : _T("other"), m_restartAfterUpdate ? _T("true") : _T("false"))) {
|
||||
criticalMsg(nullptr, QObject::tr("An error occurred while start replacing files: Update Service not found!"));
|
||||
}
|
||||
@ -748,19 +823,24 @@ void CUpdateManager::onLoadCheckFinished(const QString &filePath)
|
||||
|
||||
QString version = root.value("version").toString();
|
||||
QString curr_version = QString::fromLatin1(VER_FILEVERSION_STR);
|
||||
|
||||
if (isVersionBHigherThanA(curr_version, version) && (version != ignoredVersion())) {
|
||||
m_packageData->version = version;
|
||||
// parse package
|
||||
QJsonObject package = root.value("package").toObject();
|
||||
QString svc_version = root.value("serviceVersion").toString();
|
||||
QString curr_svc_version = getFileVersion(QStrToTStr(qApp->applicationDirPath()) + DAEMON_NAME);
|
||||
QJsonObject package = root.value("package").toObject();
|
||||
#ifdef _WIN32
|
||||
# ifdef _WIN64
|
||||
QJsonObject win = package.value("win_64").toObject();
|
||||
QJsonObject win = package.value("win_64").toObject();
|
||||
# else
|
||||
QJsonObject win = package.value("win_32").toObject();
|
||||
QJsonObject win = package.value("win_32").toObject();
|
||||
# endif
|
||||
QJsonObject package_type = win.value("archive").toObject();
|
||||
#else
|
||||
QJsonObject win = package.value("linux_64").toObject();
|
||||
#endif
|
||||
if (isVersionBHigherThanA(curr_version, version) && (version != ignoredVersion())) {
|
||||
m_packageData->object = "app";
|
||||
m_packageData->version = version;
|
||||
m_packageData->fileType = "archive";
|
||||
QJsonObject package_type = win.value("archive").toObject();
|
||||
#ifdef _WIN32
|
||||
if (!IsPackage(Portable)) {
|
||||
const QString install_key = IsPackage(MSI) ? "msi" : "iss";
|
||||
if (win.contains(install_key)) {
|
||||
@ -775,10 +855,6 @@ void CUpdateManager::onLoadCheckFinished(const QString &filePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
QJsonObject win = package.value("linux_64").toObject();
|
||||
QJsonObject package_type = win.value("archive").toObject();
|
||||
m_packageData->fileType = "archive";
|
||||
#endif
|
||||
m_packageData->packageUrl = package_type.value("url").toString().toStdWString();
|
||||
m_packageData->hash = package_type.value("md5").toString().toLower();
|
||||
@ -788,6 +864,20 @@ void CUpdateManager::onLoadCheckFinished(const QString &filePath)
|
||||
const QString lang = CLangater::getCurrentLangCode() == "ru-RU" ? "ru-RU" : "en-EN";
|
||||
QJsonValue changelog = release_notes.value(lang);
|
||||
|
||||
clearTempFiles(isSavedPackageValid() ? m_savedPackageData->fileName : "");
|
||||
if (m_packageData->packageUrl.empty() || !m_socket->sendMessage(MSG_RequestContentLenght, WStrToTStr(m_packageData->packageUrl))) {
|
||||
m_packageData->fileSize = "--";
|
||||
onCheckFinished(false, true, m_packageData->version, "");
|
||||
}
|
||||
} else
|
||||
if (isVersionBHigherThanA(curr_svc_version, svc_version)) {
|
||||
m_packageData->object = "svc";
|
||||
m_packageData->version = svc_version;
|
||||
m_packageData->fileType = "archive";
|
||||
QJsonObject package_type = win.value("serviceArchive").toObject();
|
||||
m_packageData->packageUrl = package_type.value("url").toString().toStdWString();
|
||||
m_packageData->hash = package_type.value("md5").toString().toLower();
|
||||
|
||||
clearTempFiles(isSavedPackageValid() ? m_savedPackageData->fileName : "");
|
||||
if (m_packageData->packageUrl.empty() || !m_socket->sendMessage(MSG_RequestContentLenght, WStrToTStr(m_packageData->packageUrl))) {
|
||||
m_packageData->fileSize = "--";
|
||||
@ -806,6 +896,11 @@ void CUpdateManager::onCheckFinished(bool error, bool updateExist, const QString
|
||||
{
|
||||
if ( !error) {
|
||||
if ( updateExist ) {
|
||||
if (m_packageData->object == "svc") {
|
||||
__UNLOCK
|
||||
loadUpdates();
|
||||
return;
|
||||
}
|
||||
switch (getUpdateMode()) {
|
||||
case UpdateMode::SILENT:
|
||||
__UNLOCK
|
||||
@ -835,9 +930,12 @@ void CUpdateManager::onCheckFinished(bool error, bool updateExist, const QString
|
||||
}
|
||||
|
||||
void CUpdateManager::showUpdateMessage(QWidget *parent) {
|
||||
QString name = (m_packageData->object == "app") ? QString(WINDOW_NAME) : QString(SERVICE_NAME);
|
||||
QString curr_version = (m_packageData->object == "app") ? QString(VER_FILEVERSION_STR) :
|
||||
getFileVersion(QStrToTStr(qApp->applicationDirPath()) + DAEMON_NAME);
|
||||
int result = WinDlg::showDialog(parent, tr("Update is available"),
|
||||
QString("%1\n%2: %3\n%4: %5\n%6 (%7 MB)").arg(QString(WINDOW_NAME), tr("Current version"),
|
||||
QString(VER_FILEVERSION_STR), tr("New version"), getVersion(),
|
||||
QString("%1\n%2: %3\n%4: %5\n%6 (%7 MB)").arg(name, tr("Current version"),
|
||||
curr_version, tr("New version"), getVersion(),
|
||||
tr("Would you like to download update now?"), m_packageData->fileSize),
|
||||
WinDlg::DlgBtns::mbSkipRemindDownload);
|
||||
__UNLOCK
|
||||
@ -858,9 +956,12 @@ void CUpdateManager::showUpdateMessage(QWidget *parent) {
|
||||
|
||||
void CUpdateManager::showStartInstallMessage(QWidget *parent)
|
||||
{
|
||||
QString name = (m_packageData->object == "app") ? QString(WINDOW_NAME) : QString(SERVICE_NAME);
|
||||
QString curr_version = (m_packageData->object == "app") ? QString(VER_FILEVERSION_STR) :
|
||||
getFileVersion(QStrToTStr(qApp->applicationDirPath()) + DAEMON_NAME);
|
||||
int result = WinDlg::showDialog(parent, tr("Update is ready to install"),
|
||||
QString("%1: %2\n%3: %4\n%5").arg(tr("Current version"),
|
||||
QString(VER_FILEVERSION_STR), tr("New version"), getVersion(),
|
||||
QString("%1\n%2: %3\n%4: %5\n%6").arg(name, tr("Current version"),
|
||||
curr_version, tr("New version"), getVersion(),
|
||||
tr("To finish updating, restart the app")),
|
||||
WinDlg::DlgBtns::mbInslaterRestart);
|
||||
__UNLOCK
|
||||
|
||||
@ -37,9 +37,6 @@
|
||||
#include "defines.h"
|
||||
#ifdef _WIN32
|
||||
# include "windows/platform_win/caption.h"
|
||||
# ifndef __OS_WIN_XP
|
||||
# include "windows/platform_win/csnap.h"
|
||||
# endif
|
||||
#endif
|
||||
#include <QApplication>
|
||||
#include <QHBoxLayout>
|
||||
@ -181,12 +178,6 @@ QWidget* CWindowBase::createTopPanel(QWidget *parent)
|
||||
m_pTopButtons.push_back(btn);
|
||||
layoutBtns->addWidget(btn);
|
||||
}
|
||||
#if defined (_WIN32) && !defined (__OS_WIN_XP)
|
||||
if (Utils::getWinVersion() >= Utils::WinVer::Win11) {
|
||||
CWin11Snap *snap = new CWin11Snap(m_pTopButtons[BtnType::Btn_Maximize]);
|
||||
Q_UNUSED(snap)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return _boxTitleBtns;
|
||||
}
|
||||
|
||||
@ -36,8 +36,11 @@
|
||||
#include <QWidget>
|
||||
#include <QWindow>
|
||||
#include <Windows.h>
|
||||
#include <Windowsx.h>
|
||||
#include <QStyle>
|
||||
#include <QPushButton>
|
||||
#include <QCoreApplication>
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
class Caption: public QWidget
|
||||
@ -45,25 +48,51 @@ class Caption: public QWidget
|
||||
public:
|
||||
Caption(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()):
|
||||
QWidget(parent, f)
|
||||
{}
|
||||
{
|
||||
hwnd_root = ::GetAncestor((HWND)winId(), GA_ROOT);
|
||||
snapLayoutAllowed = isArrangingAllowed();
|
||||
}
|
||||
|
||||
private:
|
||||
HWND hwnd_root;
|
||||
bool snapLayoutAllowed = false;
|
||||
|
||||
bool isArrangingAllowed() {
|
||||
BOOL arranging = FALSE;
|
||||
SystemParametersInfoA(SPI_GETWINARRANGING, 0, &arranging, 0);
|
||||
return (arranging == TRUE);
|
||||
}
|
||||
|
||||
QPoint cursorPos() {
|
||||
POINT pt;
|
||||
::GetCursorPos(&pt);
|
||||
return mapFromGlobal(QPoint(pt.x, pt.y));
|
||||
}
|
||||
|
||||
QPushButton* buttonAtPos(const QPoint &pos) {
|
||||
QWidget *child = childAt(pos);
|
||||
return child ? qobject_cast<QPushButton*>(child) : nullptr;
|
||||
}
|
||||
|
||||
QPushButton* buttonMaxUnderMouse() {
|
||||
QPushButton *btn = buttonAtPos(cursorPos());
|
||||
return (btn && btn->objectName() == "toolButtonMaximize") ? btn : nullptr;
|
||||
}
|
||||
|
||||
bool postMsg(DWORD cmd) {
|
||||
POINT pt;
|
||||
::GetCursorPos(&pt);
|
||||
QPoint pos = mapFromGlobal(QPoint(int(pt.x), int(pt.y)));
|
||||
QPushButton *pushButton = childAt(pos) ? qobject_cast<QPushButton*>(childAt(pos)) : nullptr;
|
||||
if (!pushButton) {
|
||||
HWND hWnd = ::GetAncestor((HWND)(window()->windowHandle()->winId()), GA_ROOT);
|
||||
if (!buttonAtPos(pos)) {
|
||||
::ReleaseCapture();
|
||||
::PostMessage(hWnd, cmd, HTCAPTION, POINTTOPOINTS(pt));
|
||||
::PostMessage(hwnd_root, cmd, HTCAPTION, POINTTOPOINTS(pt));
|
||||
QCoreApplication::postEvent(parent(), new QEvent(QEvent::MouseButtonPress));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override
|
||||
{
|
||||
#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
|
||||
MSG* msg = *reinterpret_cast<MSG**>(message);
|
||||
@ -83,6 +112,54 @@ private:
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case WM_NCLBUTTONDOWN: {
|
||||
if (Utils::getWinVersion() < Utils::WinVer::Win11)
|
||||
break;
|
||||
if (QPushButton *btn = buttonMaxUnderMouse()) {
|
||||
btn->setProperty("hovered", false);
|
||||
btn->setProperty("pressed", true);
|
||||
btn->style()->polish(btn);
|
||||
btn->repaint();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_TIMER: {
|
||||
QPushButton *btn = buttonMaxUnderMouse();
|
||||
if (!btn) {
|
||||
KillTimer(msg->hwnd, msg->wParam);
|
||||
if (QPushButton *btn = findChild<QPushButton*>("toolButtonMaximize")) {
|
||||
btn->setProperty("hovered", false);
|
||||
btn->setProperty("pressed", false);
|
||||
btn->style()->polish(btn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_NCHITTEST: {
|
||||
if (Utils::getWinVersion() < Utils::WinVer::Win11 || !snapLayoutAllowed)
|
||||
break;
|
||||
*result = 0;
|
||||
if (QPushButton *btn = buttonMaxUnderMouse()) {
|
||||
if (!btn->property("hovered").toBool()) {
|
||||
btn->setProperty("hovered", true);
|
||||
btn->style()->polish(btn);
|
||||
SetTimer(msg->hwnd, 1, 200, NULL);
|
||||
}
|
||||
*result = HTMAXBUTTON;
|
||||
}
|
||||
return (*result != 0);
|
||||
}
|
||||
case WM_CAPTURECHANGED: {
|
||||
if (Utils::getWinVersion() < Utils::WinVer::Win11)
|
||||
break;
|
||||
if (QPushButton *btn = buttonMaxUnderMouse())
|
||||
btn->click();
|
||||
break;
|
||||
}
|
||||
case WM_SETTINGCHANGE: {
|
||||
snapLayoutAllowed = isArrangingAllowed();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -194,11 +194,13 @@ bool CWindowPlatform::nativeEvent(const QByteArray &eventType, void *message, lo
|
||||
{
|
||||
case WM_ACTIVATE: {
|
||||
#ifndef __OS_WIN_XP
|
||||
MARGINS mrg;
|
||||
mrg.cxLeftWidth = 4;
|
||||
mrg.cxRightWidth = 4;
|
||||
mrg.cyBottomHeight = 4;
|
||||
mrg.cyTopHeight = 29;
|
||||
MARGINS mrg = {4, 4, 29, 4};
|
||||
if (Utils::getWinVersion() > Utils::WinVer::Win10) {
|
||||
mrg.cxLeftWidth = 1;
|
||||
mrg.cxRightWidth = 0;
|
||||
mrg.cyBottomHeight = 0;
|
||||
mrg.cyTopHeight = 0;
|
||||
}
|
||||
DwmExtendFrameIntoClientArea(m_hWnd, &mrg);
|
||||
#endif
|
||||
break;
|
||||
@ -299,6 +301,10 @@ bool CWindowPlatform::nativeEvent(const QByteArray &eventType, void *message, lo
|
||||
}
|
||||
|
||||
case WM_SETTINGCHANGE: {
|
||||
if (msg->wParam == SPI_SETWINARRANGING) {
|
||||
if (Utils::getWinVersion() > Utils::WinVer::Win10 && m_boxTitleBtns)
|
||||
SendMessage((HWND)m_boxTitleBtns->winId(), WM_SETTINGCHANGE, 0, 0);
|
||||
} else
|
||||
if (msg->wParam == SPI_SETWORKAREA) {
|
||||
static RECT oldWorkArea = {0,0,0,0};
|
||||
RECT workArea; // Taskbar show/hide detection
|
||||
|
||||
Reference in New Issue
Block a user