summaryrefslogtreecommitdiff
path: root/Source/Core/DolphinNoGUI/MainNoGUI.cpp
diff options
context:
space:
mode:
authorVlad Firoiu <vladfi2@gmail.com>2016-05-05 19:55:29 -0400
committerVlad Firoiu <vladfi2@gmail.com>2017-03-08 01:24:18 -0800
commitbc9db6de566ba608785ce10bf40b80885ef7e8e3 (patch)
tree169c31b9b3ccd9d20df28956ebd576541616e986 /Source/Core/DolphinNoGUI/MainNoGUI.cpp
parent6a89cf020136a335a0395f95e2de2056e3d016ad (diff)
Moved NoGUI out of DolphinWx.
Diffstat (limited to 'Source/Core/DolphinNoGUI/MainNoGUI.cpp')
-rw-r--r--Source/Core/DolphinNoGUI/MainNoGUI.cpp455
1 files changed, 455 insertions, 0 deletions
diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp
new file mode 100644
index 0000000000..d9293a0faa
--- /dev/null
+++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp
@@ -0,0 +1,455 @@
+// Copyright 2008 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <OptionParser.h>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+#include <signal.h>
+#include <string>
+#include <thread>
+#include <unistd.h>
+
+#include "Common/CommonTypes.h"
+#include "Common/Event.h"
+#include "Common/Flag.h"
+#include "Common/Logging/LogManager.h"
+#include "Common/MsgHandler.h"
+
+#include "Core/Analytics.h"
+#include "Core/BootManager.h"
+#include "Core/ConfigManager.h"
+#include "Core/Core.h"
+#include "Core/HW/Wiimote.h"
+#include "Core/Host.h"
+#include "Core/IOS/IPC.h"
+#include "Core/IOS/STM/STM.h"
+#include "Core/IOS/USB/Bluetooth/BTEmu.h"
+#include "Core/IOS/USB/Bluetooth/WiimoteDevice.h"
+#include "Core/State.h"
+
+#include "UICommon/CommandLineParse.h"
+#include "UICommon/UICommon.h"
+
+#include "VideoCommon/RenderBase.h"
+#include "VideoCommon/VideoBackendBase.h"
+
+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)
+{
+ const char message[] = "A signal was received. A second signal will force Dolphin to stop.\n";
+ if (write(STDERR_FILENO, message, sizeof(message)) < 0)
+ {
+ }
+ s_shutdown_requested.Set();
+}
+
+namespace ProcessorInterface
+{
+void PowerButton_Tap();
+}
+
+class Platform
+{
+public:
+ virtual void Init() {}
+ virtual void SetTitle(const std::string& title) {}
+ virtual void MainLoop()
+ {
+ while (s_running.IsSet())
+ {
+ Core::HostDispatchJobs();
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+ }
+ virtual void Shutdown() {}
+ virtual ~Platform() {}
+};
+
+static Platform* platform;
+
+void Host_NotifyMapLoaded()
+{
+}
+void Host_RefreshDSPDebuggerWindow()
+{
+}
+
+static Common::Event updateMainFrameEvent;
+void Host_Message(int Id)
+{
+ if (Id == WM_USER_STOP)
+ {
+ s_running.Clear();
+ updateMainFrameEvent.Set();
+ }
+}
+
+static void* s_window_handle = nullptr;
+void* Host_GetRenderHandle()
+{
+ return s_window_handle;
+}
+
+void Host_UpdateTitle(const std::string& title)
+{
+ platform->SetTitle(title);
+}
+
+void Host_UpdateDisasmDialog()
+{
+}
+
+void Host_UpdateMainFrame()
+{
+ updateMainFrameEvent.Set();
+}
+
+void Host_RequestRenderWindowSize(int width, int height)
+{
+}
+
+void Host_SetStartupDebuggingParameters()
+{
+ SConfig& StartUp = SConfig::GetInstance();
+ StartUp.bEnableDebugging = false;
+ StartUp.bBootToPause = false;
+}
+
+bool Host_UIHasFocus()
+{
+ return false;
+}
+
+bool Host_RendererHasFocus()
+{
+ return rendererHasFocus;
+}
+
+bool Host_RendererIsFullscreen()
+{
+ return rendererIsFullscreen;
+}
+
+void Host_ConnectWiimote(int wm_idx, bool connect)
+{
+ if (Core::IsRunning() && SConfig::GetInstance().bWii &&
+ !SConfig::GetInstance().m_bt_passthrough_enabled)
+ {
+ Core::QueueHostJob([=] {
+ bool was_unpaused = Core::PauseAndLock(true);
+ const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
+ IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305"));
+ if (bt)
+ bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect);
+ Host_UpdateMainFrame();
+ Core::PauseAndLock(false, was_unpaused);
+ });
+ }
+}
+
+void Host_SetWiiMoteConnectionState(int _State)
+{
+}
+
+void Host_ShowVideoConfig(void*, const std::string&)
+{
+}
+
+void Host_YieldToUI()
+{
+}
+
+#if HAVE_X11
+#include <X11/keysym.h>
+#include "UICommon/X11Utils.h"
+
+class PlatformX11 : public Platform
+{
+ Display* dpy;
+ Window win;
+ Cursor blankCursor = None;
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ X11Utils::XRRConfiguration* XRRConfig;
+#endif
+
+ void Init() override
+ {
+ XInitThreads();
+ dpy = XOpenDisplay(nullptr);
+ if (!dpy)
+ {
+ PanicAlert("No X11 display found");
+ exit(1);
+ }
+
+ win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), SConfig::GetInstance().iRenderWindowXPos,
+ SConfig::GetInstance().iRenderWindowYPos,
+ SConfig::GetInstance().iRenderWindowWidth,
+ SConfig::GetInstance().iRenderWindowHeight, 0, 0, BlackPixel(dpy, 0));
+ XSelectInput(dpy, win, StructureNotifyMask | KeyPressMask | FocusChangeMask);
+ Atom wmProtocols[1];
+ wmProtocols[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
+ XSetWMProtocols(dpy, win, wmProtocols, 1);
+ XMapRaised(dpy, win);
+ XFlush(dpy);
+ s_window_handle = (void*)win;
+
+ if (SConfig::GetInstance().bDisableScreenSaver)
+ X11Utils::InhibitScreensaver(dpy, win, true);
+
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ XRRConfig = new X11Utils::XRRConfiguration(dpy, win);
+#endif
+
+ if (SConfig::GetInstance().bHideCursor)
+ {
+ // make a blank cursor
+ Pixmap Blank;
+ XColor DummyColor;
+ char ZeroData[1] = {0};
+ Blank = XCreateBitmapFromData(dpy, win, ZeroData, 1, 1);
+ blankCursor = XCreatePixmapCursor(dpy, Blank, Blank, &DummyColor, &DummyColor, 0, 0);
+ XFreePixmap(dpy, Blank);
+ XDefineCursor(dpy, win, blankCursor);
+ }
+ }
+
+ void SetTitle(const std::string& string) override { XStoreName(dpy, win, string.c_str()); }
+ void MainLoop() override
+ {
+ bool fullscreen = SConfig::GetInstance().bFullscreen;
+ int last_window_width = SConfig::GetInstance().iRenderWindowWidth;
+ int last_window_height = SConfig::GetInstance().iRenderWindowHeight;
+
+ if (fullscreen)
+ {
+ rendererIsFullscreen = X11Utils::ToggleFullscreen(dpy, win);
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ XRRConfig->ToggleDisplayMode(True);
+#endif
+ }
+
+ // The actual loop
+ while (s_running.IsSet())
+ {
+ if (s_shutdown_requested.TestAndClear())
+ {
+ const auto stm = IOS::HLE::GetDeviceByName("/dev/stm/eventhook");
+ if (!s_tried_graceful_shutdown.IsSet() && stm &&
+ std::static_pointer_cast<IOS::HLE::Device::STMEventHook>(stm)->HasHookInstalled())
+ {
+ 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--)
+ {
+ XNextEvent(dpy, &event);
+ switch (event.type)
+ {
+ case KeyPress:
+ key = XLookupKeysym((XKeyEvent*)&event, 0);
+ if (key == XK_Escape)
+ {
+ if (Core::GetState() == Core::State::Running)
+ {
+ if (SConfig::GetInstance().bHideCursor)
+ XUndefineCursor(dpy, win);
+ Core::SetState(Core::State::Paused);
+ }
+ else
+ {
+ if (SConfig::GetInstance().bHideCursor)
+ XDefineCursor(dpy, win, blankCursor);
+ Core::SetState(Core::State::Running);
+ }
+ }
+ else if ((key == XK_Return) && (event.xkey.state & Mod1Mask))
+ {
+ fullscreen = !fullscreen;
+ X11Utils::ToggleFullscreen(dpy, win);
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ XRRConfig->ToggleDisplayMode(fullscreen);
+#endif
+ }
+ else if (key >= XK_F1 && key <= XK_F8)
+ {
+ int slot_number = key - XK_F1 + 1;
+ if (event.xkey.state & ShiftMask)
+ State::Save(slot_number);
+ else
+ State::Load(slot_number);
+ }
+ else if (key == XK_F9)
+ Core::SaveScreenShot();
+ else if (key == XK_F11)
+ State::LoadLastSaved();
+ else if (key == XK_F12)
+ {
+ if (event.xkey.state & ShiftMask)
+ State::UndoLoadState();
+ else
+ State::UndoSaveState();
+ }
+ break;
+ case FocusIn:
+ rendererHasFocus = true;
+ if (SConfig::GetInstance().bHideCursor && Core::GetState() != Core::State::Paused)
+ XDefineCursor(dpy, win, blankCursor);
+ break;
+ case FocusOut:
+ rendererHasFocus = false;
+ if (SConfig::GetInstance().bHideCursor)
+ XUndefineCursor(dpy, win);
+ break;
+ case ClientMessage:
+ if ((unsigned long)event.xclient.data.l[0] == XInternAtom(dpy, "WM_DELETE_WINDOW", False))
+ s_shutdown_requested.Set();
+ break;
+ case ConfigureNotify:
+ {
+ if (last_window_width != event.xconfigure.width ||
+ last_window_height != event.xconfigure.height)
+ {
+ last_window_width = event.xconfigure.width;
+ last_window_height = event.xconfigure.height;
+
+ // We call Renderer::ChangeSurface here to indicate the size has changed,
+ // but pass the same window handle. This is needed for the Vulkan backend,
+ // otherwise it cannot tell that the window has been resized on some drivers.
+ if (g_renderer)
+ g_renderer->ChangeSurface(s_window_handle);
+ }
+ }
+ break;
+ }
+ }
+ if (!fullscreen)
+ {
+ Window winDummy;
+ unsigned int borderDummy, depthDummy;
+ XGetGeometry(dpy, win, &winDummy, &SConfig::GetInstance().iRenderWindowXPos,
+ &SConfig::GetInstance().iRenderWindowYPos,
+ (unsigned int*)&SConfig::GetInstance().iRenderWindowWidth,
+ (unsigned int*)&SConfig::GetInstance().iRenderWindowHeight, &borderDummy,
+ &depthDummy);
+ rendererIsFullscreen = false;
+ }
+ Core::HostDispatchJobs();
+ usleep(100000);
+ }
+ }
+
+ void Shutdown() override
+ {
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ delete XRRConfig;
+#endif
+
+ if (SConfig::GetInstance().bHideCursor)
+ XFreeCursor(dpy, blankCursor);
+
+ XCloseDisplay(dpy);
+ }
+};
+#endif
+
+static Platform* GetPlatform()
+{
+#if defined(USE_EGL) && defined(USE_HEADLESS)
+ return new Platform();
+#elif HAVE_X11
+ return new PlatformX11();
+#endif
+ return nullptr;
+}
+
+int main(int argc, char* argv[])
+{
+ auto parser = CommandLineParse::CreateParser(CommandLineParse::ParserOptions::OmitGUIOptions);
+ optparse::Values& options = CommandLineParse::ParseArguments(parser.get(), argc, argv);
+ std::vector<std::string> args = parser->args();
+
+ std::string boot_filename;
+ if (options.is_set("exec"))
+ {
+ boot_filename = static_cast<const char*>(options.get("exec"));
+ }
+ else if (args.size())
+ {
+ boot_filename = args.front();
+ args.erase(args.begin());
+ }
+ else
+ {
+ parser->print_help();
+ return 0;
+ }
+
+ std::string user_directory;
+ if (options.is_set("user"))
+ {
+ user_directory = static_cast<const char*>(options.get("user"));
+ }
+
+ platform = GetPlatform();
+ if (!platform)
+ {
+ fprintf(stderr, "No platform found\n");
+ return 1;
+ }
+
+ UICommon::SetUserDirectory(user_directory);
+ UICommon::Init();
+
+ Core::SetOnStoppedCallback([]() { s_running.Clear(); });
+ platform->Init();
+
+ // Shut down cleanly on SIGINT and SIGTERM
+ struct sigaction sa;
+ sa.sa_handler = signal_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &sa, nullptr);
+ sigaction(SIGTERM, &sa, nullptr);
+
+ DolphinAnalytics::Instance()->ReportDolphinStart("nogui");
+
+ if (!BootManager::BootCore(boot_filename))
+ {
+ fprintf(stderr, "Could not boot %s\n", boot_filename.c_str());
+ return 1;
+ }
+
+ while (!Core::IsRunning() && s_running.IsSet())
+ {
+ Core::HostDispatchJobs();
+ updateMainFrameEvent.Wait();
+ }
+
+ if (s_running.IsSet())
+ platform->MainLoop();
+ Core::Stop();
+
+ Core::Shutdown();
+ platform->Shutdown();
+ UICommon::Shutdown();
+
+ delete platform;
+
+ return 0;
+}