Merge pull request #1171 from ONLYOFFICE/patch/develop_r1

Patch/develop
This commit is contained in:
Oleg Kozhukharenko
2024-02-27 13:03:54 +02:00
committed by GitHub
13 changed files with 313 additions and 59 deletions

View File

@ -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 \

View File

@ -70,7 +70,8 @@ enum MsgCommands {
MSG_OtherError,
MSG_RequestContentLenght,
MSG_UnzipProgress,
MSG_SetLanguage
MSG_SetLanguage,
MSG_StartReplacingService
};
class CSocket

View File

@ -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
}

View File

@ -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;

View File

@ -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);
});

View File

@ -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)

View File

@ -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);

View File

@ -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 */

View File

@ -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;}
/***********************************/

View File

@ -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, &section, 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, &section, 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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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