Files
desktop-apps/win-linux/src/utils.cpp
2025-02-21 15:24:33 +02:00

1204 lines
38 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2019
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#ifdef __linux__
# include "platform_linux/gtkutils.h"
#endif
#include "utils.h"
#include "defines.h"
#include <QSettings>
#include <QStandardPaths>
#include <QDir>
#include <QRegularExpression>
#include <QApplication>
#include <QDesktopWidget>
#include <QUrl>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QScreen>
#include <QStorageInfo>
#include <QPrinterInfo>
#include <QProcess>
#include "cascapplicationmanagerwrapper.h"
#include "qdpichecker.h"
#include "common/File.h"
#ifdef _WIN32
# include <QDesktopServices>
#include <windowsx.h>
# include <sddl.h>
# include <Lm.h>
#include "shlobj.h"
#include "lmcons.h"
#else
# include <QEventLoop>
# include <QX11Info>
#include <sys/stat.h>
#include <stdlib.h>
#endif
namespace InputArgs {
std::vector<std::wstring> in_args;
auto init(int argc, char** const argv) -> void {
for (int c(1); c < argc; ++c) {
in_args.push_back(UTF8_TO_U(std::string(argv[c])));
}
}
auto init(wchar_t const * wargvl) -> void {
#ifdef Q_OS_WIN
int argc;
LPWSTR * argv = CommandLineToArgvW(wargvl, &argc);
if (argv != nullptr) {
for(int i(1); i < argc; ++i) {
in_args.push_back(argv[i]);
}
}
LocalFree(argv);
#endif
}
auto contains(const std::wstring& param) -> bool {
const std::wstring::size_type l = param.length();
auto iter = std::find_if(std::begin(in_args), std::end(in_args),
[&param, l](const std::wstring& s) {
std::wstring::size_type n = s.find(param);
if (n != std::wstring::npos) {
if (n + l == s.length())
return true;
else {
wchar_t d = s.at(n+l);
if (d == L':' || d == L'=' || d == L'|')
return true;
}
}
return false;
});
return iter != end(in_args);
}
auto argument_value(const std::wstring& param) -> std::wstring {
for (const auto& item: in_args) {
if ( item.find(param) != std::wstring::npos ) {
return item.substr(param.size() + 1); // substring after '=' or ':' symbol
}
}
return L"";
}
auto arguments() -> const std::vector<std::wstring>& {
return in_args;
}
std::wstring web_apps_params;
auto webapps_params() -> const std::wstring& {
return web_apps_params;
}
auto set_webapps_params(const std::wstring& params) -> void {
web_apps_params = params;
}
auto change_webapps_param(const std::wstring& from, const std::wstring& to) -> const std::wstring& {
size_t start_pos = web_apps_params.find(from);
if( start_pos != std::string::npos ) {
web_apps_params.replace(start_pos, from.length(), to);
} else
if ( true /*append*/ ) {
web_apps_params.append(to);
}
return web_apps_params;
}
}
namespace EditorJSVariables {
QJsonObject vars_object;
auto init() -> void {
#ifdef __OS_WIN_XP
vars_object["os"] = "winxp";
#endif
if ( InputArgs::contains(L"--help-url") )
vars_object["helpUrl"] = QUrl(QString::fromStdWString(InputArgs::argument_value(L"--help-url"))).toString();
else {
GET_REGISTRY_USER(_reg_user)
if ( _reg_user.contains("helpUrl") )
vars_object["helpUrl"] = _reg_user.value("helpUrl").toString();
#ifdef URL_WEBAPPS_HELP
else if ( !QString(URL_WEBAPPS_HELP).isEmpty() )
vars_object["helpUrl"] = URL_WEBAPPS_HELP;
#endif
}
vars_object["defaultPrinterName"] = QPrinterInfo::defaultPrinterName();
}
auto setVariable(const QString& name, const QString& var) -> void {
vars_object[name] = var;
}
auto setVariable(const QString& name, const QJsonObject& obj) -> void {
vars_object[name] = obj;
}
auto setVariable(const QString& name, const QJsonArray& array) -> void {
vars_object[name] = array;
}
auto applyVariable(const QString& name, const QJsonObject& obj) -> void {
vars_object[name] = obj;
apply();
}
auto toWString() -> std::wstring {
return vars_object.isEmpty() ? L"" : Utils::stringifyJson(vars_object).toStdWString();
}
auto apply() -> void {
AscAppManager::getInstance().SetRendererProcessVariable(toWString());
}
}
namespace AppOptions {
auto packageType() -> AppPackageType {
QString _package = QSettings("./converter/package.config", QSettings::IniFormat).value("package").toString();
if ( _package == "exe" ) return AppPackageType::ISS; else
if ( _package == "msi" ) return AppPackageType::MSI; else
if ( _package == "snap" ) return AppPackageType::Snap; else
if ( _package == "flatpack" ) return AppPackageType::Flatpack; else
/*if( _package.isEmpty() )*/ return AppPackageType::Portable;
return AppPackageType::Unknown;
}
}
namespace Scaling {
auto scalingToFactor(const QString& scaling) -> std::wstring
{
switch ( scaling.toInt() ) {
case 100: return L"1";
case 125: return L"1.25";
case 150: return L"1.5";
case 175: return L"1.75";
case 200: return L"2";
case 225: return L"2.25";
case 250: return L"2.5";
case 275: return L"2.75";
case 300: return L"3";
case 350: return L"3.5";
case 400: return L"4";
case 450: return L"4.5";
case 500: return L"5";
default: return L"0";
}
}
auto factorToScaling(const std::wstring& value) -> QString
{
return value == L"1" ? "100" :
value == L"1.25" ? "125" :
value == L"1.5" ? "150" :
value == L"1.75" ? "175" :
value == L"2" ? "200" :
value == L"2.25" ? "225" :
value == L"2.5" ? "250" :
value == L"2.75" ? "275" :
value == L"3" ? "300" :
value == L"3.5" ? "350" :
value == L"4" ? "400" :
value == L"4.5" ? "450" :
value == L"5" ? "500" : "0";
}
}
QStringList * Utils::getInputFiles(const QStringList& inlist)
{
QStringList * _ret_files_list = nullptr;
if ( !inlist.isEmpty() ) {
_ret_files_list = new QStringList;
QStringListIterator i(inlist);
while (i.hasNext()) {
QString arg = i.next();
if ( arg.startsWith("--new:") || arg.startsWith("--new=") )
_ret_files_list->append( arg );
else {
QFileInfo info( arg );
if ( info.isFile() ) {
_ret_files_list->append(info.absoluteFilePath());
}
}
}
}
return _ret_files_list;
}
QString Utils::lastPath(int t)
{
GET_REGISTRY_USER(_reg_user)
QString _path;
if (t == LOCAL_PATH_OPEN)
_path = _reg_user.value("openPath").value<QString>(); else
_path = _reg_user.value("savePath").value<QString>();
return !_path.isEmpty() && QDir(_path).exists() ?
_path : QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
}
void Utils::keepLastPath(int t, const QString& p)
{
GET_REGISTRY_USER(_reg_user)
if (t == LOCAL_PATH_OPEN)
_reg_user.setValue("openPath", p); else
_reg_user.setValue("savePath", p);
}
bool Utils::makepath(const QString& p)
{
#ifdef __linux
mode_t _mask = umask(0);
(_mask & S_IRWXO) && umask(_mask & ~S_IRWXO);
#endif
return QDir().mkpath(p);
}
bool Utils::writeFile(const QString &filePath, const QByteArray &data)
{
QFile file(filePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
auto bytes_written = file.write(data);
file.close();
return bytes_written == data.size();
}
return false;
}
QRect Utils::getScreenGeometry(const QPoint& leftTop)
{
// int _scr_num = QApplication::desktop()->screenNumber(leftTop); - return the wrong number
// return QApplication::desktop()->screenGeometry(_scr_num);
#ifdef __linux
auto pointToRect = [](const QPoint &p, const QRect &r) -> int {
int dx = 0, dy = 0;
if (p.x() < r.left()) dx = r.left() - p.x(); else
if (p.x() > r.right()) dx = p.x() - r.right();
if (p.y() < r.top()) dy = r.top() - p.y(); else
if (p.y() > r.bottom()) dy = p.y() - r.bottom();
return dx + dy;
};
int closestScreen = 0;
int shortestDistance = pointToRect(leftTop, QApplication::desktop()->screenGeometry(0));
for (int i = 0; ++i < QApplication::desktop()->screenCount(); ) {
int thisDistance = pointToRect(leftTop, QApplication::desktop()->screenGeometry(i));
if (thisDistance < shortestDistance) {
shortestDistance = thisDistance;
closestScreen = i;
}
}
return QApplication::desktop()->screenGeometry(closestScreen);
#else
POINT lt{leftTop.x(), leftTop.y()};
MONITORINFO mi{sizeof(MONITORINFO)};
::GetMonitorInfo(::MonitorFromPoint(lt, MONITOR_DEFAULTTOPRIMARY), &mi);
return QRect(QPoint(mi.rcWork.left, mi.rcWork.top), QPoint(mi.rcWork.right, mi.rcWork.bottom));
#endif
}
QString Utils::systemLocationCode()
{
#define LOCATION_MAX_LEN 9
#ifdef _WIN32
WCHAR _country_code[LOCATION_MAX_LEN]{0};
// "no entry point for GetLocaleInfoEx" error on win_xp
// if ( QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA ) {
// if (!GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_SISO3166CTRYNAME, _country_code, LOCATION_MAX_LEN))
// return "unknown";
// } else {
if (!GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SISO3166CTRYNAME, _country_code, LOCATION_MAX_LEN))
return "unknown";
// }
return QString::fromWCharArray(_country_code);
#else
QStringList list = QLocale().name().split('_');
if (list.size() < 2)
return "EN";
return list.at(1);
#endif
}
void Utils::openUrl(const QString& url)
{
#ifdef __linux
QUrl _url(url);
if ( _url.scheme() == "mailto" ) {
system(QString("LD_LIBRARY_PATH='' xdg-email %1") // xdg-email filepath email
.arg(QString( _url.toEncoded() )).toUtf8());
} else {
if (url.startsWith("xdg:")) {
// url is already encoded for xdg
std::wstring sUrlW = url.toStdWString().substr(4);
std::string sCommand = "LD_LIBRARY_PATH='' xdg-open " + U_TO_UTF8(sUrlW);
system(sCommand.c_str());
} else {
// xdg-open workingpath path
system(QString("LD_LIBRARY_PATH='' xdg-open \"%1\"")
.arg(QString( _url.toEncoded() )).toUtf8());
}
}
#else
QDesktopServices::openUrl(QUrl(url));
#endif
}
void Utils::openFileLocation(const QString& path)
{
#if defined(Q_OS_WIN)
auto _path = QDir::toNativeSeparators(path).toStdWString();
if (LPITEMIDLIST idl = ILCreateFromPath(_path.c_str())) {
SHOpenFolderAndSelectItems(static_cast<LPCITEMIDLIST>(idl), 0, 0, 0);
ILFree(idl);
}
#else
static QString _file_browser;
static QString _arg_select = "--no-desktop";
if ( _file_browser.isEmpty() ) {
auto _get_cmd_output = [](const QString& cmd, const QStringList& args, QString& error) {
QProcess process;
process.start(cmd, args);
process.waitForFinished(-1);
error = process.readAllStandardError();
return process.readAllStandardOutput();
};
QString _error;
QString _cmd_output = _get_cmd_output("xdg-mime", QStringList{"query", "default", "inode/directory"}, _error);
// if ( _error.isEmpty() )
{
if ( _cmd_output.contains(QRegularExpression("nautilus\\.desktop", QRegularExpression::CaseInsensitiveOption)) ||
_cmd_output.contains(QRegularExpression("nautilus-folder-handler\\.desktop", QRegularExpression::CaseInsensitiveOption)) )
{
// _cmd_output = _get_cmd_output("nautilus", QStringList{"--version"}, _error);
// if ( _error.isEmpty() )
{
// QRegularExpression _regex("nautilus\\s(\\d{1,3})\\.(\\d{1,3})(?:\\.(\\d{1,5}))?");
// QRegularExpressionMatch match = _regex.match(_cmd_output);
// if ( match.hasMatch() ) {
// bool is_verion_supported = match.captured(1).toInt() > 3;
// if ( !is_verion_supported && match.captured(1).toInt() == 3 ) {
// is_verion_supported = match.captured(2).toInt() > 0;
// if ( !is_verion_supported && !match.captured(3).isEmpty() )
// is_verion_supported = !(match.captured(3).toInt() < 2);
// }
// is_file_browser_supported = is_verion_supported;
// }
}
_file_browser = "nautilus";
} else
if ( _cmd_output.contains(QRegularExpression("dolphin\\.desktop", QRegularExpression::CaseInsensitiveOption)) ) {
_file_browser = "dolphin";
_arg_select = "--select";
} else
if ( _cmd_output == "caja-folder-handler.desktop" ) {
_file_browser = "caja";
} else
if ( _cmd_output == "nemo.desktop" ) {
_file_browser = "nemo";
} else
if ( _cmd_output == "kfmclient_dir.desktop" ) {
_file_browser = "konqueror";
_arg_select = "--select";
} else {
_file_browser = "unknown";
}
}
}
QFileInfo fileInfo(path);
if ( !_file_browser.isEmpty() && _file_browser != "unknown" ) {
qputenv("LD_LIBRARY_PATH", "");
QProcess::startDetached(_file_browser, QStringList{_arg_select, fileInfo.absoluteFilePath()});
} else
system(QString("LD_LIBRARY_PATH='' xdg-open \"%1\"").arg(fileInfo.path()).toUtf8());
#endif
}
bool Utils::isFileLocal(const QString& path)
{
QStorageInfo storage(QFileInfo(path).dir());
# ifdef Q_OS_WIN
return storage.device().startsWith("\\\\?\\");
# else
return storage.device().startsWith("/dev/");
# endif
}
QString Utils::uniqFileName(const QString& path)
{
QFileInfo _info(path);
if ( _info.exists() ) {
QString _name = _info.baseName(),
_suffix = _info.suffix();
QDir _dir = _info.dir();
int _index{0};
while ( true ) {
_info = QFileInfo(_dir, _name + QString::number(++_index) + "." + _suffix);
if ( !_info.exists() ) return _info.absoluteFilePath();
}
}
return path;
}
QString Utils::getPortalName(const QString& url)
{
if ( !url.isEmpty() ) {
QRegularExpressionMatch match = QRegularExpression(rePortalName).match(url);
if (match.hasMatch()) {
QString out = match.captured(1);
return out.endsWith('/') ? out.remove(-1, 1) : out;
}
}
return url;
}
QString Utils::stringifyJson(const QJsonObject& obj)
{
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
}
inline double choose_scaling(double s)
{
return s > 4.5 ? 5 :
s > 4 ? 4.5 :
s > 3.5 ? 4 :
s > 3 ? 3.5 :
s > 2.75 ? 3 :
s > 2.5 ? 2.75 :
s > 2.25 ? 2.5 :
s > 2 ? 2.25 :
s > 1.75 ? 2 :
s > 1.5 ? 1.75 :
s > 1.25 ? 1.5 :
s > 1 ? 1.25 : 1;
}
double Utils::getScreenDpiRatio(int scrnum)
{
unsigned int _dpi_x = 0;
unsigned int _dpi_y = 0;
double nScale = AscAppManager::getInstance().GetMonitorScaleByIndex(scrnum, _dpi_x, _dpi_y);
return choose_scaling(nScale);
}
double Utils::getScreenDpiRatio(const QPoint& pt)
{
QWidget _w;
_w.setGeometry(QRect(pt, QSize(10,10)));
#ifdef Q_OS_LINUX
return getScreenDpiRatioByWidget(&_w);
#else
return getScreenDpiRatioByHWND(_w.winId());
#endif
}
double Utils::getScreenDpiRatioByHWND(int hwnd)
{
unsigned int _dpi_x = 0;
unsigned int _dpi_y = 0;
double nScale = AscAppManager::getInstance().GetMonitorScaleByWindow((WindowHandleId)hwnd, _dpi_x, _dpi_y);
return choose_scaling(nScale);
}
double Utils::getScreenDpiRatioByWidget(QWidget* wid)
{
if (!wid)
return 1;
unsigned int nDpiX = 0;
unsigned int nDpiY = 0;
#ifdef Q_OS_LINUX
QDpiChecker * pChecker = (QDpiChecker *)AscAppManager::getInstance().GetDpiChecker();
int nResult = pChecker->GetWidgetDpi(wid, &nDpiX, &nDpiY);
double dpiApp = pChecker->GetScale(nDpiX, nDpiY);
#else
double dpiApp = AscAppManager::getInstance().GetMonitorScaleByWindow((WindowHandleId)wid->winId(), nDpiX, nDpiY);
#endif
if ( dpiApp >= 0 ) {
return choose_scaling(dpiApp);
}
return wid->devicePixelRatio();
}
QScreen * Utils::screenAt(const QPoint& pt)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
return QApplication::screenAt(pt);
#else
QVarLengthArray<const QScreen *, 8> _cached_screens;
for (const QScreen *screen : QApplication::screens()) {
if (_cached_screens.contains(screen))
continue;
for (QScreen *sibling : screen->virtualSiblings()) {
QRect r = sibling->geometry();
if (sibling->geometry().contains(pt))
return sibling;
_cached_screens.append(sibling);
}
}
return nullptr;
#endif
}
/*
QByteArray Utils::getAppStylesheets(int scale)
{
auto read_styles = [](const QString& dir) {
QByteArray _css;
QFile file;
QFileInfoList files = QDir(dir).entryInfoList(QStringList("*.qss"), QDir::Files);
foreach(const QFileInfo &info, files) {
file.setFileName(info.absoluteFilePath());
if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) {
_css.append(file.readAll());
file.close();
}
}
return _css;
};
QByteArray _out( read_styles(QString(":styles/res/styles")) );
if ( scale > 1 ) {
_out.append( read_styles(QString(":styles@2x")) );
}
return _out;
}
*/
QByteArray Utils::readStylesheets(std::vector<std::string> const * list)
{
auto read_styles = [](std::vector<std::string> const * inl) {
QByteArray _css;
QFile file;
for ( auto &path : *inl ) {
file.setFileName(path.c_str());
if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) {
_css.append(file.readAll());
file.close();
}
}
return std::move(_css);
};
return read_styles(list);
}
QByteArray Utils::readStylesheets(const QString& path)
{
QByteArray _css;
QFile file(path);
if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) {
_css.append(file.readAll());
file.close();
}
return _css;
}
QJsonObject Utils::parseJsonString(const std::wstring& wjson)
{
QJsonParseError jerror;
QByteArray stringdata = QString::fromStdWString(wjson).toUtf8();
QJsonDocument jdoc = QJsonDocument::fromJson(stringdata, &jerror);
if( jerror.error == QJsonParseError::NoError ) {
return jdoc.object();
}
return QJsonObject();
}
QJsonObject Utils::parseJsonFile(const QString& path)
{
QFile file(path);
if ( file.open(QIODevice::ReadOnly) ) {
QByteArray data{file.readAll()};
file.close();
QJsonParseError jpe;
QJsonDocument jdoc = QJsonDocument::fromJson(data, &jpe);
if ( jpe.error == QJsonParseError::NoError ) {
return jdoc.object();
}
}
return QJsonObject();
}
bool Utils::updatesAllowed()
{
GET_REGISTRY_SYSTEM(reg_system)
if (reg_system.value("CheckForUpdates", true).toBool()) {
#ifdef _WIN32
return (IsPackage(Portable) || IsPackage(ISS) || IsPackage(MSI));
#else
return IsPackage(Portable);
#endif
}
return false;
}
void Utils::addToRecent(const std::wstring &path)
{
#ifdef _WIN32
std::wstring _path(path);
std::replace(_path.begin(), _path.end(), '/', '\\');
# ifdef __OS_WIN_XP
SHAddToRecentDocs(SHARD_PATH, _path.c_str());
# else
if (LPITEMIDLIST idl = ILCreateFromPath(_path.c_str())) {
SHARDAPPIDINFOIDLIST inf;
inf.pidl = static_cast<PCIDLIST_ABSOLUTE>(idl);
inf.pszAppID = TEXT(APP_USER_MODEL_ID);
SHAddToRecentDocs(SHARD_APPIDINFOIDLIST, &inf);
ILFree(idl);
}
# endif
#else
QString _path = QString::fromStdWString(path);
std::string uri = "file://" + _path.toStdString();
add_to_recent(uri.c_str());
#endif
}
void Utils::processMoreEvents(uint timeout)
{
QEventLoop loop;
QTimer::singleShot(timeout, &loop, SLOT(quit()));
loop.exec();
}
#ifdef _WIN32
Utils::WinVer Utils::getWinVersion()
{
static WinVer winVer = WinVer::Undef;
if (winVer == WinVer::Undef) {
if (HMODULE module = GetModuleHandleA("ntdll")) {
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
*(FARPROC*)&RtlGetVersion = GetProcAddress(module, "RtlGetVersion");
if (RtlGetVersion) {
OSVERSIONINFOEXW os = {0};
os.dwOSVersionInfoSize = sizeof(os);
RtlGetVersion(&os);
#define MjrVer os.dwMajorVersion
#define MinVer os.dwMinorVersion
#define BldVer os.dwBuildNumber
winVer = MjrVer == 5L && (MinVer == 1L || MinVer == 2L) ? WinVer::WinXP :
MjrVer == 6L && MinVer == 0L ? WinVer::WinVista :
MjrVer == 6L && MinVer == 1L ? WinVer::Win7 :
MjrVer == 6L && MinVer == 2L ? WinVer::Win8 :
MjrVer == 6L && MinVer == 3L ? WinVer::Win8_1 :
MjrVer == 10L && MinVer == 0L && BldVer < 22000 ? WinVer::Win10 :
MjrVer == 10L && MinVer == 0L && BldVer >= 22000 ? WinVer::Win11 :
MjrVer == 10L && MinVer > 0L ? WinVer::Win11 :
MjrVer > 10L ? WinVer::Win11 : WinVer::Undef;
}
}
}
return winVer;
}
QString Utils::GetCurrentUserSID()
{
static QString user_sid;
if (user_sid.isEmpty()) {
HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
DWORD tokenLen = 0;
GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenLen);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
if (PTOKEN_USER pTokenUser = (PTOKEN_USER)malloc(tokenLen)) {
if (GetTokenInformation(hToken, TokenUser, pTokenUser, tokenLen, &tokenLen)) {
LPWSTR sid = NULL;
if (ConvertSidToStringSid(pTokenUser->User.Sid, &sid)) {
user_sid = QString::fromWCharArray(sid);
LocalFree(sid);
}
}
free(pTokenUser);
}
}
CloseHandle(hToken);
}
}
return user_sid;
}
std::atomic_bool sessionInProgress{true};
bool Utils::isSessionInProgress()
{
return sessionInProgress;
}
void Utils::setSessionInProgress(bool state)
{
sessionInProgress = state;
}
void Utils::setAppUserModelId()
{
if (HMODULE lib = LoadLibrary(L"shell32")) {
HRESULT (WINAPI *SetAppUserModelID)(PCWSTR AppID);
*(FARPROC*)&SetAppUserModelID = GetProcAddress(lib, "SetCurrentProcessExplicitAppUserModelID");
if (SetAppUserModelID)
SetAppUserModelID(TEXT(APP_USER_MODEL_ID));
FreeLibrary(lib);
}
}
#else
void Utils::setInstAppPort(int port)
{
GET_REGISTRY_USER(reg_user);
if (port == -1) {
reg_user.remove("instAppPort");
} else
if (port > 1023 && port < 65536) {
reg_user.setValue("instAppPort", port);
} else {
qWarning() << "Value not applied: port must be in the range 1024 - 65535";
}
}
int Utils::getInstAppPort()
{
GET_REGISTRY_USER(reg_user);
return reg_user.value("instAppPort", INSTANCE_APP_PORT).toInt();
}
#endif
QString Utils::replaceBackslash(const QString& path)
{
return QString(path).replace(QRegularExpression("\\\\"), "/");
}
std::wstring Utils::normalizeAppProtocolUrl(const std::wstring &url)
{
QUrl _url(QString::fromStdWString(url));
if (_url.scheme() == APP_PROTOCOL) {
QUrlQuery query(_url);
query.addQueryItem("placement", "desktop");
_url.setQuery(query);
return _url.toString(QUrl::RemoveScheme).toStdWString();
}
return url;
}
void Utils::replaceAll(std::wstring& subject, const std::wstring& search, const std::wstring& replace)
{
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::wstring::npos)
{
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
std::wstring Utils::systemUserName()
{
#ifdef Q_OS_WIN
WCHAR _env_name[UNLEN + 1]{0};
DWORD _size = UNLEN + 1;
if (GetUserName(_env_name, &_size)) {
LPBYTE buff = nullptr;
if (NetUserGetInfo(nullptr, _env_name, 10, &buff) == NERR_Success) {
std::wstring user_name(reinterpret_cast<USER_INFO_10*>(buff)->usri10_full_name);
NetApiBufferFree(buff);
if (!user_name.empty())
return user_name;
}
return _env_name;
}
return L"Unknown.User";
#else
QString _env_name = qgetenv("USER");
if ( _env_name.isEmpty() ) {
_env_name = qgetenv("USERNAME");
if (_env_name.isEmpty())
_env_name = "Unknown.User";
}
return _env_name.toStdWString();
#endif
}
std::wstring Utils::appUserName()
{
GET_REGISTRY_USER(_reg_user)
QJsonParseError jerror;
QByteArray data = QByteArray::fromBase64(_reg_user.value("appdata").toByteArray());
QJsonDocument jdoc = QJsonDocument::fromJson(data, &jerror);
if( jerror.error == QJsonParseError::NoError ) {
QJsonObject objRoot = jdoc.object();
if ( objRoot.contains("username") ) {
return objRoot["username"].toString().toStdWString();
}
}
return systemUserName();
}
namespace WindowHelper {
#ifdef Q_OS_LINUX
CParentDisable::CParentDisable(QWidget* &parent)
{
disable(parent);
}
CParentDisable::~CParentDisable()
{
enable();
}
void CParentDisable::disable(QWidget* &parent)
{
if (parent) {
parent->setProperty("blocked", true);
Qt::WindowFlags flags = Qt::FramelessWindowHint;
if (!QX11Info::isCompositingManagerRunning()) {
flags |= (Qt::SubWindow | Qt::BypassWindowManagerHint);
Utils::processMoreEvents(); // Fixed Cef rendering before reopening the dialog
} else
flags |= Qt::Dialog;
m_pChild = new QWidget(parent, flags);
m_pChild->setAttribute(Qt::WA_TranslucentBackground);
if (QX11Info::isCompositingManagerRunning()) {
m_pChild->setWindowModality(Qt::ApplicationModal);
int offset = parent->isMaximized() ? 0 : 10;
m_pChild->move(parent->pos() - QPoint(offset, offset));
m_pChild->setFixedSize(parent->size() + 2 * QSize(offset, offset));
parent = m_pChild;
} else
m_pChild->setGeometry(parent->rect());
m_pChild->show();
}
}
void CParentDisable::enable()
{
if ( m_pChild ) {
if (m_pChild->parent())
m_pChild->parent()->setProperty("blocked", false);
delete m_pChild, m_pChild = nullptr;
}
}
// Linux Environment Info
int desktop_env = -1;
auto getEnvInfo() -> int {
if ( desktop_env == -1 ) {
const QString env(qgetenv("XDG_CURRENT_DESKTOP"));
if (env.indexOf("Unity") != -1) {
const QString session(qgetenv("DESKTOP_SESSION"));
desktop_env = (session.indexOf("gnome-fallback") != -1) ? GNOME : UNITY;
} else
if (env.indexOf("GNOME") != -1)
desktop_env = GNOME;
else
if (env.indexOf("KDE") != -1)
desktop_env = KDE;
else desktop_env = OTHER;
}
return desktop_env;
}
auto useGtkDialog() -> bool {
GET_REGISTRY_USER(reg_user)
bool use_gtk_dialog = true;
bool saved_flag = reg_user.value("--xdg-desktop-portal", false).toBool();
if (InputArgs::contains(L"--xdg-desktop-portal=default")) {
use_gtk_dialog = false;
if (saved_flag)
reg_user.setValue("--xdg-desktop-portal", false);
} else
if (InputArgs::contains(L"--xdg-desktop-portal")) {
use_gtk_dialog = false;
if (!saved_flag)
reg_user.setValue("--xdg-desktop-portal", true);
} else {
if (saved_flag)
use_gtk_dialog = false;
}
return use_gtk_dialog;
}
#else
// auto isWindowSystemDocked(HWND handle) -> bool {
// RECT windowrect;
// WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT);
// if ( GetWindowRect(handle, &windowrect) && GetWindowPlacement(handle, &wp) && wp.showCmd == SW_SHOWNORMAL ) {
// return (wp.rcNormalPosition.right - wp.rcNormalPosition.left != windowrect.right - windowrect.left) ||
// (wp.rcNormalPosition.bottom - wp.rcNormalPosition.top != windowrect.bottom - windowrect.top);
// }
// return false;
// }
// auto correctWindowMinimumSize(HWND handle) -> void {
// WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT);
// if ( GetWindowPlacement(handle, &wp) ) {
// int dpi_ratio = Utils::getScreenDpiRatioByHWND((int)handle);
// QSize _min_windowsize{MAIN_WINDOW_MIN_WIDTH * dpi_ratio,MAIN_WINDOW_MIN_HEIGHT * dpi_ratio};
// QRect windowRect{QPoint(wp.rcNormalPosition.left, wp.rcNormalPosition.top),
// QPoint(wp.rcNormalPosition.right, wp.rcNormalPosition.bottom)};
// if ( windowRect.width() < _min_windowsize.width() ||
// windowRect.height() < _min_windowsize.height() )
// {
// // if ( windowRect.width() < _min_windowsize.width() )
// wp.rcNormalPosition.right = wp.rcNormalPosition.left + _min_windowsize.width();
// // if ( windowRect.height() < _min_windowsize.height() )
// wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + _min_windowsize.height();
// SetWindowPlacement(handle, &wp);
// }
// }
// }
// auto correctModalOrder(HWND windowhandle, HWND modalhandle) -> void
// {
// if ( !IsWindowEnabled(windowhandle) && modalhandle && modalhandle != windowhandle ) {
// SetActiveWindow(modalhandle);
// SetWindowPos(windowhandle, modalhandle, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
// }
// }
// typedef BOOL (__stdcall *AdjustWindowRectExForDpiW)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
// auto adjustWindowRect(HWND handle, double dpiratio, LPRECT rect) -> void
// {
// static AdjustWindowRectExForDpiW _adjustWindowRectEx = nullptr;
// static bool _is_read = false;
// if ( !_is_read && !_adjustWindowRectEx ) {
// HMODULE _lib = ::LoadLibrary(L"user32.dll");
// _adjustWindowRectEx = reinterpret_cast<AdjustWindowRectExForDpiW>(GetProcAddress(_lib, "AdjustWindowRectExForDpi"));
// FreeLibrary(_lib);
// _is_read = true;
// }
// if ( _adjustWindowRectEx ) {
// _adjustWindowRectEx(rect, (GetWindowStyle(handle) & ~WS_DLGFRAME), FALSE, 0, 96*dpiratio);
// } else AdjustWindowRectEx(rect, (GetWindowStyle(handle) & ~WS_DLGFRAME), FALSE, 0);
// }
auto bringToTop(HWND hwnd) -> void
{
DWORD appID = ::GetCurrentThreadId();
DWORD frgID = ::GetWindowThreadProcessId(::GetForegroundWindow(), NULL);
::AttachThreadInput(frgID, appID, TRUE);
::SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
::SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
::SetForegroundWindow(hwnd);
::SetFocus(hwnd);
::SetActiveWindow(hwnd);
::AttachThreadInput(frgID, appID, FALSE);
}
auto toggleLayoutDirection(HWND hwnd) -> void
{
LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
if (exstyle & WS_EX_LAYOUTRTL)
SetWindowLong(hwnd, GWL_EXSTYLE, exstyle & ~WS_EX_LAYOUTRTL);
else
if (AscAppManager::isRtlEnabled())
SetWindowLong(hwnd, GWL_EXSTYLE, exstyle | WS_EX_LAYOUTRTL);
}
#endif
// auto correctWindowMinimumSize(const QRect& windowrect, const QSize& minsize) -> QSize
// {
// QRect _screen_size = Utils::getScreenGeometry(windowrect.topLeft());
// QSize _window_min_size{minsize};
// if ( _window_min_size.width() > _screen_size.size().width() || _window_min_size.height() > _screen_size.size().height() )
// _window_min_size.scale(_screen_size.size() - QSize(50,50), Qt::KeepAspectRatio);
// return _window_min_size;
// }
auto isLeftButtonPressed() -> bool {
#ifdef Q_OS_LINUX
return check_button_state(Qt::LeftButton);
#else
return (::GetKeyState(VK_LBUTTON) & 0x8000) != 0;
#endif
}
auto constructFullscreenWidget(QWidget * panelwidget) -> CFullScrWidget *
{
#if defined(_WIN32) && (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
QPoint pt = panelwidget->window()->mapToGlobal(panelwidget->pos());
#else
QPoint pt = panelwidget->mapToGlobal(panelwidget->pos());
#endif
CTabPanel * _panel = qobject_cast<CTabPanel *>(panelwidget);
CFullScrWidget * _parent = new CFullScrWidget;
_parent->setWindowIcon(Utils::appIcon());
_parent->setWindowTitle(_panel->data()->title());
QRect _scr_geometry;
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
int _scr_count = QApplication::desktop()->screenCount();
if ( _scr_count > 1 ) {
int _scrNum = QApplication::desktop()->screenNumber(pt);
if ( _panel->reporterMode() ) {
_scr_geometry = QApplication::desktop()->screenGeometry(_scr_count - _scrNum - 1);
} else _scr_geometry = QApplication::desktop()->screenGeometry(_scrNum);
} else {
_scr_geometry = QApplication::desktop()->screenGeometry(QApplication::desktop()->primaryScreen());
}
#else
int _scr_count = QApplication::screens().count();
if ( _scr_count > 1 ) {
QScreen * _screen = QApplication::screenAt(pt);
if ( _panel->reporterMode() ) {
int _scrNum = QApplication::screens().indexOf(_screen);
_scr_geometry = QApplication::screens().at(_scr_count - _scrNum - 1)->geometry();
} else _scr_geometry = _screen->geometry();
} else {
_scr_geometry = QApplication::primaryScreen()->geometry();
}
#endif
_parent->setGeometry(_scr_geometry);
_parent->showFullScreen();
_panel->setParent(_parent);
_panel->show();
_panel->setGeometry(0,0,_parent->width(),_parent->height());
return _parent;
}
auto useNativeDialog() -> bool
{
bool use_native_dialog = true;
#ifdef FILEDIALOG_DONT_USE_NATIVEDIALOGS
use_native_dialog = InputArgs::contains(L"--native-file-dialog");
#endif
return use_native_dialog;
}
auto activeWindow() -> QWidget*
{
#ifdef _WIN32
HWND hwnd_top = GetForegroundWindow();
QWidget *wgt = QWidget::find((WId)hwnd_top);
return (wgt && wgt->isWindow()) ? wgt : nullptr;
#else
return QApplication::activeWindow();
#endif
}
auto currentTopWindow() -> QWidget*
{
QStringList wnd_list{"MainWindow", "editorWindow"};
QWidget *wgt = activeWindow();
if (wgt && wnd_list.contains(wgt->objectName()) && !wgt->isMinimized()
&& wgt->property("stabilized").toBool())
return wgt;
return nullptr;
}
auto defaultWindowMaximizeState() -> bool
{
GET_REGISTRY_USER(reg_user);
if (reg_user.contains("position") || reg_user.childGroups().contains("EditorsGeometry"))
return false;
auto scr_rc = qApp->primaryScreen()->geometry();
return (scr_rc.width() <= SCREEN_THRESHOLD_SIZE.width() || scr_rc.height() <= SCREEN_THRESHOLD_SIZE.height());
}
}