diff --git a/Source/Core/Common/SysConf.cpp b/Source/Core/Common/SysConf.cpp
index d4c58a3def..ec0bad5b9b 100644
--- a/Source/Core/Common/SysConf.cpp
+++ b/Source/Core/Common/SysConf.cpp
@@ -314,7 +314,7 @@ void SysConf::GenerateSysConf()
// IPL.IDL
current_offset += create_item(items[23], Type_SmallArray, "IPL.IDL", 1, current_offset);
- items[23].data[0] = 0x01;
+ items[23].data[0] = 0x00;
// IPL.EULA
current_offset += create_item(items[24], Type_Bool, "IPL.EULA", 1, current_offset);
diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp
index f7651b5bce..6370bbf9d1 100644
--- a/Source/Core/Core/BootManager.cpp
+++ b/Source/Core/Core/BootManager.cpp
@@ -392,6 +392,15 @@ bool BootCore(const std::string& _rFilename)
SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", StartUp.bProgressive);
SConfig::GetInstance().m_SYSCONF->SetData("IPL.E60", StartUp.bPAL60);
+ if (StartUp.bWii)
+ {
+ // Disable WiiConnect24's standby mode. If it is enabled, it prevents us from receiving
+ // shutdown commands in the State Transition Manager (STM).
+ // TODO: remove this if and once Dolphin supports WC24 standby mode.
+ SConfig::GetInstance().m_SYSCONF->SetData("IPL.IDL", 0x00);
+ NOTICE_LOG(BOOT, "Disabling WC24 'standby' (shutdown to idle) to avoid hanging on shutdown");
+ }
+
// Run the game
// Init the core
if (!Core::Init())
diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index 5989d47399..ef5c3e9d1e 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -143,6 +143,7 @@ set(SRCS ActionReplay.cpp
IPC_HLE/WII_Socket.cpp
IPC_HLE/WII_IPC_HLE_Device_net.cpp
IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp
+ IPC_HLE/WII_IPC_HLE_Device_stm.cpp
IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp
IPC_HLE/WII_IPC_HLE_Device_usb.cpp
IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp
diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index e89a1d6a41..f0a54a74f3 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -183,6 +183,7 @@
+
@@ -386,8 +387,8 @@
-
+
@@ -480,4 +481,4 @@
-
\ No newline at end of file
+
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index bc12b068ac..082b302901 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -585,6 +585,9 @@
IPC HLE %28IOS/Starlet%29\SDIO - SD Card
+
+ IPC HLE %28IOS/Starlet%29
+
IPC HLE %28IOS/Starlet%29\USB
@@ -1247,4 +1250,4 @@
-
\ No newline at end of file
+
diff --git a/Source/Core/Core/HW/ProcessorInterface.cpp b/Source/Core/Core/HW/ProcessorInterface.cpp
index 04fec4cd07..a24f5529b6 100644
--- a/Source/Core/Core/HW/ProcessorInterface.cpp
+++ b/Source/Core/Core/HW/ProcessorInterface.cpp
@@ -37,6 +37,9 @@ static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate);
static CoreTiming::EventType* iosNotifyResetButton;
static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate);
+static CoreTiming::EventType* iosNotifyPowerButton;
+static void IOSNotifyPowerButtonCallback(u64 userdata, s64 cyclesLate);
+
// Let the PPC know that an external exception is set/cleared
void UpdateException();
@@ -75,6 +78,8 @@ void Init()
toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback);
iosNotifyResetButton =
CoreTiming::RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback);
+ iosNotifyPowerButton =
+ CoreTiming::RegisterEvent("IOSNotifyPowerButton", IOSNotifyPowerButtonCallback);
}
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
@@ -214,6 +219,17 @@ static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate)
}
}
+static void IOSNotifyPowerButtonCallback(u64 userdata, s64 cyclesLate)
+{
+ if (SConfig::GetInstance().bWii)
+ {
+ std::shared_ptr stm =
+ WII_IPC_HLE_Interface::GetDeviceByName("/dev/stm/eventhook");
+ if (stm)
+ std::static_pointer_cast(stm)->PowerButton();
+ }
+}
+
void ResetButton_Tap()
{
CoreTiming::ScheduleEvent(0, toggleResetButton, true, CoreTiming::FromThread::ANY);
@@ -222,4 +238,9 @@ void ResetButton_Tap()
CoreTiming::FromThread::ANY);
}
+void PowerButton_Tap()
+{
+ CoreTiming::ScheduleEvent(0, iosNotifyPowerButton, 0, CoreTiming::FromThread::ANY);
+}
+
} // namespace ProcessorInterface
diff --git a/Source/Core/Core/HW/ProcessorInterface.h b/Source/Core/Core/HW/ProcessorInterface.h
index 5b9310e9fb..3f42105358 100644
--- a/Source/Core/Core/HW/ProcessorInterface.h
+++ b/Source/Core/Core/HW/ProcessorInterface.h
@@ -76,5 +76,6 @@ void SetInterrupt(u32 _causemask, bool _bSet = true);
// Thread-safe func which sets and clears reset button state automagically
void ResetButton_Tap();
+void PowerButton_Tap();
} // namespace ProcessorInterface
diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.cpp
new file mode 100644
index 0000000000..0bd3f8f257
--- /dev/null
+++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.cpp
@@ -0,0 +1,169 @@
+// Copyright 2016 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "Core/IPC_HLE/WII_IPC_HLE_Device_stm.h"
+
+namespace Core
+{
+void QueueHostJob(std::function job, bool run_during_stop);
+void Stop();
+}
+
+static u32 s_event_hook_address = 0;
+
+IPCCommandResult CWII_IPC_HLE_Device_stm_immediate::Open(u32 command_address, u32 mode)
+{
+ INFO_LOG(WII_IPC_STM, "STM immediate: Open");
+ Memory::Write_U32(GetDeviceID(), command_address + 4);
+ m_Active = true;
+ return GetDefaultReply();
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_stm_immediate::Close(u32 command_address, bool force)
+{
+ INFO_LOG(WII_IPC_STM, "STM immediate: Close");
+ if (!force)
+ Memory::Write_U32(0, command_address + 4);
+ m_Active = false;
+ return GetDefaultReply();
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_stm_immediate::IOCtl(u32 command_address)
+{
+ u32 parameter = Memory::Read_U32(command_address + 0x0C);
+ u32 buffer_in = Memory::Read_U32(command_address + 0x10);
+ u32 buffer_in_size = Memory::Read_U32(command_address + 0x14);
+ u32 buffer_out = Memory::Read_U32(command_address + 0x18);
+ u32 buffer_out_size = Memory::Read_U32(command_address + 0x1C);
+
+ // Prepare the out buffer(s) with zeroes as a safety precaution
+ // to avoid returning bad values
+ Memory::Memset(buffer_out, 0, buffer_out_size);
+ u32 return_value = 0;
+
+ switch (parameter)
+ {
+ case IOCTL_STM_IDLE:
+ case IOCTL_STM_SHUTDOWN:
+ NOTICE_LOG(WII_IPC_STM, "IOCTL_STM_IDLE or IOCTL_STM_SHUTDOWN received, shutting down");
+ Core::QueueHostJob(&Core::Stop, false);
+ break;
+
+ case IOCTL_STM_RELEASE_EH:
+ if (s_event_hook_address == 0)
+ {
+ return_value = FS_ENOENT;
+ break;
+ }
+ Memory::Write_U32(0, Memory::Read_U32(s_event_hook_address + 0x18));
+ Memory::Write_U32(FS_SUCCESS, s_event_hook_address + 4);
+ Memory::Write_U32(IPC_REP_ASYNC, s_event_hook_address);
+ Memory::Write_U32(IPC_CMD_IOCTL, s_event_hook_address + 8);
+ WII_IPC_HLE_Interface::EnqueueReply(s_event_hook_address);
+ s_event_hook_address = 0;
+ break;
+
+ case IOCTL_STM_HOTRESET:
+ INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
+ INFO_LOG(WII_IPC_STM, " IOCTL_STM_HOTRESET");
+ break;
+
+ case IOCTL_STM_VIDIMMING: // (Input: 20 bytes, Output: 20 bytes)
+ INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
+ INFO_LOG(WII_IPC_STM, " IOCTL_STM_VIDIMMING");
+ // DumpCommands(buffer_in, buffer_in_size / 4, LogTypes::WII_IPC_STM);
+ // Memory::Write_U32(1, buffer_out);
+ // return_value = 1;
+ break;
+
+ case IOCTL_STM_LEDMODE: // (Input: 20 bytes, Output: 20 bytes)
+ INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
+ INFO_LOG(WII_IPC_STM, " IOCTL_STM_LEDMODE");
+ break;
+
+ default:
+ {
+ _dbg_assert_msg_(WII_IPC_STM, 0, "CWII_IPC_HLE_Device_stm_immediate: 0x%x", parameter);
+
+ INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
+ DEBUG_LOG(WII_IPC_STM, " parameter: 0x%x", parameter);
+ DEBUG_LOG(WII_IPC_STM, " InBuffer: 0x%08x", buffer_in);
+ DEBUG_LOG(WII_IPC_STM, " InBufferSize: 0x%08x", buffer_in_size);
+ DEBUG_LOG(WII_IPC_STM, " OutBuffer: 0x%08x", buffer_out);
+ DEBUG_LOG(WII_IPC_STM, " OutBufferSize: 0x%08x", buffer_out_size);
+ }
+ break;
+ }
+
+ // Write return value to the IPC call
+ Memory::Write_U32(return_value, command_address + 0x4);
+ return GetDefaultReply();
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_stm_eventhook::Open(u32 command_address, u32 mode)
+{
+ Memory::Write_U32(GetDeviceID(), command_address + 4);
+ m_Active = true;
+ return GetDefaultReply();
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_stm_eventhook::Close(u32 command_address, bool force)
+{
+ s_event_hook_address = 0;
+
+ INFO_LOG(WII_IPC_STM, "STM eventhook: Close");
+ if (!force)
+ Memory::Write_U32(0, command_address + 4);
+ m_Active = false;
+ return GetDefaultReply();
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_stm_eventhook::IOCtl(u32 command_address)
+{
+ u32 parameter = Memory::Read_U32(command_address + 0x0C);
+ if (parameter != IOCTL_STM_EVENTHOOK)
+ {
+ ERROR_LOG(WII_IPC_STM, "Bad IOCtl in CWII_IPC_HLE_Device_stm_eventhook");
+ Memory::Write_U32(FS_EINVAL, command_address + 4);
+ return GetDefaultReply();
+ }
+
+ // IOCTL_STM_EVENTHOOK waits until the reset button or power button
+ // is pressed.
+ s_event_hook_address = command_address;
+ return GetNoReply();
+}
+
+void CWII_IPC_HLE_Device_stm_eventhook::TriggerEvent(const u32 event) const
+{
+ if (!m_Active || s_event_hook_address == 0)
+ {
+ // If the device isn't open, ignore the button press.
+ return;
+ }
+
+ // The reset button returns STM_EVENT_RESET.
+ u32 buffer_out = Memory::Read_U32(s_event_hook_address + 0x18);
+ Memory::Write_U32(event, buffer_out);
+
+ // Fill in command buffer.
+ Memory::Write_U32(FS_SUCCESS, s_event_hook_address + 4);
+ Memory::Write_U32(IPC_REP_ASYNC, s_event_hook_address);
+ Memory::Write_U32(IPC_CMD_IOCTL, s_event_hook_address + 8);
+
+ // Generate a reply to the IPC command.
+ WII_IPC_HLE_Interface::EnqueueReply(s_event_hook_address);
+ s_event_hook_address = 0;
+}
+
+void CWII_IPC_HLE_Device_stm_eventhook::ResetButton() const
+{
+ // The reset button returns STM_EVENT_RESET.
+ TriggerEvent(STM_EVENT_RESET);
+}
+
+void CWII_IPC_HLE_Device_stm_eventhook::PowerButton() const
+{
+ TriggerEvent(STM_EVENT_POWER);
+}
diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h
index b8c78b2776..56adc6a929 100644
--- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h
+++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h
@@ -4,7 +4,6 @@
#pragma once
-#include
#include "Core/IPC_HLE/WII_IPC_HLE_Device.h"
enum
@@ -32,155 +31,37 @@ enum
};
// The /dev/stm/immediate
-class CWII_IPC_HLE_Device_stm_immediate : public IWII_IPC_HLE_Device
+class CWII_IPC_HLE_Device_stm_immediate final : public IWII_IPC_HLE_Device
{
public:
- CWII_IPC_HLE_Device_stm_immediate(u32 _DeviceID, const std::string& _rDeviceName)
- : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
+ CWII_IPC_HLE_Device_stm_immediate(u32 device_id, const std::string& device_name)
+ : IWII_IPC_HLE_Device(device_id, device_name)
{
}
- virtual ~CWII_IPC_HLE_Device_stm_immediate() {}
- IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override
- {
- INFO_LOG(WII_IPC_STM, "STM immediate: Open");
- Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
- m_Active = true;
- return GetDefaultReply();
- }
-
- IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override
- {
- INFO_LOG(WII_IPC_STM, "STM immediate: Close");
- if (!_bForce)
- Memory::Write_U32(0, _CommandAddress + 4);
- m_Active = false;
- return GetDefaultReply();
- }
-
- IPCCommandResult IOCtl(u32 _CommandAddress) override
- {
- u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C);
- u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
- u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
- u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
- u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
-
- // Prepare the out buffer(s) with zeroes as a safety precaution
- // to avoid returning bad values
- Memory::Memset(BufferOut, 0, BufferOutSize);
- u32 ReturnValue = 0;
-
- switch (Parameter)
- {
- case IOCTL_STM_RELEASE_EH:
- INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
- INFO_LOG(WII_IPC_STM, " IOCTL_STM_RELEASE_EH");
- break;
-
- case IOCTL_STM_HOTRESET:
- INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
- INFO_LOG(WII_IPC_STM, " IOCTL_STM_HOTRESET");
- break;
-
- case IOCTL_STM_VIDIMMING: // (Input: 20 bytes, Output: 20 bytes)
- INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
- INFO_LOG(WII_IPC_STM, " IOCTL_STM_VIDIMMING");
- // DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_STM);
- // Memory::Write_U32(1, BufferOut);
- // ReturnValue = 1;
- break;
-
- case IOCTL_STM_LEDMODE: // (Input: 20 bytes, Output: 20 bytes)
- INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
- INFO_LOG(WII_IPC_STM, " IOCTL_STM_LEDMODE");
- break;
-
- default:
- {
- _dbg_assert_msg_(WII_IPC_STM, 0, "CWII_IPC_HLE_Device_stm_immediate: 0x%x", Parameter);
-
- INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
- DEBUG_LOG(WII_IPC_STM, " Parameter: 0x%x", Parameter);
- DEBUG_LOG(WII_IPC_STM, " InBuffer: 0x%08x", BufferIn);
- DEBUG_LOG(WII_IPC_STM, " InBufferSize: 0x%08x", BufferInSize);
- DEBUG_LOG(WII_IPC_STM, " OutBuffer: 0x%08x", BufferOut);
- DEBUG_LOG(WII_IPC_STM, " OutBufferSize: 0x%08x", BufferOutSize);
- }
- break;
- }
-
- // Write return value to the IPC call
- Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
- return GetDefaultReply();
- }
+ ~CWII_IPC_HLE_Device_stm_immediate() override = default;
+ IPCCommandResult Open(u32 command_address, u32 mode) override;
+ IPCCommandResult Close(u32 command_address, bool force) override;
+ IPCCommandResult IOCtl(u32 command_address) override;
};
// The /dev/stm/eventhook
-class CWII_IPC_HLE_Device_stm_eventhook : public IWII_IPC_HLE_Device
+class CWII_IPC_HLE_Device_stm_eventhook final : public IWII_IPC_HLE_Device
{
public:
- CWII_IPC_HLE_Device_stm_eventhook(u32 _DeviceID, const std::string& _rDeviceName)
- : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName), m_EventHookAddress(0)
+ CWII_IPC_HLE_Device_stm_eventhook(u32 device_id, const std::string& device_name)
+ : IWII_IPC_HLE_Device(device_id, device_name)
{
}
- virtual ~CWII_IPC_HLE_Device_stm_eventhook() {}
- IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override
- {
- Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
- m_Active = true;
- return GetDefaultReply();
- }
+ ~CWII_IPC_HLE_Device_stm_eventhook() override = default;
+ IPCCommandResult Open(u32 command_address, u32 mode) override;
+ IPCCommandResult Close(u32 command_address, bool force) override;
+ IPCCommandResult IOCtl(u32 command_address) override;
- IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override
- {
- m_EventHookAddress = 0;
+ void ResetButton() const;
+ void PowerButton() const;
- INFO_LOG(WII_IPC_STM, "STM eventhook: Close");
- if (!_bForce)
- Memory::Write_U32(0, _CommandAddress + 4);
- m_Active = false;
- return GetDefaultReply();
- }
-
- IPCCommandResult IOCtl(u32 _CommandAddress) override
- {
- u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C);
- if (Parameter != IOCTL_STM_EVENTHOOK)
- {
- ERROR_LOG(WII_IPC_STM, "Bad IOCtl in CWII_IPC_HLE_Device_stm_eventhook");
- Memory::Write_U32(FS_EINVAL, _CommandAddress + 4);
- return GetDefaultReply();
- }
-
- // IOCTL_STM_EVENTHOOK waits until the reset button or power button
- // is pressed.
- m_EventHookAddress = _CommandAddress;
- return GetNoReply();
- }
-
- void ResetButton()
- {
- if (!m_Active || m_EventHookAddress == 0)
- {
- // If the device isn't open, ignore the button press.
- return;
- }
-
- // The reset button returns STM_EVENT_RESET.
- u32 BufferOut = Memory::Read_U32(m_EventHookAddress + 0x18);
- Memory::Write_U32(STM_EVENT_RESET, BufferOut);
-
- // Fill in command buffer.
- Memory::Write_U32(FS_SUCCESS, m_EventHookAddress + 4);
- Memory::Write_U32(IPC_REP_ASYNC, m_EventHookAddress);
- Memory::Write_U32(IPC_CMD_IOCTL, m_EventHookAddress + 8);
-
- // Generate a reply to the IPC command.
- WII_IPC_HLE_Interface::EnqueueReply(m_EventHookAddress);
- }
-
- // STATE_TO_SAVE
- u32 m_EventHookAddress;
+private:
+ void TriggerEvent(u32 event) const;
};
diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h
index 43a5a3745a..1e7c5eec0a 100644
--- a/Source/Core/DolphinWX/Frame.h
+++ b/Source/Core/DolphinWX/Frame.h
@@ -158,6 +158,7 @@ private:
bool m_bGameLoading = false;
bool m_bClosing = false;
bool m_confirmStop = false;
+ bool m_tried_graceful_shutdown = false;
int m_saveSlot = 1;
std::vector drives;
diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp
index 51675ae115..d253446161 100644
--- a/Source/Core/DolphinWX/FrameTools.cpp
+++ b/Source/Core/DolphinWX/FrameTools.cpp
@@ -1148,9 +1148,12 @@ void CFrame::DoStop()
Core::SetState(Core::CORE_PAUSE);
}
- wxMessageDialog m_StopDlg(this, _("Do you want to stop the current emulation?"),
- _("Please confirm..."),
- wxYES_NO | wxSTAY_ON_TOP | wxICON_EXCLAMATION, wxDefaultPosition);
+ wxMessageDialog m_StopDlg(
+ this, !m_tried_graceful_shutdown ? _("Do you want to stop the current emulation?") :
+ _("A shutdown is already in progress. Unsaved data "
+ "may be lost if you stop the current emulation "
+ "before it completes. Force stop?"),
+ _("Please confirm..."), wxYES_NO | wxSTAY_ON_TOP | wxICON_EXCLAMATION, wxDefaultPosition);
HotkeyManagerEmu::Enable(false);
int Ret = m_StopDlg.ShowModal();
@@ -1165,6 +1168,16 @@ void CFrame::DoStop()
}
}
+ if (SConfig::GetInstance().bWii && !m_tried_graceful_shutdown)
+ {
+ Core::DisplayMessage("Shutting down", 30000);
+ Core::SetState(Core::CORE_RUN);
+ ProcessorInterface::PowerButton_Tap();
+ m_confirmStop = false;
+ m_tried_graceful_shutdown = true;
+ return;
+ }
+
if (UseDebugger && g_pCodeWindow)
{
if (g_pCodeWindow->m_WatchWindow)
@@ -1200,6 +1213,7 @@ void CFrame::DoStop()
void CFrame::OnStopped()
{
m_confirmStop = false;
+ m_tried_graceful_shutdown = false;
#if defined(HAVE_X11) && HAVE_X11
if (SConfig::GetInstance().bDisableScreenSaver)
diff --git a/Source/Core/DolphinWX/MainNoGUI.cpp b/Source/Core/DolphinWX/MainNoGUI.cpp
index 1d06ff559a..c954539e79 100644
--- a/Source/Core/DolphinWX/MainNoGUI.cpp
+++ b/Source/Core/DolphinWX/MainNoGUI.cpp
@@ -34,6 +34,8 @@
static bool rendererHasFocus = true;
static bool rendererIsFullscreen = false;
static Common::Flag s_running{true};
+static Common::Flag s_shutdown_requested{false};
+static Common::Flag s_tried_graceful_shutdown{false};
static void signal_handler(int)
{
@@ -41,7 +43,12 @@ static void signal_handler(int)
if (write(STDERR_FILENO, message, sizeof(message)) < 0)
{
}
- s_running.Clear();
+ s_shutdown_requested.Set();
+}
+
+namespace ProcessorInterface
+{
+void PowerButton_Tap();
}
class Platform
@@ -222,6 +229,19 @@ class PlatformX11 : public Platform
// The actual loop
while (s_running.IsSet())
{
+ if (s_shutdown_requested.TestAndClear())
+ {
+ if (!s_tried_graceful_shutdown.IsSet() && SConfig::GetInstance().bWii)
+ {
+ ProcessorInterface::PowerButton_Tap();
+ s_tried_graceful_shutdown.Set();
+ }
+ else
+ {
+ s_running.Clear();
+ }
+ }
+
XEvent event;
KeySym key;
for (int num_events = XPending(dpy); num_events > 0; num_events--)
@@ -286,7 +306,7 @@ class PlatformX11 : public Platform
break;
case ClientMessage:
if ((unsigned long)event.xclient.data.l[0] == XInternAtom(dpy, "WM_DELETE_WINDOW", False))
- s_running.Clear();
+ s_shutdown_requested.Set();
break;
}
}
@@ -375,6 +395,7 @@ int main(int argc, char* argv[])
UICommon::SetUserDirectory(""); // Auto-detect user folder
UICommon::Init();
+ Core::SetOnStoppedCallback([]() { s_running.Clear(); });
platform->Init();
// Shut down cleanly on SIGINT and SIGTERM