diff --git a/src/widgets/executablefileopendialog.cpp b/src/widgets/executablefileopendialog.cpp --- a/src/widgets/executablefileopendialog.cpp +++ b/src/widgets/executablefileopendialog.cpp @@ -27,35 +27,48 @@ #include -ExecutableFileOpenDialog::ExecutableFileOpenDialog(QWidget *parent) : +ExecutableFileOpenDialog::ExecutableFileOpenDialog(ExecutableFileOpenDialog::Mode mode, QWidget *parent) : QDialog(parent) { QLabel *label = new QLabel(i18n("What do you wish to do with this executable file?"), this); m_dontAskAgain = new QCheckBox(this); m_dontAskAgain->setText(i18n("Do not ask again")); - QPushButton *openButton = new QPushButton(i18n("&Open"), this); - QPushButton *executeButton = new QPushButton(i18n("&Execute"), this); + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel, this); - openButton->setIcon(QIcon::fromTheme(QStringLiteral("document-preview"))); - executeButton->setIcon(QIcon::fromTheme(QStringLiteral("system-run"))); + QPushButton *openButton; + if (mode == OpenOrExecute) { + openButton = new QPushButton(i18n("&Open"), this); + openButton->setIcon(QIcon::fromTheme(QStringLiteral("document-preview"))); + buttonBox->addButton(openButton, QDialogButtonBox::AcceptRole); + } - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel, this); - buttonBox->addButton(openButton, QDialogButtonBox::AcceptRole); + QPushButton *executeButton = new QPushButton(i18n("&Execute"), this); + executeButton->setIcon(QIcon::fromTheme(QStringLiteral("system-run"))); buttonBox->addButton(executeButton, QDialogButtonBox::AcceptRole); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(label); layout->addWidget(m_dontAskAgain); layout->addWidget(buttonBox); setLayout(layout); - connect(openButton, &QPushButton::clicked, [=]{done(OpenFile);}); - connect(executeButton, &QPushButton::clicked, [=]{done(ExecuteFile);}); + + if (mode == OnlyExecute) { + connect(executeButton, &QPushButton::clicked, [=]{done(ExecuteFile);}); + } else if (mode == OpenAsExecute) { + connect(executeButton, &QPushButton::clicked, [=]{done(OpenFile);}); + } else { + connect(openButton, &QPushButton::clicked, [=]{done(OpenFile);}); + connect(executeButton, &QPushButton::clicked, [=]{done(ExecuteFile);}); + } connect(buttonBox, &QDialogButtonBox::rejected, this, &ExecutableFileOpenDialog::reject); } +ExecutableFileOpenDialog::ExecutableFileOpenDialog(QWidget *parent) : + ExecutableFileOpenDialog(ExecutableFileOpenDialog::OpenOrExecute, parent) { } + bool ExecutableFileOpenDialog::isDontAskAgainChecked() const { return m_dontAskAgain->isChecked(); diff --git a/src/widgets/executablefileopendialog_p.h b/src/widgets/executablefileopendialog_p.h --- a/src/widgets/executablefileopendialog_p.h +++ b/src/widgets/executablefileopendialog_p.h @@ -36,6 +36,19 @@ OpenFile = 42, ExecuteFile }; + + enum Mode { + // For executable scripts + OpenOrExecute, + // For native binary executables + OnlyExecute, + // For *.exe files, open with WINE is like execute the file + // In this case, openAsExecute is true, we hide "Open" button and connect + // "Execute" button to OpenFile action. + OpenAsExecute + }; + + explicit ExecutableFileOpenDialog(Mode mode, QWidget* parent = nullptr); explicit ExecutableFileOpenDialog(QWidget* parent = nullptr); bool isDontAskAgainChecked() const; diff --git a/src/widgets/krun.cpp b/src/widgets/krun.cpp --- a/src/widgets/krun.cpp +++ b/src/widgets/krun.cpp @@ -58,7 +58,6 @@ #include "kopenwithdialog.h" #include "krecentdocument.h" #include "kdesktopfileactions.h" -#include "executablefileopendialog_p.h" #include #include @@ -155,15 +154,13 @@ QMimeDatabase db; QMimeType mimeType = db.mimeTypeForName(mimetype); if (!mimeType.inherits(QStringLiteral("application/x-executable")) -#ifdef Q_OS_WIN && !mimeType.inherits(QStringLiteral("application/x-ms-dos-executable")) -#endif && !mimeType.inherits(QStringLiteral("application/x-executable-script")) && !mimeType.inherits(QStringLiteral("application/x-sharedlib"))) { return false; } - if (!hasExecuteBit(url.toLocalFile())) { + if (!hasExecuteBit(url.toLocalFile()) && !mimeType.inherits(QStringLiteral("application/x-ms-dos-executable"))) { return false; } @@ -357,29 +354,21 @@ } else if (isExecutable(_mimetype)) { // Check whether file is executable script const QMimeType mime = db.mimeTypeForName(_mimetype); - bool isTextFile = mime.inherits(QStringLiteral("text/plain")); +#ifdef Q_OS_WIN + bool isNativeBinary = !mime.inherits(QStringLiteral("text/plain")); +#else + bool isNativeBinary = !mime.inherits(QStringLiteral("text/plain")) && !mime.inherits(QStringLiteral("application/x-ms-dos-executable")); +#endif // Only run local files if (u.isLocalFile() && runExecutables) { if (KAuthorized::authorize(QStringLiteral("shell_access"))) { bool canRun = true; bool isFileExecutable = hasExecuteBit(u.toLocalFile()); -#ifdef Q_OS_WIN - // On Windows, run all executables normally - const bool supportsRunningExecutable = true; -#else - // On non-Windows systems, this will prevent Windows executables - // from being run, so that programs like Wine can handle them instead. - const bool supportsRunningExecutable = !mime.inherits(QStringLiteral("application/x-ms-dos-executable")); -#endif - - if (!supportsRunningExecutable) { - // Don't run Windows executables on non-Windows platform - canRun = false; - } else if (!isFileExecutable && !isTextFile) { - // For executables that aren't scripts and without execute bit, - // show prompt asking user if he wants to run the program. + // For executables that aren't scripts and without execute bit, + // show prompt asking user if he wants to run the program. + if (!isFileExecutable && isNativeBinary) { canRun = false; int result = showUntrustedProgramWarning(u.fileName(), window); if (result == QDialog::Accepted) { @@ -394,8 +383,8 @@ canRun = true; } } - } else if (!isFileExecutable && isTextFile) { - // Don't try to run scripts without execute bit, instead + } else if (!isFileExecutable && !isNativeBinary) { + // Don't try to run scripts/exes without execute bit, instead // open them with default application canRun = false; } @@ -410,7 +399,7 @@ // Show no permission warning noAuth = true; } - } else if (!isTextFile) { + } else if (isNativeBinary) { // Show warning for executables that aren't scripts noRun = true; } @@ -1070,7 +1059,7 @@ void KRun::KRunPrivate::showPrompt() { - ExecutableFileOpenDialog *dialog = new ExecutableFileOpenDialog(q->window()); + ExecutableFileOpenDialog *dialog = new ExecutableFileOpenDialog(promptMode(), q->window()); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, &ExecutableFileOpenDialog::finished, q, [this, dialog](int result){ onDialogFinished(result, dialog->isDontAskAgainChecked()); @@ -1088,9 +1077,8 @@ const bool isFileExecutable = (isExecutableFile(m_strURL, mime.name()) || mime.inherits(QStringLiteral("application/x-desktop"))); - const bool isTextFile = mime.inherits(QStringLiteral("text/plain")); - if (isFileExecutable && isTextFile) { + if (isFileExecutable) { KConfigGroup cfgGroup(KSharedConfig::openConfig(QStringLiteral("kiorc")), "Executable scripts"); const QString value = cfgGroup.readEntry("behaviourOnLaunch", "alwaysAsk"); @@ -1104,6 +1092,19 @@ return false; } +ExecutableFileOpenDialog::Mode KRun::KRunPrivate::promptMode() +{ + const QMimeDatabase db; + const QMimeType mime = db.mimeTypeForUrl(m_strURL); + if (mime.inherits(QStringLiteral("text/plain"))) { + return ExecutableFileOpenDialog::OpenOrExecute; + } else if (mime.inherits(QStringLiteral("application/x-ms-dos-executable"))) { + return ExecutableFileOpenDialog::OpenAsExecute; + } else { + return ExecutableFileOpenDialog::OnlyExecute; + } +} + void KRun::KRunPrivate::onDialogFinished(int result, bool isDontAskAgainSet) { if (result == ExecutableFileOpenDialog::Rejected) { diff --git a/src/widgets/krun_p.h b/src/widgets/krun_p.h --- a/src/widgets/krun_p.h +++ b/src/widgets/krun_p.h @@ -30,6 +30,7 @@ #include class KProcess; +#include "executablefileopendialog_p.h" #include "kstartupinfo.h" /** @@ -129,6 +130,7 @@ * Check whether we need to show a prompt(before executing a script or desktop file) */ bool isPromptNeeded(); + ExecutableFileOpenDialog::Mode promptMode(); void onDialogFinished(int result, bool isDontAskAgainSet); KRun * const q;