mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-20 21:33:27 -07:00
Merge pull request #5575 from Chocobo1/explorer
Avoid spawning a new explorer.exe process when selecting "Open containing folder"
This commit is contained in:
commit
affebf3431
2 changed files with 65 additions and 91 deletions
|
@ -52,6 +52,7 @@
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <powrprof.h>
|
#include <powrprof.h>
|
||||||
|
#include <Shlobj.h>
|
||||||
const int UNLEN = 256;
|
const int UNLEN = 256;
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -233,6 +234,7 @@ QPoint Utils::Misc::screenCenter(QWidget *win)
|
||||||
QRect desk(QApplication::desktop()->availableGeometry(scrn));
|
QRect desk(QApplication::desktop()->availableGeometry(scrn));
|
||||||
return QPoint((desk.width() - win->frameGeometry().width()) / 2, (desk.height() - win->frameGeometry().height()) / 2);
|
return QPoint((desk.width() - win->frameGeometry().width()) / 2, (desk.height() - win->frameGeometry().height()) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,12 +269,12 @@ QString Utils::Misc::pythonExecutable()
|
||||||
* http://legacy.python.org/dev/peps/pep-0394/
|
* http://legacy.python.org/dev/peps/pep-0394/
|
||||||
*/
|
*/
|
||||||
pythonProc.start("python3", QStringList() << "--version", QIODevice::ReadOnly);
|
pythonProc.start("python3", QStringList() << "--version", QIODevice::ReadOnly);
|
||||||
if (pythonProc.waitForFinished() && pythonProc.exitCode() == 0) {
|
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
||||||
executable = "python3";
|
executable = "python3";
|
||||||
return executable;
|
return executable;
|
||||||
}
|
}
|
||||||
pythonProc.start("python2", QStringList() << "--version", QIODevice::ReadOnly);
|
pythonProc.start("python2", QStringList() << "--version", QIODevice::ReadOnly);
|
||||||
if (pythonProc.waitForFinished() && pythonProc.exitCode() == 0) {
|
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
||||||
executable = "python2";
|
executable = "python2";
|
||||||
return executable;
|
return executable;
|
||||||
}
|
}
|
||||||
|
@ -280,7 +282,7 @@ QString Utils::Misc::pythonExecutable()
|
||||||
// Look for "python" in Windows and in UNIX if "python2" and "python3" are
|
// Look for "python" in Windows and in UNIX if "python2" and "python3" are
|
||||||
// not detected.
|
// not detected.
|
||||||
pythonProc.start("python", QStringList() << "--version", QIODevice::ReadOnly);
|
pythonProc.start("python", QStringList() << "--version", QIODevice::ReadOnly);
|
||||||
if (pythonProc.waitForFinished() && pythonProc.exitCode() == 0)
|
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0))
|
||||||
executable = "python";
|
executable = "python";
|
||||||
else
|
else
|
||||||
Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python not detected"), Log::INFO);
|
Logger::instance()->addMessage(QCoreApplication::translate("misc", "Python not detected"), Log::INFO);
|
||||||
|
@ -293,14 +295,15 @@ QString Utils::Misc::pythonExecutable()
|
||||||
* eg 2.7.9
|
* eg 2.7.9
|
||||||
* Make sure to have setup python first
|
* Make sure to have setup python first
|
||||||
*/
|
*/
|
||||||
QString Utils::Misc::pythonVersionComplete() {
|
QString Utils::Misc::pythonVersionComplete()
|
||||||
|
{
|
||||||
static QString version;
|
static QString version;
|
||||||
if (version.isEmpty()) {
|
if (version.isEmpty()) {
|
||||||
if (pythonExecutable().isEmpty())
|
if (pythonExecutable().isEmpty())
|
||||||
return version;
|
return version;
|
||||||
QProcess pythonProc;
|
QProcess pythonProc;
|
||||||
pythonProc.start(pythonExecutable(), QStringList() << "--version", QIODevice::ReadOnly);
|
pythonProc.start(pythonExecutable(), QStringList() << "--version", QIODevice::ReadOnly);
|
||||||
if (pythonProc.waitForFinished() && pythonProc.exitCode() == 0) {
|
if (pythonProc.waitForFinished() && (pythonProc.exitCode() == 0)) {
|
||||||
QByteArray output = pythonProc.readAllStandardOutput();
|
QByteArray output = pythonProc.readAllStandardOutput();
|
||||||
if (output.isEmpty())
|
if (output.isEmpty())
|
||||||
output = pythonProc.readAllStandardError();
|
output = pythonProc.readAllStandardError();
|
||||||
|
@ -349,9 +352,8 @@ QString Utils::Misc::friendlyUnit(qint64 bytesValue, bool isSpeed)
|
||||||
{
|
{
|
||||||
SizeUnit unit;
|
SizeUnit unit;
|
||||||
qreal friendlyVal;
|
qreal friendlyVal;
|
||||||
if (!friendlyUnit(bytesValue, friendlyVal, unit)) {
|
if (!friendlyUnit(bytesValue, friendlyVal, unit))
|
||||||
return QCoreApplication::translate("misc", "Unknown", "Unknown (size)");
|
return QCoreApplication::translate("misc", "Unknown", "Unknown (size)");
|
||||||
}
|
|
||||||
QString ret;
|
QString ret;
|
||||||
if (unit == SizeUnit::Byte)
|
if (unit == SizeUnit::Byte)
|
||||||
ret = QString::number(bytesValue) + " " + unitString(unit);
|
ret = QString::number(bytesValue) + " " + unitString(unit);
|
||||||
|
@ -364,9 +366,8 @@ QString Utils::Misc::friendlyUnit(qint64 bytesValue, bool isSpeed)
|
||||||
|
|
||||||
qlonglong Utils::Misc::sizeInBytes(qreal size, Utils::Misc::SizeUnit unit)
|
qlonglong Utils::Misc::sizeInBytes(qreal size, Utils::Misc::SizeUnit unit)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < static_cast<int>(unit); ++i) {
|
for (int i = 0; i < static_cast<int>(unit); ++i)
|
||||||
size *= 1024;
|
size *= 1024;
|
||||||
}
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,7 +428,7 @@ bool Utils::Misc::isPreviewable(const QString& extension)
|
||||||
// time duration like "1d 2h 10m".
|
// time duration like "1d 2h 10m".
|
||||||
QString Utils::Misc::userFriendlyDuration(qlonglong seconds)
|
QString Utils::Misc::userFriendlyDuration(qlonglong seconds)
|
||||||
{
|
{
|
||||||
if (seconds < 0 || seconds >= MAX_ETA)
|
if ((seconds < 0) || (seconds >= MAX_ETA))
|
||||||
return QString::fromUtf8(C_INFINITY);
|
return QString::fromUtf8(C_INFINITY);
|
||||||
if (seconds == 0)
|
if (seconds == 0)
|
||||||
return "0";
|
return "0";
|
||||||
|
@ -572,70 +573,42 @@ void Utils::Misc::openPath(const QString& absolutePath)
|
||||||
void Utils::Misc::openFolderSelect(const QString &absolutePath)
|
void Utils::Misc::openFolderSelect(const QString &absolutePath)
|
||||||
{
|
{
|
||||||
const QString path = Utils::Fs::fromNativePath(absolutePath);
|
const QString path = Utils::Fs::fromNativePath(absolutePath);
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
if (QFileInfo(path).exists()) {
|
|
||||||
// Syntax is: explorer /select, "C:\Folder1\Folder2\file_to_select"
|
|
||||||
// Dir separators MUST be win-style slashes
|
|
||||||
|
|
||||||
// QProcess::startDetached() has an obscure bug. If the path has
|
|
||||||
// no spaces and a comma(and maybe other special characters) it doesn't
|
|
||||||
// get wrapped in quotes. So explorer.exe can't find the correct path and
|
|
||||||
// displays the default one. If we wrap the path in quotes and pass it to
|
|
||||||
// QProcess::startDetached() explorer.exe still shows the default path. In
|
|
||||||
// this case QProcess::startDetached() probably puts its own quotes around ours.
|
|
||||||
|
|
||||||
STARTUPINFO startupInfo;
|
|
||||||
::ZeroMemory(&startupInfo, sizeof(startupInfo));
|
|
||||||
startupInfo.cb = sizeof(startupInfo);
|
|
||||||
|
|
||||||
PROCESS_INFORMATION processInfo;
|
|
||||||
::ZeroMemory(&processInfo, sizeof(processInfo));
|
|
||||||
|
|
||||||
QString cmd = QString("explorer.exe /select,\"%1\"").arg(Utils::Fs::toNativePath(absolutePath));
|
|
||||||
LPWSTR lpCmd = new WCHAR[cmd.size() + 1];
|
|
||||||
cmd.toWCharArray(lpCmd);
|
|
||||||
lpCmd[cmd.size()] = 0;
|
|
||||||
|
|
||||||
bool ret = ::CreateProcessW(NULL, lpCmd, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
|
|
||||||
delete [] lpCmd;
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
::CloseHandle(processInfo.hProcess);
|
|
||||||
::CloseHandle(processInfo.hThread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// If the item to select doesn't exist, try to open its parent
|
// If the item to select doesn't exist, try to open its parent
|
||||||
|
if (!QFileInfo(path).exists()) {
|
||||||
openPath(path.left(path.lastIndexOf("/")));
|
openPath(path.left(path.lastIndexOf("/")));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
HRESULT hresult = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
|
ITEMIDLIST *pidl = ::ILCreateFromPathW(reinterpret_cast<PCTSTR>(Utils::Fs::toNativePath(path).utf16()));
|
||||||
|
if (pidl) {
|
||||||
|
::SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0);
|
||||||
|
::ILFree(pidl);
|
||||||
|
}
|
||||||
|
if ((hresult == S_OK) || (hresult == S_FALSE))
|
||||||
|
::CoUninitialize();
|
||||||
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
||||||
if (QFileInfo(path).exists()) {
|
|
||||||
QProcess proc;
|
QProcess proc;
|
||||||
proc.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory");
|
proc.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory");
|
||||||
proc.waitForFinished();
|
proc.waitForFinished();
|
||||||
QString output = proc.readLine().simplified();
|
QString output = proc.readLine().simplified();
|
||||||
if (output == "dolphin.desktop" || output == "org.kde.dolphin.desktop")
|
if ((output == "dolphin.desktop") || (output == "org.kde.dolphin.desktop"))
|
||||||
proc.startDetached("dolphin", QStringList() << "--select" << Utils::Fs::toNativePath(path));
|
proc.startDetached("dolphin", QStringList() << "--select" << Utils::Fs::toNativePath(path));
|
||||||
else if (output == "nautilus.desktop" || output == "org.gnome.Nautilus.desktop"
|
else if ((output == "nautilus.desktop") || (output == "org.gnome.Nautilus.desktop")
|
||||||
|| output == "nautilus-folder-handler.desktop")
|
|| (output == "nautilus-folder-handler.desktop"))
|
||||||
proc.startDetached("nautilus", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path));
|
proc.startDetached("nautilus", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path));
|
||||||
else if (output == "nemo.desktop")
|
else if (output == "nemo.desktop")
|
||||||
proc.startDetached("nemo", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path));
|
proc.startDetached("nemo", QStringList() << "--no-desktop" << Utils::Fs::toNativePath(path));
|
||||||
else if (output == "konqueror.desktop" || output == "kfmclient_dir.desktop")
|
else if ((output == "konqueror.desktop") || (output == "kfmclient_dir.desktop"))
|
||||||
proc.startDetached("konqueror", QStringList() << "--select" << Utils::Fs::toNativePath(path));
|
proc.startDetached("konqueror", QStringList() << "--select" << Utils::Fs::toNativePath(path));
|
||||||
else {
|
else
|
||||||
// "caja" manager can't pinpoint the file, see: https://github.com/qbittorrent/qBittorrent/issues/5003
|
// "caja" manager can't pinpoint the file, see: https://github.com/qbittorrent/qBittorrent/issues/5003
|
||||||
openPath(path.left(path.lastIndexOf("/")));
|
openPath(path.left(path.lastIndexOf("/")));
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// If the item to select doesn't exist, try to open its parent
|
|
||||||
openPath(path.left(path.lastIndexOf("/")));
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
openPath(path.left(path.lastIndexOf("/")));
|
openPath(path.left(path.lastIndexOf("/")));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DISABLE_GUI
|
#endif // DISABLE_GUI
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -663,6 +636,7 @@ QSize Utils::Misc::smallIconSize()
|
||||||
int s = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
|
int s = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||||
return QSize(s, s);
|
return QSize(s, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString Utils::Misc::osName()
|
QString Utils::Misc::osName()
|
||||||
|
|
|
@ -37,8 +37,8 @@ DEFINES += _UNICODE
|
||||||
DEFINES += WIN32
|
DEFINES += WIN32
|
||||||
DEFINES += _WIN32
|
DEFINES += _WIN32
|
||||||
DEFINES += WIN32_LEAN_AND_MEAN
|
DEFINES += WIN32_LEAN_AND_MEAN
|
||||||
DEFINES += _WIN32_WINNT=0x0500
|
DEFINES += _WIN32_WINNT=0x0501
|
||||||
DEFINES += _WIN32_IE=0x0500
|
DEFINES += _WIN32_IE=0x0501
|
||||||
DEFINES += _CRT_SECURE_NO_DEPRECATE
|
DEFINES += _CRT_SECURE_NO_DEPRECATE
|
||||||
DEFINES += _SCL_SECURE_NO_DEPRECATE
|
DEFINES += _SCL_SECURE_NO_DEPRECATE
|
||||||
DEFINES += __USE_W32_SOCKETS
|
DEFINES += __USE_W32_SOCKETS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue