Fix UI scale for X11.
Fix page up and page down keys not working. Fix mouse wheel not working
This commit is contained in:
parent
98ff358a3a
commit
fe452faadc
4 changed files with 85 additions and 55 deletions
|
|
@ -1,10 +1,65 @@
|
|||
|
||||
#include "sdl2_display_backend.h"
|
||||
#include "sdl2_display_window.h"
|
||||
#include <stdexcept>
|
||||
#include <SDL2/SDL_video.h>
|
||||
#ifndef WIN32
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace X11DPI
|
||||
{
|
||||
typedef struct _XDisplay Display;
|
||||
typedef Display *(*XOpenDisplayPtr)(const char*);
|
||||
typedef char *(*XGetDefaultPtr)(Display*, const char*, const char*);
|
||||
typedef int (*XCloseDisplayPtr)(Display*);
|
||||
}
|
||||
|
||||
SDL2DisplayBackend::SDL2DisplayBackend()
|
||||
{
|
||||
int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
|
||||
if (result != 0)
|
||||
throw std::runtime_error(std::string("Unable to initialize SDL:") + SDL_GetError());
|
||||
|
||||
SDL2DisplayWindow::PaintEventNumber = SDL_RegisterEvents(1);
|
||||
|
||||
// SDL2 doesn't have proper native hidpi support for Linux. Cheat a bit here by asking X11 ourselves.
|
||||
#if !defined(WIN32) && !defined(__APPLE__)
|
||||
const char* driver = SDL_GetCurrentVideoDriver();
|
||||
if (driver && strcmp(driver, "x11") == 0)
|
||||
{
|
||||
void* module = dlopen("libX11.so", RTLD_NOW | RTLD_LOCAL);
|
||||
if (module)
|
||||
{
|
||||
using namespace X11DPI;
|
||||
auto XOpenDisplay = (XOpenDisplayPtr)dlsym(module, "XOpenDisplay");
|
||||
auto XGetDefault = (XGetDefaultPtr)dlsym(module, "XGetDefault");
|
||||
auto XCloseDisplay = (XCloseDisplayPtr)dlsym(module, "XCloseDisplay");
|
||||
if (XOpenDisplay && XGetDefault && XCloseDisplay)
|
||||
{
|
||||
auto display = XOpenDisplay(nullptr);
|
||||
if (display)
|
||||
{
|
||||
char* value = XGetDefault(display, "Xft", "dpi");
|
||||
if (value)
|
||||
{
|
||||
int dpi = std::atoi(value);
|
||||
if (dpi != 0)
|
||||
{
|
||||
UIScale = dpi / 96.0;
|
||||
}
|
||||
}
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<DisplayWindow> SDL2DisplayBackend::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI)
|
||||
{
|
||||
return std::make_unique<SDL2DisplayWindow>(windowHost, popupWindow, static_cast<SDL2DisplayWindow*>(owner), renderAPI);
|
||||
return std::make_unique<SDL2DisplayWindow>(windowHost, popupWindow, static_cast<SDL2DisplayWindow*>(owner), renderAPI, UIScale);
|
||||
}
|
||||
|
||||
void SDL2DisplayBackend::ProcessEvents()
|
||||
|
|
@ -24,7 +79,12 @@ void SDL2DisplayBackend::ExitLoop()
|
|||
|
||||
Size SDL2DisplayBackend::GetScreenSize()
|
||||
{
|
||||
return SDL2DisplayWindow::GetScreenSize();
|
||||
SDL_Rect rect = {};
|
||||
int result = SDL_GetDisplayBounds(0, &rect);
|
||||
if (result != 0)
|
||||
throw std::runtime_error(std::string("Unable to get screen size:") + SDL_GetError());
|
||||
|
||||
return Size(rect.w / UIScale, rect.h / UIScale);
|
||||
}
|
||||
|
||||
void* SDL2DisplayBackend::StartTimer(int timeoutMilliseconds, std::function<void()> onTimer)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
class SDL2DisplayBackend : public DisplayBackend
|
||||
{
|
||||
public:
|
||||
SDL2DisplayBackend();
|
||||
|
||||
std::unique_ptr<DisplayWindow> Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI) override;
|
||||
void ProcessEvents() override;
|
||||
void RunLoop() override;
|
||||
|
|
@ -16,4 +18,7 @@ public:
|
|||
Size GetScreenSize() override;
|
||||
|
||||
bool IsSDL2() override { return true; }
|
||||
|
||||
private:
|
||||
double UIScale = 1.0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,28 +7,8 @@ Uint32 SDL2DisplayWindow::PaintEventNumber = 0xffffffff;
|
|||
bool SDL2DisplayWindow::ExitRunLoop;
|
||||
std::unordered_map<int, SDL2DisplayWindow*> SDL2DisplayWindow::WindowList;
|
||||
|
||||
class InitSDL
|
||||
SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner, RenderAPI renderAPI, double uiscale) : WindowHost(windowHost), UIScale(uiscale)
|
||||
{
|
||||
public:
|
||||
InitSDL()
|
||||
{
|
||||
int result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
|
||||
if (result != 0)
|
||||
throw std::runtime_error(std::string("Unable to initialize SDL:") + SDL_GetError());
|
||||
|
||||
SDL2DisplayWindow::PaintEventNumber = SDL_RegisterEvents(1);
|
||||
}
|
||||
};
|
||||
|
||||
static void CheckInitSDL()
|
||||
{
|
||||
static InitSDL initsdl;
|
||||
}
|
||||
|
||||
SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner, RenderAPI renderAPI) : WindowHost(windowHost)
|
||||
{
|
||||
CheckInitSDL();
|
||||
|
||||
unsigned int flags = SDL_WINDOW_HIDDEN /*| SDL_WINDOW_ALLOW_HIGHDPI*/;
|
||||
if (renderAPI == RenderAPI::Vulkan)
|
||||
flags |= SDL_WINDOW_VULKAN;
|
||||
|
|
@ -121,8 +101,8 @@ void SDL2DisplayWindow::SetClientFrame(const Rect& box)
|
|||
int w = (int)std::round(box.width * uiscale);
|
||||
int h = (int)std::round(box.height * uiscale);
|
||||
|
||||
SDL_SetWindowPosition(Handle.window, x, y);
|
||||
SDL_SetWindowSize(Handle.window, w, h);
|
||||
SDL_SetWindowPosition(Handle.window, x, y);
|
||||
}
|
||||
|
||||
void SDL2DisplayWindow::Show()
|
||||
|
|
@ -288,7 +268,8 @@ int SDL2DisplayWindow::GetPixelHeight() const
|
|||
double SDL2DisplayWindow::GetDpiScale() const
|
||||
{
|
||||
// SDL2 doesn't really support this properly. SDL_GetDisplayDPI returns the wrong information according to the docs.
|
||||
return 1.0;
|
||||
// We currently cheat by asking X11 directly. See the SDL2DisplayBackend constructor.
|
||||
return UIScale;
|
||||
}
|
||||
|
||||
void SDL2DisplayWindow::PresentBitmap(int width, int height, const uint32_t* pixels)
|
||||
|
|
@ -360,8 +341,6 @@ void SDL2DisplayWindow::SetClipboardText(const std::string& text)
|
|||
|
||||
void SDL2DisplayWindow::ProcessEvents()
|
||||
{
|
||||
CheckInitSDL();
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event) != 0)
|
||||
{
|
||||
|
|
@ -371,8 +350,6 @@ void SDL2DisplayWindow::ProcessEvents()
|
|||
|
||||
void SDL2DisplayWindow::RunLoop()
|
||||
{
|
||||
CheckInitSDL();
|
||||
|
||||
ExitRunLoop = false;
|
||||
while (!ExitRunLoop)
|
||||
{
|
||||
|
|
@ -385,28 +362,11 @@ void SDL2DisplayWindow::RunLoop()
|
|||
|
||||
void SDL2DisplayWindow::ExitLoop()
|
||||
{
|
||||
CheckInitSDL();
|
||||
|
||||
ExitRunLoop = true;
|
||||
}
|
||||
|
||||
Size SDL2DisplayWindow::GetScreenSize()
|
||||
{
|
||||
CheckInitSDL();
|
||||
|
||||
SDL_Rect rect = {};
|
||||
int result = SDL_GetDisplayBounds(0, &rect);
|
||||
if (result != 0)
|
||||
throw std::runtime_error(std::string("Unable to get screen size:") + SDL_GetError());
|
||||
|
||||
double uiscale = 1.0; // SDL2 doesn't really support this properly. SDL_GetDisplayDPI returns the wrong information according to the docs.
|
||||
return Size(rect.w / uiscale, rect.h / uiscale);
|
||||
}
|
||||
|
||||
void* SDL2DisplayWindow::StartTimer(int timeoutMilliseconds, std::function<void()> onTimer)
|
||||
{
|
||||
CheckInitSDL();
|
||||
|
||||
// To do: implement timers
|
||||
|
||||
return nullptr;
|
||||
|
|
@ -414,8 +374,6 @@ void* SDL2DisplayWindow::StartTimer(int timeoutMilliseconds, std::function<void(
|
|||
|
||||
void SDL2DisplayWindow::StopTimer(void* timerID)
|
||||
{
|
||||
CheckInitSDL();
|
||||
|
||||
// To do: implement timers
|
||||
}
|
||||
|
||||
|
|
@ -523,11 +481,15 @@ void SDL2DisplayWindow::OnMouseButtonDown(const SDL_MouseButtonEvent& event)
|
|||
|
||||
void SDL2DisplayWindow::OnMouseWheel(const SDL_MouseWheelEvent& event)
|
||||
{
|
||||
InputKey key = (event.y > 0) ? InputKey::MouseWheelUp : (event.y < 0) ? InputKey::MouseWheelDown : InputKey::None;
|
||||
if (key != InputKey::None)
|
||||
{
|
||||
WindowHost->OnWindowMouseWheel(GetMousePos(event), key);
|
||||
}
|
||||
int x = 0, y = 0;
|
||||
SDL_GetMouseState(&x, &y);
|
||||
double uiscale = GetDpiScale();
|
||||
Point mousepos(x / uiscale, y / uiscale);
|
||||
|
||||
if (event.y > 0)
|
||||
WindowHost->OnWindowMouseWheel(mousepos, InputKey::MouseWheelUp);
|
||||
else if (event.y < 0)
|
||||
WindowHost->OnWindowMouseWheel(mousepos, InputKey::MouseWheelDown);
|
||||
}
|
||||
|
||||
void SDL2DisplayWindow::OnMouseMotion(const SDL_MouseMotionEvent& event)
|
||||
|
|
@ -560,7 +522,9 @@ InputKey SDL2DisplayWindow::ScancodeToInputKey(SDL_Scancode keycode)
|
|||
case SDL_SCANCODE_ESCAPE: return InputKey::Escape;
|
||||
case SDL_SCANCODE_SPACE: return InputKey::Space;
|
||||
case SDL_SCANCODE_END: return InputKey::End;
|
||||
case SDL_SCANCODE_PAGEDOWN: return InputKey::PageDown;
|
||||
case SDL_SCANCODE_HOME: return InputKey::Home;
|
||||
case SDL_SCANCODE_PAGEUP: return InputKey::PageUp;
|
||||
case SDL_SCANCODE_LEFT: return InputKey::Left;
|
||||
case SDL_SCANCODE_UP: return InputKey::Up;
|
||||
case SDL_SCANCODE_RIGHT: return InputKey::Right;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
class SDL2DisplayWindow : public DisplayWindow
|
||||
{
|
||||
public:
|
||||
SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner, RenderAPI renderAPI);
|
||||
SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner, RenderAPI renderAPI, double uiscale);
|
||||
~SDL2DisplayWindow();
|
||||
|
||||
void SetWindowTitle(const std::string& text) override;
|
||||
|
|
@ -83,7 +83,6 @@ public:
|
|||
static void ProcessEvents();
|
||||
static void RunLoop();
|
||||
static void ExitLoop();
|
||||
static Size GetScreenSize();
|
||||
|
||||
static void* StartTimer(int timeoutMilliseconds, std::function<void()> onTimer);
|
||||
static void StopTimer(void* timerID);
|
||||
|
|
@ -95,6 +94,8 @@ public:
|
|||
int BackBufferWidth = 0;
|
||||
int BackBufferHeight = 0;
|
||||
|
||||
double UIScale = 1.0;
|
||||
|
||||
bool CursorLocked = false;
|
||||
bool isFullscreen = false;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue