summaryrefslogtreecommitdiff
path: root/Source/Core/DolphinNoGUI/PlatformX11.cpp
diff options
context:
space:
mode:
authorConnor McLaughlin <stenzek@gmail.com>2019-02-16 14:15:00 +1000
committerGitHub <noreply@github.com>2019-02-16 14:15:00 +1000
commitb5c3881fe703287c4f883ca42a3b931bb6594854 (patch)
tree29daf45582fa2860c76127271457675184341900 /Source/Core/DolphinNoGUI/PlatformX11.cpp
parentc41f32bcf8fe0c04d54d3541df210a604b2399d1 (diff)
parenteabde77892faf4408481f685f2fbf1b348232d5f (diff)
Merge pull request #7512 from stenzek/runtime-headless
DolphinNoGUI: Runtime selection of platform
Diffstat (limited to 'Source/Core/DolphinNoGUI/PlatformX11.cpp')
-rw-r--r--Source/Core/DolphinNoGUI/PlatformX11.cpp270
1 files changed, 270 insertions, 0 deletions
diff --git a/Source/Core/DolphinNoGUI/PlatformX11.cpp b/Source/Core/DolphinNoGUI/PlatformX11.cpp
new file mode 100644
index 0000000000..31a8a2e28d
--- /dev/null
+++ b/Source/Core/DolphinNoGUI/PlatformX11.cpp
@@ -0,0 +1,270 @@
+// Copyright 2018 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <unistd.h>
+
+#include "DolphinNoGUI/Platform.h"
+
+#include "Common/MsgHandler.h"
+#include "Core/ConfigManager.h"
+#include "Core/Core.h"
+#include "Core/State.h"
+
+#include <climits>
+#include <cstdio>
+
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include "UICommon/X11Utils.h"
+#include "VideoCommon/RenderBase.h"
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+#endif
+
+namespace
+{
+class PlatformX11 : public Platform
+{
+public:
+ ~PlatformX11() override;
+
+ bool Init() override;
+ void SetTitle(const std::string& string) override;
+ void MainLoop() override;
+
+ WindowSystemInfo GetWindowSystemInfo() const;
+
+private:
+ void CloseDisplay();
+ void UpdateWindowPosition();
+ void ProcessEvents();
+
+ Display* m_display = nullptr;
+ Window m_window = {};
+ Cursor m_blank_cursor = None;
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ X11Utils::XRRConfiguration* m_xrr_config = nullptr;
+#endif
+};
+
+PlatformX11::~PlatformX11()
+{
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ delete m_xrr_config;
+#endif
+
+ if (m_display)
+ {
+ if (SConfig::GetInstance().bHideCursor)
+ XFreeCursor(m_display, m_blank_cursor);
+
+ XCloseDisplay(m_display);
+ }
+}
+
+bool PlatformX11::Init()
+{
+ XInitThreads();
+ m_display = XOpenDisplay(nullptr);
+ if (!m_display)
+ {
+ PanicAlert("No X11 display found");
+ return false;
+ }
+
+ m_window = XCreateSimpleWindow(
+ m_display, DefaultRootWindow(m_display), SConfig::GetInstance().iRenderWindowXPos,
+ SConfig::GetInstance().iRenderWindowYPos, SConfig::GetInstance().iRenderWindowWidth,
+ SConfig::GetInstance().iRenderWindowHeight, 0, 0, BlackPixel(m_display, 0));
+ XSelectInput(m_display, m_window, StructureNotifyMask | KeyPressMask | FocusChangeMask);
+ Atom wmProtocols[1];
+ wmProtocols[0] = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
+ XSetWMProtocols(m_display, m_window, wmProtocols, 1);
+ pid_t pid = getpid();
+ XChangeProperty(m_display, m_window, XInternAtom(m_display, "_NET_WM_PID", False), XA_CARDINAL,
+ 32, PropModeReplace, reinterpret_cast<unsigned char*>(&pid), 1);
+ char host_name[HOST_NAME_MAX] = "";
+ if (!gethostname(host_name, sizeof(host_name)))
+ {
+ XTextProperty wmClientMachine = {reinterpret_cast<unsigned char*>(host_name), XA_STRING, 8,
+ strlen(host_name)};
+ XSetWMClientMachine(m_display, m_window, &wmClientMachine);
+ }
+ XMapRaised(m_display, m_window);
+ XFlush(m_display);
+ XSync(m_display, True);
+ ProcessEvents();
+
+ if (SConfig::GetInstance().bDisableScreenSaver)
+ X11Utils::InhibitScreensaver(m_window, true);
+
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ m_xrr_config = new X11Utils::XRRConfiguration(m_display, m_window);
+#endif
+
+ if (SConfig::GetInstance().bHideCursor)
+ {
+ // make a blank cursor
+ Pixmap Blank;
+ XColor DummyColor;
+ char ZeroData[1] = {0};
+ Blank = XCreateBitmapFromData(m_display, m_window, ZeroData, 1, 1);
+ m_blank_cursor = XCreatePixmapCursor(m_display, Blank, Blank, &DummyColor, &DummyColor, 0, 0);
+ XFreePixmap(m_display, Blank);
+ XDefineCursor(m_display, m_window, m_blank_cursor);
+ }
+
+ // Enter fullscreen if enabled.
+ if (SConfig::GetInstance().bFullscreen)
+ {
+ m_window_fullscreen = X11Utils::ToggleFullscreen(m_display, m_window);
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ m_xrr_config->ToggleDisplayMode(True);
+#endif
+ ProcessEvents();
+ }
+
+ UpdateWindowPosition();
+ return true;
+}
+
+void PlatformX11::SetTitle(const std::string& string)
+{
+ XStoreName(m_display, m_window, string.c_str());
+}
+
+void PlatformX11::MainLoop()
+{
+ while (IsRunning())
+ {
+ UpdateRunningFlag();
+ Core::HostDispatchJobs();
+ ProcessEvents();
+ UpdateWindowPosition();
+
+ // TODO: Is this sleep appropriate?
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+}
+
+WindowSystemInfo PlatformX11::GetWindowSystemInfo() const
+{
+ WindowSystemInfo wsi;
+ wsi.type = WindowSystemType::X11;
+ wsi.display_connection = static_cast<void*>(m_display);
+ wsi.render_surface = reinterpret_cast<void*>(m_window);
+ return wsi;
+}
+
+void PlatformX11::UpdateWindowPosition()
+{
+ if (m_window_fullscreen)
+ return;
+
+ Window winDummy;
+ unsigned int borderDummy, depthDummy;
+ XGetGeometry(m_display, m_window, &winDummy, &SConfig::GetInstance().iRenderWindowXPos,
+ &SConfig::GetInstance().iRenderWindowYPos,
+ reinterpret_cast<unsigned int*>(&SConfig::GetInstance().iRenderWindowWidth),
+ reinterpret_cast<unsigned int*>(&SConfig::GetInstance().iRenderWindowHeight),
+ &borderDummy, &depthDummy);
+}
+
+void PlatformX11::ProcessEvents()
+{
+ XEvent event;
+ KeySym key;
+ for (int num_events = XPending(m_display); num_events > 0; num_events--)
+ {
+ XNextEvent(m_display, &event);
+ switch (event.type)
+ {
+ case KeyPress:
+ key = XLookupKeysym((XKeyEvent*)&event, 0);
+ if (key == XK_Escape)
+ {
+ RequestShutdown();
+ }
+ else if (key == XK_F10)
+ {
+ if (Core::GetState() == Core::State::Running)
+ {
+ if (SConfig::GetInstance().bHideCursor)
+ XUndefineCursor(m_display, m_window);
+ Core::SetState(Core::State::Paused);
+ }
+ else
+ {
+ if (SConfig::GetInstance().bHideCursor)
+ XDefineCursor(m_display, m_window, m_blank_cursor);
+ Core::SetState(Core::State::Running);
+ }
+ }
+ else if ((key == XK_Return) && (event.xkey.state & Mod1Mask))
+ {
+ m_window_fullscreen = !m_window_fullscreen;
+ X11Utils::ToggleFullscreen(m_display, m_window);
+#if defined(HAVE_XRANDR) && HAVE_XRANDR
+ m_xrr_config->ToggleDisplayMode(m_window_fullscreen);
+#endif
+ UpdateWindowPosition();
+ }
+ 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:
+ {
+ m_window_focus = true;
+ if (SConfig::GetInstance().bHideCursor && Core::GetState() != Core::State::Paused)
+ XDefineCursor(m_display, m_window, m_blank_cursor);
+ }
+ break;
+ case FocusOut:
+ {
+ m_window_focus = false;
+ if (SConfig::GetInstance().bHideCursor)
+ XUndefineCursor(m_display, m_window);
+ }
+ break;
+ case ClientMessage:
+ {
+ if ((unsigned long)event.xclient.data.l[0] ==
+ XInternAtom(m_display, "WM_DELETE_WINDOW", False))
+ Stop();
+ }
+ break;
+ case ConfigureNotify:
+ {
+ if (g_renderer)
+ g_renderer->ResizeSurface();
+ }
+ break;
+ }
+ }
+}
+} // namespace
+
+std::unique_ptr<Platform> Platform::CreateX11Platform()
+{
+ return std::make_unique<PlatformX11>();
+}