Specify parent window for popups. (#3406)
Some checks failed
CI / ${{ matrix.name }} (/usr/bin/gcc-12, /usr/bin/g++-12, ubuntu:22.04, linux-x86_64-system-deps, false, 3.11.x, true, false) (push) Has been cancelled
CI / ${{ matrix.name }} (default, default, 6) (push) Has been cancelled
CI / ${{ matrix.name }} (ubuntu:20.04, linux-x86_64, true, 3.6.x, false, false) (push) Has been cancelled
CI / ${{ matrix.name }} (ubuntu:20.04, tarball, false, 3.6.x, false, true) (push) Has been cancelled
CI / ${{ matrix.name }} (/usr/bin/gcc-7, /usr/bin/g++-7, ubuntu:18.04, linux-x86_64-qt5-system-deps, false, 3.6.x, 5, true) (push) Has been cancelled
CI / ${{ matrix.name }} (ubuntu:18.04, linux-x86_64-qt5, true, 3.6.x, 5, false) (push) Has been cancelled
CI / ${{ matrix.name }} () (push) Has been cancelled
CI / ${{ matrix.name }} (3.12.x) (push) Has been cancelled
CI / ${{ matrix.name }} (arm64, macos-arm64, macos-14, artifact_macos, true) (push) Has been cancelled
CI / ${{ matrix.name }} (false) (push) Has been cancelled
CI / ${{ matrix.name }} (windows-x86_64, windows-2019, artifact_windows, true, 3.12.x) (push) Has been cancelled
CI / ${{ matrix.name }} (x86_64, macos-x86_64, macos-13, true) (push) Has been cancelled
Docs / deploy (push) Has been cancelled
Linter / changes (push) Has been cancelled
CI / plugin-test-${{ matrix.name }} (build, artifact_macos, macos-arm64, macos-14) (push) Has been cancelled
CI / plugin-test-${{ matrix.name }} (build, artifact_windows, windows, windows-2019) (push) Has been cancelled
CI / plugin-test-${{ matrix.name }} (build-linux, artifact_linux, linux-x86_64, ubuntu-20.04) (push) Has been cancelled
Linter / clang-format (push) Has been cancelled
coverity-scan / latest (push) Has been cancelled

* Specify parrent window for popups.

Message boxes without parent are almost always a mistake. Such message boxes
* Aren't properly position on top of current window, instead they get placed in the corner of screen possibly away from main window.
* They get treated as separate window by window manager, but they still prevent proper interaction with main window. If you alt tab the message box can get lost, resulting in confusing behavior where you don't know why you can't interact with main window.
This commit is contained in:
karliss 2025-01-22 13:39:35 +02:00 committed by GitHub
parent d5088a51ae
commit 3652cb7b23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 40 additions and 24 deletions

View File

@ -6,6 +6,12 @@
#include <QObject> #include <QObject>
#include <QMessageBox> #include <QMessageBox>
#include <QJsonObject> #include <QJsonObject>
#include <qwidget.h>
IOModesController::IOModesController(QWidget *parentWindow)
: QObject(parentWindow), parentWindow(parentWindow)
{
}
bool IOModesController::canWrite() bool IOModesController::canWrite()
{ {
@ -48,7 +54,7 @@ bool IOModesController::prepareForWriting()
return true; return true;
} }
QMessageBox msgBox; QMessageBox msgBox(parentWindow);
msgBox.setIcon(QMessageBox::Icon::Critical); msgBox.setIcon(QMessageBox::Icon::Critical);
msgBox.setWindowTitle(QObject::tr("Write error")); msgBox.setWindowTitle(QObject::tr("Write error"));
msgBox.setText(QObject::tr( msgBox.setText(QObject::tr(
@ -91,7 +97,7 @@ bool IOModesController::askCommitUnsavedChanges()
// Check if there are uncommitted changes // Check if there are uncommitted changes
if (!allChangesComitted()) { if (!allChangesComitted()) {
QMessageBox::StandardButton ret = QMessageBox::question( QMessageBox::StandardButton ret = QMessageBox::question(
NULL, QObject::tr("Uncommitted changes"), parentWindow, QObject::tr("Uncommitted changes"),
QObject::tr("It seems that you have changes or patches that are not committed to " QObject::tr("It seems that you have changes or patches that are not committed to "
"the file.\n" "the file.\n"
"Do you want to commit them now?"), "Do you want to commit them now?"),

View File

@ -2,12 +2,14 @@
#define IOMODESCONTROLLER_H #define IOMODESCONTROLLER_H
#include "core/Cutter.h" #include "core/Cutter.h"
#include <qwidget.h>
class IOModesController : public QObject class IOModesController : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
IOModesController(QWidget *parent);
enum class Mode { READ_ONLY, CACHE, WRITE }; enum class Mode { READ_ONLY, CACHE, WRITE };
bool prepareForWriting(); bool prepareForWriting();
bool canWrite(); bool canWrite();
@ -17,6 +19,9 @@ public:
public slots: public slots:
bool askCommitUnsavedChanges(); bool askCommitUnsavedChanges();
private:
QWidget *parentWindow;
}; };
#endif // IOMODESCONTROLLER_H #endif // IOMODESCONTROLLER_H

View File

@ -129,7 +129,8 @@ T *getNewInstance(MainWindow *m)
using namespace Cutter; using namespace Cutter;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), core(Core()), ui(new Ui::MainWindow) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), core(Core()), ui(new Ui::MainWindow), ioModesController(this)
{ {
tabsOnTop = false; tabsOnTop = false;
configuration = Config(); configuration = Config();
@ -538,7 +539,7 @@ void MainWindow::openNewFile(InitialOptions &options, bool skipOptionsDialog)
if (options.script.isEmpty()) { if (options.script.isEmpty()) {
QString script = QString("%1.rz").arg(this->filename); QString script = QString("%1.rz").arg(this->filename);
if (rz_file_exists(script.toStdString().data())) { if (rz_file_exists(script.toStdString().data())) {
QMessageBox mb; QMessageBox mb(this);
mb.setWindowTitle(tr("Script loading")); mb.setWindowTitle(tr("Script loading"));
mb.setText(tr("Do you want to load the '%1' script?").arg(script)); mb.setText(tr("Do you want to load the '%1' script?").arg(script));
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No); mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);

View File

@ -95,7 +95,9 @@ void AboutDialog::on_checkForUpdatesButton_clicked()
#if CUTTER_UPDATE_WORKER_AVAILABLE #if CUTTER_UPDATE_WORKER_AVAILABLE
UpdateWorker updateWorker; UpdateWorker updateWorker;
QProgressDialog waitDialog; auto parentWindow = this;
QProgressDialog waitDialog(parentWindow);
QProgressBar *bar = new QProgressBar(&waitDialog); QProgressBar *bar = new QProgressBar(&waitDialog);
bar->setMaximum(0); bar->setMaximum(0);
@ -104,12 +106,12 @@ void AboutDialog::on_checkForUpdatesButton_clicked()
connect(&updateWorker, &UpdateWorker::checkComplete, &waitDialog, &QProgressDialog::cancel); connect(&updateWorker, &UpdateWorker::checkComplete, &waitDialog, &QProgressDialog::cancel);
connect(&updateWorker, &UpdateWorker::checkComplete, connect(&updateWorker, &UpdateWorker::checkComplete,
[&updateWorker](const QVersionNumber &version, const QString &error) { [&updateWorker, parentWindow](const QVersionNumber &version, const QString &error) {
if (!error.isEmpty()) { if (!error.isEmpty()) {
QMessageBox::critical(nullptr, tr("Error!"), error); QMessageBox::critical(parentWindow, tr("Error!"), error);
} else { } else {
if (version <= UpdateWorker::currentVersionNumber()) { if (version <= UpdateWorker::currentVersionNumber()) {
QMessageBox::information(nullptr, tr("Version control"), QMessageBox::information(parentWindow, tr("Version control"),
tr("Cutter is up to date!")); tr("Cutter is up to date!"));
} else { } else {
updateWorker.showUpdateDialog(false); updateWorker.showUpdateDialog(false);

View File

@ -62,7 +62,7 @@ void GlibcHeapInfoDialog::updateFields()
void GlibcHeapInfoDialog::saveChunkInfo() void GlibcHeapInfoDialog::saveChunkInfo()
{ {
QMessageBox msgBox; QMessageBox msgBox(this);
msgBox.setText("Do you want to overwrite chunk metadata?"); msgBox.setText("Do you want to overwrite chunk metadata?");
msgBox.setInformativeText( msgBox.setInformativeText(
"Any field which cannot be converted to a valid integer will be saved as zero"); "Any field which cannot be converted to a valid integer will be saved as zero");

View File

@ -53,7 +53,7 @@ bool RemoteDebugDialog::validate()
} else if (debugger == WINDBG) { } else if (debugger == WINDBG) {
return validatePath(); return validatePath();
} }
QMessageBox msgBox; QMessageBox msgBox(this);
msgBox.setText(tr("Invalid debugger")); msgBox.setText(tr("Invalid debugger"));
msgBox.exec(); msgBox.exec();
return false; return false;
@ -61,7 +61,7 @@ bool RemoteDebugDialog::validate()
bool RemoteDebugDialog::validateIp() bool RemoteDebugDialog::validateIp()
{ {
QMessageBox msgBox; QMessageBox msgBox(this);
QString ip = getIpOrPath(); QString ip = getIpOrPath();
if (QHostAddress(ip).isNull()) { if (QHostAddress(ip).isNull()) {
@ -74,7 +74,7 @@ bool RemoteDebugDialog::validateIp()
bool RemoteDebugDialog::validatePath() bool RemoteDebugDialog::validatePath()
{ {
QMessageBox msgBox; QMessageBox msgBox(this);
QString path = getIpOrPath(); QString path = getIpOrPath();
if (!QFileInfo(path).exists()) { if (!QFileInfo(path).exists()) {
@ -87,7 +87,7 @@ bool RemoteDebugDialog::validatePath()
bool RemoteDebugDialog::validatePort() bool RemoteDebugDialog::validatePort()
{ {
QMessageBox msgBox; QMessageBox msgBox(this);
int port = getPort(); int port = getPort();
if (port < 1 || port > 65535) { if (port < 1 || port > 65535) {

View File

@ -66,7 +66,7 @@ void WelcomeDialog::onLanguageComboBox_currentIndexChanged(int index)
QString language = ui->languageComboBox->itemText(index); QString language = ui->languageComboBox->itemText(index);
Config()->setLocaleByName(language); Config()->setLocaleByName(language);
QMessageBox mb; QMessageBox mb(this);
mb.setWindowTitle(tr("Language settings")); mb.setWindowTitle(tr("Language settings"));
mb.setText(tr("Language will be changed after next application start.")); mb.setText(tr("Language will be changed after next application start."));
mb.setIcon(QMessageBox::Information); mb.setIcon(QMessageBox::Information);

View File

@ -156,16 +156,16 @@ void AppearanceOptionsWidget::on_deleteButton_clicked()
{ {
QString currTheme = ui->colorComboBox->currentText(); QString currTheme = ui->colorComboBox->currentText();
if (!ThemeWorker().isCustomTheme(currTheme)) { if (!ThemeWorker().isCustomTheme(currTheme)) {
QMessageBox::critical(nullptr, tr("Error"), ThemeWorker().deleteTheme(currTheme)); QMessageBox::critical(this, tr("Error"), ThemeWorker().deleteTheme(currTheme));
return; return;
} }
int ret = QMessageBox::question( int ret = QMessageBox::question(
nullptr, tr("Delete"), tr("Are you sure you want to delete <b>%1</b>?").arg(currTheme)); this, tr("Delete"), tr("Are you sure you want to delete <b>%1</b>?").arg(currTheme));
if (ret == QMessageBox::Yes) { if (ret == QMessageBox::Yes) {
QString err = ThemeWorker().deleteTheme(currTheme); QString err = ThemeWorker().deleteTheme(currTheme);
updateThemeFromConfig(false); updateThemeFromConfig(false);
if (!err.isEmpty()) { if (!err.isEmpty()) {
QMessageBox::critical(nullptr, tr("Error"), err); QMessageBox::critical(this, tr("Error"), err);
} }
} }
} }

View File

@ -25,6 +25,7 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
offset(0), offset(0),
canCopy(false), canCopy(false),
mainWindow(mainWindow), mainWindow(mainWindow),
ioModesController(mainWindow),
actionEditInstruction(this), actionEditInstruction(this),
actionNopInstruction(this), actionNopInstruction(this),
actionJmpReverse(this), actionJmpReverse(this),

View File

@ -143,7 +143,7 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main),
reverseActions = { actionStepBack, actionContinueBack }; reverseActions = { actionStepBack, actionContinueBack };
connect(Core(), &CutterCore::debugProcessFinished, this, [=](int pid) { connect(Core(), &CutterCore::debugProcessFinished, this, [=](int pid) {
QMessageBox msgBox; QMessageBox msgBox(main);
msgBox.setText(tr("Debugged process exited (") + QString::number(pid) + ")"); msgBox.setText(tr("Debugged process exited (") + QString::number(pid) + ")");
msgBox.exec(); msgBox.exec();
}); });
@ -262,7 +262,7 @@ void DebugActions::showDebugWarning()
{ {
if (!acceptedDebugWarning) { if (!acceptedDebugWarning) {
acceptedDebugWarning = true; acceptedDebugWarning = true;
QMessageBox msgBox; QMessageBox msgBox(main);
msgBox.setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse); msgBox.setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
msgBox.setText(tr("Debug is currently in beta.\n") msgBox.setText(tr("Debug is currently in beta.\n")
+ tr("If you encounter any problems or have suggestions, please submit an " + tr("If you encounter any problems or have suggestions, please submit an "
@ -302,7 +302,7 @@ void DebugActions::onAttachedRemoteDebugger(bool successfully)
return; return;
if (!successfully) { if (!successfully) {
QMessageBox msgBox; QMessageBox msgBox(main);
msgBox.setText(tr("Error connecting.")); msgBox.setText(tr("Error connecting."));
msgBox.exec(); msgBox.exec();
attachRemoteDialog(); attachRemoteDialog();
@ -326,7 +326,7 @@ void DebugActions::attachRemoteDialog()
if (!remoteDialog) { if (!remoteDialog) {
remoteDialog = new RemoteDebugDialog(main); remoteDialog = new RemoteDebugDialog(main);
} }
QMessageBox msgBox; QMessageBox msgBox(main);
bool success = false; bool success = false;
while (!success) { while (!success) {
success = true; success = true;
@ -355,7 +355,7 @@ void DebugActions::attachProcessDialog()
attachProcess(pid); attachProcess(pid);
} else { } else {
success = false; success = false;
QMessageBox msgBox; QMessageBox msgBox(main);
msgBox.setText(tr("Error attaching. No process selected!")); msgBox.setText(tr("Error attaching. No process selected!"));
msgBox.exec(); msgBox.exec();
} }
@ -384,7 +384,7 @@ void DebugActions::startDebug()
QFileInfo info(filename); QFileInfo info(filename);
if (!Core()->currentlyDebugging && !info.isExecutable()) { if (!Core()->currentlyDebugging && !info.isExecutable()) {
QMessageBox msgBox; QMessageBox msgBox(main);
msgBox.setText(tr("File '%1' does not have executable permissions.").arg(filename)); msgBox.setText(tr("File '%1' does not have executable permissions.").arg(filename));
msgBox.exec(); msgBox.exec();
return; return;

View File

@ -44,6 +44,7 @@ HexWidget::HexWidget(QWidget *parent)
showAscii(true), showAscii(true),
showExHex(true), showExHex(true),
showExAddr(true), showExAddr(true),
ioModesController(parent),
warningTimer(this) warningTimer(this)
{ {
setMouseTracking(true); setMouseTracking(true);

View File

@ -157,7 +157,7 @@ void ProcessesWidget::onActivated(const QModelIndex &index)
// attach to any given id. If it isn't found simply update the UI. // attach to any given id. If it isn't found simply update the UI.
for (const auto &value : Core()->getAllProcesses()) { for (const auto &value : Core()->getAllProcesses()) {
if (pid == value.pid) { if (pid == value.pid) {
QMessageBox msgBox; QMessageBox msgBox(this);
switch (value.status) { switch (value.status) {
case RZ_DBG_PROC_ZOMBIE: case RZ_DBG_PROC_ZOMBIE:
case RZ_DBG_PROC_DEAD: case RZ_DBG_PROC_DEAD: