From 8a639bd13d4059d94ce064fecea8bd631b04303d Mon Sep 17 00:00:00 2001 From: cristian64 Date: Mon, 25 Aug 2025 18:03:27 +0100 Subject: [PATCH] DolphinQt: Center dialogs on top-level parent window. The `QtUtils::AdjustSizeWithinScreen()` function now centers the widget on their parent window after the widget's size is adjusted. This is required in some desktop environments (generally on Linux systems) to ensure that the just-resized widget remains aligned with its parent window. The creation of the **Cheats Manager** dialog is now deferred to first show, as creating it within the main window's constructor prevents the dialog from knowing the real position of its parent window, which is only properly calculated on first show. For the same reasons, the analytics prompt is now shown only when the application is ready (i.e. when the main window has been shown). | Before | After | | ------ | ----- | | [Dolphin Emulator] Misplaced analytics prompt | [Dolphin Emulator] Centered analytics prompt | | [Dolphin Emulator] Misplaced Settings dialog | [Dolphin Emulator] Centered Settings dialog | | [Dolphin Emulator] Misplaced Cheats Manager dialog | [Dolphin Emulator] Centered Cheats Manager dialog | --- Source/Core/DolphinQt/Main.cpp | 54 ++++++++++++++--------- Source/Core/DolphinQt/MainWindow.cpp | 24 ++++++---- Source/Core/DolphinQt/MainWindow.h | 2 +- Source/Core/DolphinQt/QtUtils/QtUtils.cpp | 23 ++++++++++ Source/Core/DolphinQt/QtUtils/QtUtils.h | 4 ++ 5 files changed, 78 insertions(+), 29 deletions(-) diff --git a/Source/Core/DolphinQt/Main.cpp b/Source/Core/DolphinQt/Main.cpp index 8ab4a21ee7b..a69c5af22e8 100644 --- a/Source/Core/DolphinQt/Main.cpp +++ b/Source/Core/DolphinQt/Main.cpp @@ -265,30 +265,44 @@ int main(int argc, char* argv[]) #if defined(USE_ANALYTICS) && USE_ANALYTICS if (!Config::Get(Config::MAIN_ANALYTICS_PERMISSION_ASKED)) { - ModalMessageBox analytics_prompt(&win); + // To ensure that the analytics prompt appears aligned with the center of the main window, + // the dialog is only shown after the application is ready, as only then it is guaranteed that + // the main window has been placed in its final position. + auto* const connection_context = new QObject(&win); + QObject::connect( + qApp, &QGuiApplication::applicationStateChanged, connection_context, + [connection_context, &win](const Qt::ApplicationState state) { + if (state != Qt::ApplicationState::ApplicationActive) + return; - analytics_prompt.setIcon(QMessageBox::Question); - analytics_prompt.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - analytics_prompt.setWindowTitle(QObject::tr("Allow Usage Statistics Reporting")); - analytics_prompt.setText( - QObject::tr("Do you authorize Dolphin to report information to Dolphin's developers?")); - analytics_prompt.setInformativeText( - QObject::tr("If authorized, Dolphin can collect data on its performance, " - "feature usage, and configuration, as well as data on your system's " - "hardware and operating system.\n\n" - "No private data is ever collected. This data helps us understand " - "how people and emulated games use Dolphin and prioritize our " - "efforts. It also helps us identify rare configurations that are " - "causing bugs, performance and stability issues.\n" - "This authorization can be revoked at any time through Dolphin's " - "settings.")); + // Severe the connection after the first run. + delete connection_context; - const int answer = analytics_prompt.exec(); + ModalMessageBox analytics_prompt(&win); - Config::SetBase(Config::MAIN_ANALYTICS_PERMISSION_ASKED, true); - Settings::Instance().SetAnalyticsEnabled(answer == QMessageBox::Yes); + analytics_prompt.setIcon(QMessageBox::Question); + analytics_prompt.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + analytics_prompt.setWindowTitle(QObject::tr("Allow Usage Statistics Reporting")); + analytics_prompt.setText(QObject::tr( + "Do you authorize Dolphin to report information to Dolphin's developers?")); + analytics_prompt.setInformativeText( + QObject::tr("If authorized, Dolphin can collect data on its performance, " + "feature usage, and configuration, as well as data on your system's " + "hardware and operating system.\n\n" + "No private data is ever collected. This data helps us understand " + "how people and emulated games use Dolphin and prioritize our " + "efforts. It also helps us identify rare configurations that are " + "causing bugs, performance and stability issues.\n" + "This authorization can be revoked at any time through Dolphin's " + "settings.")); - DolphinAnalytics::Instance().ReloadConfig(); + const int answer = analytics_prompt.exec(); + + Config::SetBase(Config::MAIN_ANALYTICS_PERMISSION_ASKED, true); + Settings::Instance().SetAnalyticsEnabled(answer == QMessageBox::Yes); + + DolphinAnalytics::Instance().ReloadConfig(); + }); } #endif diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index a8e4e0764d6..b5cc0813a30 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -256,12 +256,7 @@ MainWindow::MainWindow(Core::System& system, std::unique_ptr boo }); #endif - connect(m_cheats_manager, &CheatsManager::OpenGeneralSettings, this, - &MainWindow::ShowGeneralWindow); - #ifdef USE_RETRO_ACHIEVEMENTS - connect(m_cheats_manager, &CheatsManager::OpenAchievementSettings, this, - &MainWindow::ShowAchievementSettings); connect(m_game_list, &GameList::OpenAchievementSettings, this, &MainWindow::ShowAchievementSettings); #endif // USE_RETRO_ACHIEVEMENTS @@ -481,7 +476,6 @@ void MainWindow::CreateComponents() m_watch_widget = new WatchWidget(this); m_breakpoint_widget = new BreakpointWidget(this); m_code_widget = new CodeWidget(this); - m_cheats_manager = new CheatsManager(m_system, this); m_assembler_widget = new AssemblerWidget(this); const auto request_watch = [this](QString name, u32 addr) { @@ -523,8 +517,6 @@ void MainWindow::CreateComponents() }); connect(m_breakpoint_widget, &BreakpointWidget::ShowMemory, m_memory_widget, &MemoryWidget::SetAddress); - connect(m_cheats_manager, &CheatsManager::ShowMemory, m_memory_widget, &MemoryWidget::SetAddress); - connect(m_cheats_manager, &CheatsManager::RequestWatch, request_watch); } void MainWindow::ConnectMenuBar() @@ -2037,6 +2029,22 @@ void MainWindow::ShowResourcePackManager() void MainWindow::ShowCheatsManager() { + if (!m_cheats_manager) + { + m_cheats_manager = new CheatsManager(m_system, this); + + connect(m_cheats_manager, &CheatsManager::ShowMemory, m_memory_widget, + &MemoryWidget::SetAddress); + connect(m_cheats_manager, &CheatsManager::RequestWatch, m_watch_widget, &WatchWidget::AddWatch); + connect(m_cheats_manager, &CheatsManager::OpenGeneralSettings, this, + &MainWindow::ShowGeneralWindow); + +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_cheats_manager, &CheatsManager::OpenAchievementSettings, this, + &MainWindow::ShowAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS + } + m_cheats_manager->show(); } diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index 38250058ed8..0442fa28d44 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -281,6 +281,6 @@ private: RegisterWidget* m_register_widget; ThreadWidget* m_thread_widget; WatchWidget* m_watch_widget; - CheatsManager* m_cheats_manager; + CheatsManager* m_cheats_manager{}; QByteArray m_render_widget_geometry; }; diff --git a/Source/Core/DolphinQt/QtUtils/QtUtils.cpp b/Source/Core/DolphinQt/QtUtils/QtUtils.cpp index 5914448a916..6c64acfeb72 100644 --- a/Source/Core/DolphinQt/QtUtils/QtUtils.cpp +++ b/Source/Core/DolphinQt/QtUtils/QtUtils.cpp @@ -43,6 +43,29 @@ void AdjustSizeWithinScreen(QWidget* widget) const auto adj_screen_size = screen_size * 9 / 10; widget->resize(widget->sizeHint().boundedTo(adj_screen_size)); + + CenterOnParentWindow(widget); +} + +void CenterOnParentWindow(QWidget* const widget) +{ + // Find the top-level window. + const QWidget* const parent_widget{widget->parentWidget()}; + if (!parent_widget) + return; + const QWidget* const window{parent_widget->window()}; + + // Calculate position based on the widgets' size and position. + const QRect window_geometry{window->geometry()}; + const QSize window_size{window_geometry.size()}; + const QPoint window_pos{window_geometry.topLeft()}; + const QRect geometry{widget->geometry()}; + const QSize size{geometry.size()}; + const QPoint offset{(window_size.width() - size.width()) / 2, + (window_size.height() - size.height()) / 2}; + const QPoint pos{window_pos + offset}; + + widget->setGeometry(QRect(pos, size)); } } // namespace QtUtils diff --git a/Source/Core/DolphinQt/QtUtils/QtUtils.h b/Source/Core/DolphinQt/QtUtils/QtUtils.h index 715a6c67dbb..812808cf9f4 100644 --- a/Source/Core/DolphinQt/QtUtils/QtUtils.h +++ b/Source/Core/DolphinQt/QtUtils/QtUtils.h @@ -19,6 +19,10 @@ QWidget* CreateIconWarning(QWidget* parent, QStyle::StandardPixmap standard_pixm // Similar to QWidget::adjustSize except maximum size is 9/10 of screen rather than 2/3. void AdjustSizeWithinScreen(QWidget* widget); +// Centers the widget on its parent. It should be called after any adjustments to the widget's size +// has been applied. +void CenterOnParentWindow(QWidget* widget); + // A QWidget that returns the minimumSizeHint as the primary sizeHint. // Useful for QListWidget which hints a fairly large height even when entirely empty. // Usage: QtUtils::MinimumSizeHintWidget