From a7f334dc2a3eec0119d8b77ec3ff35bbc8aae5f9 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 3 Oct 2018 17:34:27 +1000 Subject: [PATCH 1/4] ControllerInterface: Don't crash on non-X11 QPA --- Source/Core/Core/Core.cpp | 2 +- Source/Core/DolphinQt/MainWindow.cpp | 21 ++++++++++++------- Source/Core/DolphinQt/MainWindow.h | 2 +- .../ControllerInterface.cpp | 20 +++++++++++------- .../ControllerInterface/ControllerInterface.h | 7 ++++--- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index c64eb1e22e..fff3e6bfff 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -459,7 +459,7 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi bool init_controllers = false; if (!g_controller_interface.IsInit()) { - g_controller_interface.Initialize(wsi.render_surface); + g_controller_interface.Initialize(wsi); Pad::Initialize(); Keyboard::Initialize(); init_controllers = true; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index ec15365e55..f02542da95 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -169,6 +169,7 @@ MainWindow::MainWindow(std::unique_ptr boot_parameters) : QMainW setWindowIcon(Resources::GetAppIcon()); setUnifiedTitleAndToolBarOnMac(true); setAcceptDrops(true); + setAttribute(Qt::WA_NativeWindow); InitControllers(); @@ -237,7 +238,7 @@ void MainWindow::InitControllers() if (g_controller_interface.IsInit()) return; - g_controller_interface.Initialize(reinterpret_cast(winId())); + g_controller_interface.Initialize(GetWindowSystemInfo(windowHandle())); Pad::Initialize(); Keyboard::Initialize(); Wiimote::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); @@ -874,7 +875,8 @@ void MainWindow::SetFullScreenResolution(bool fullscreen) // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. ChangeDisplaySettings(&screen_settings, CDS_FULLSCREEN); #elif defined(HAVE_XRANDR) && HAVE_XRANDR - m_xrr_config->ToggleDisplayMode(fullscreen); + if (m_xrr_config) + m_xrr_config->ToggleDisplayMode(fullscreen); #endif } @@ -1003,14 +1005,18 @@ void MainWindow::ShowGraphicsWindow() if (!m_graphics_window) { #if defined(HAVE_XRANDR) && HAVE_XRANDR - m_xrr_config = std::make_unique( - static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForWindow( - "display", windowHandle())), - winId()); + if (GetWindowSystemType() == WindowSystemType::X11) + { + m_xrr_config = std::make_unique( + static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForWindow( + "display", windowHandle())), + winId()); + } m_graphics_window = new GraphicsWindow(m_xrr_config.get(), this); #else m_graphics_window = new GraphicsWindow(nullptr, this); #endif + InstallHotkeyFilter(m_graphics_window); } m_graphics_window->show(); @@ -1273,7 +1279,8 @@ void MainWindow::NetPlayQuit() void MainWindow::EnableScreenSaver(bool enable) { #if defined(HAVE_XRANDR) && HAVE_XRANDR - UICommon::EnableScreenSaver(winId(), enable); + if (GetWindowSystemType() == WindowSystemType::X11) + UICommon::EnableScreenSaver(winId(), enable); #else UICommon::EnableScreenSaver(enable); #endif diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index eaec778b5d..937e3beb7c 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -173,7 +173,7 @@ private: MenuBar* m_menu_bar; SearchBar* m_search_bar; GameList* m_game_list; - RenderWidget* m_render_widget; + RenderWidget* m_render_widget = nullptr; bool m_rendering_to_main; bool m_stop_requested = false; bool m_exit_requested = false; diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index 0e6857c137..7be22d4a8d 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -41,12 +41,12 @@ ControllerInterface g_controller_interface; // // Detect devices and inputs outputs / will make refresh function later // -void ControllerInterface::Initialize(void* const hwnd) +void ControllerInterface::Initialize(const WindowSystemInfo& wsi) { if (m_is_init) return; - m_hwnd = hwnd; + m_wsi = wsi; m_is_populating_devices = true; #ifdef CIFACE_USE_DINPUT @@ -59,7 +59,8 @@ void ControllerInterface::Initialize(void* const hwnd) // nothing needed #endif #ifdef CIFACE_USE_OSX - ciface::OSX::Init(hwnd); + if (m_wsi.type == WindowSystemType::MacOS) + ciface::OSX::Init(wsi.render_surface); // nothing needed for Quartz #endif #ifdef CIFACE_USE_SDL @@ -92,17 +93,22 @@ void ControllerInterface::RefreshDevices() m_is_populating_devices = true; #ifdef CIFACE_USE_DINPUT - ciface::DInput::PopulateDevices(reinterpret_cast(m_hwnd)); + if (m_wsi.type == WindowSystemType::Windows) + ciface::DInput::PopulateDevices(reinterpret_cast(m_wsi.render_surface)); #endif #ifdef CIFACE_USE_XINPUT ciface::XInput::PopulateDevices(); #endif #ifdef CIFACE_USE_XLIB - ciface::XInput2::PopulateDevices(m_hwnd); + if (m_wsi.type == WindowSystemType::X11) + ciface::XInput2::PopulateDevices(m_wsi.render_surface); #endif #ifdef CIFACE_USE_OSX - ciface::OSX::PopulateDevices(m_hwnd); - ciface::Quartz::PopulateDevices(m_hwnd); + if (m_wsi.type == WindowSystemType::MacOS) + { + ciface::OSX::PopulateDevices(m_wsi.render_surface); + ciface::Quartz::PopulateDevices(m_wsi.render_surface); + } #endif #ifdef CIFACE_USE_SDL ciface::SDL::PopulateDevices(); diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h index c576b20fb3..2e078e8934 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h @@ -10,6 +10,7 @@ #include #include +#include "Common/WindowSystemInfo.h" #include "InputCommon/ControllerInterface/Device.h" // enable disable sources @@ -39,8 +40,8 @@ class ControllerInterface : public ciface::Core::DeviceContainer { public: - ControllerInterface() : m_is_init(false), m_hwnd(nullptr) {} - void Initialize(void* const hwnd); + ControllerInterface() : m_is_init(false) {} + void Initialize(const WindowSystemInfo& wsi); void RefreshDevices(); void Shutdown(); void AddDevice(std::shared_ptr device); @@ -56,7 +57,7 @@ private: mutable std::mutex m_callbacks_mutex; bool m_is_init; std::atomic m_is_populating_devices{false}; - void* m_hwnd; + WindowSystemInfo m_wsi; }; extern ControllerInterface g_controller_interface; From 52828901efedb146cb572573b2381e73d2ada4d9 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 27 Oct 2018 20:06:35 +1000 Subject: [PATCH 2/4] Core: Switch controller interface to render widget on booting Previously, the Qt frontend would initialize the controller interface on starting, resulting in the cursor position being relative to the main window, instead of the render window. --- Source/Core/Core/Core.cpp | 5 +++++ Source/Core/DolphinQt/MainWindow.cpp | 5 +++++ .../ControllerInterface/ControllerInterface.cpp | 9 +++++++++ .../ControllerInterface/ControllerInterface.h | 1 + 4 files changed, 20 insertions(+) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index fff3e6bfff..b5a4b13ce0 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -456,6 +456,10 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi return; } + // The frontend will likely have initialized the controller interface, as it needs + // it to provide the configuration dialogs. In this case, instead of re-initializing + // entirely, we switch the window used for inputs to the render window. This way, the + // cursor position is relative to the render window, instead of the main window. bool init_controllers = false; if (!g_controller_interface.IsInit()) { @@ -467,6 +471,7 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi else { // Update references in case controllers were refreshed + g_controller_interface.ChangeWindow(wsi.render_surface); Pad::LoadConfig(); Keyboard::LoadConfig(); } diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index f02542da95..e2b9e15791 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -940,6 +940,11 @@ void MainWindow::HideRenderWidget(bool reinit) if (m_render_widget->isFullScreen()) SetFullScreenResolution(focus); }); + + // The controller interface will still be registered to the old render widget, if the core + // has booted. Therefore, we should re-bind it to the main window for now. When the core + // is next started, it will be swapped back to the new render widget. + g_controller_interface.ChangeWindow(GetWindowSystemInfo(windowHandle()).render_surface); } } diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index 7be22d4a8d..9f6e7c5179 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -80,6 +80,15 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi) RefreshDevices(); } +void ControllerInterface::ChangeWindow(void* hwnd) +{ + if (!m_is_init) + return; + + m_wsi.render_surface = hwnd; + RefreshDevices(); +} + void ControllerInterface::RefreshDevices() { if (!m_is_init) diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h index 2e078e8934..d5567222a4 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h @@ -42,6 +42,7 @@ class ControllerInterface : public ciface::Core::DeviceContainer public: ControllerInterface() : m_is_init(false) {} void Initialize(const WindowSystemInfo& wsi); + void ChangeWindow(void* hwnd); void RefreshDevices(); void Shutdown(); void AddDevice(std::shared_ptr device); From cb6ba59a4434591d91c920ac5735b098ad41112f Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 27 Oct 2018 21:18:54 +1000 Subject: [PATCH 3/4] Host: Don't call ChangeSurface when handle hasn't changed This was causing a deadlock when switching to fullscreen in render-to-main-window mode. --- Source/Core/DolphinQt/Host.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/DolphinQt/Host.cpp b/Source/Core/DolphinQt/Host.cpp index daaaee14b0..5e73896d7a 100644 --- a/Source/Core/DolphinQt/Host.cpp +++ b/Source/Core/DolphinQt/Host.cpp @@ -32,6 +32,10 @@ Host* Host::GetInstance() void Host::SetRenderHandle(void* handle) { + if (m_render_handle == handle) + return; + + m_render_handle = handle; if (g_renderer) g_renderer->ChangeSurface(handle); } From 6392be61ebf00188cd048b42c99fff60f0a56139 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 27 Oct 2018 21:22:55 +1000 Subject: [PATCH 4/4] Host: Also call ControllerInterface::ChangeWindow when window changes This should prevent us from trying to poll against destroyed native windows. --- Source/Core/DolphinQt/Host.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/DolphinQt/Host.cpp b/Source/Core/DolphinQt/Host.cpp index 5e73896d7a..c4d3711eda 100644 --- a/Source/Core/DolphinQt/Host.cpp +++ b/Source/Core/DolphinQt/Host.cpp @@ -19,6 +19,8 @@ #include "DolphinQt/QtUtils/QueueOnObject.h" #include "DolphinQt/Settings.h" +#include "InputCommon/ControllerInterface/ControllerInterface.h" + #include "VideoCommon/RenderBase.h" #include "VideoCommon/VideoConfig.h" @@ -37,7 +39,11 @@ void Host::SetRenderHandle(void* handle) m_render_handle = handle; if (g_renderer) + { g_renderer->ChangeSurface(handle); + if (g_controller_interface.IsInit()) + g_controller_interface.ChangeWindow(handle); + } } bool Host::GetRenderFocus()