Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDL3 : WIP #1182

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion app/app.pro
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
QT += core quick network quickcontrols2 svg
CONFIG += c++11

INCLUDEPATH += /usr/local/include/

unix:!macx {
TARGET = moonlight
} else {
Expand Down Expand Up @@ -66,7 +68,14 @@ macx {

unix:!macx {
CONFIG += link_pkgconfig
PKGCONFIG += openssl sdl2 SDL2_ttf opus
PKGCONFIG += openssl opus
packagesExist(sdl3) {
DEFINES += HAVE_SDL3
PKGCONFIG += sdl3 sdl3-ttf
}
else {
PKGCONFIG += sdl2 SDL2_ttf
}

!disable-ffmpeg {
packagesExist(libavcodec) {
Expand Down
34 changes: 34 additions & 0 deletions app/backend/systemproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,22 @@ void SystemProperties::querySdlVideoInfoInternal()
// We call the internal variant because we're already in a safe thread context.
refreshDisplaysInternal();

#if SDL_VERSION_ATLEAST(3, 0, 0)
SDL_Window* testWindow = SDL_CreateWindow("", 1280, 720,
#else
SDL_Window* testWindow = SDL_CreateWindow("", 0, 0, 1280, 720,
#endif
SDL_WINDOW_HIDDEN | StreamUtils::getPlatformWindowFlags());
if (!testWindow) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Failed to create test window with platform flags: %s",
SDL_GetError());

#if SDL_VERSION_ATLEAST(3, 0, 0)
testWindow = SDL_CreateWindow("", 1280, 720, SDL_WINDOW_HIDDEN);
#else
testWindow = SDL_CreateWindow("", 0, 0, 1280, 720, SDL_WINDOW_HIDDEN);
#endif
if (!testWindow) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to create window for hardware decode test: %s",
Expand Down Expand Up @@ -197,7 +205,13 @@ void SystemProperties::refreshDisplaysInternal()
monitorNativeResolutions.clear();

SDL_DisplayMode bestMode;
#if SDL_VERSION_ATLEAST(3, 0, 0)
int numDisplays = 0;
SDL_DisplayID *displays = SDL_GetDisplays(&numDisplays);
for (int displayIndex = 0; displayIndex < numDisplays; displayIndex++) {
#else
for (int displayIndex = 0; displayIndex < SDL_GetNumVideoDisplays(); displayIndex++) {
#endif
SDL_DisplayMode desktopMode;

if (StreamUtils::getNativeDesktopMode(displayIndex, &desktopMode)) {
Expand All @@ -212,6 +226,20 @@ void SystemProperties::refreshDisplaysInternal()

// Start at desktop mode and work our way up
bestMode = desktopMode;
#if SDL_VERSION_ATLEAST(3, 0, 0)
int numModes = 0;
const SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(displayIndex, &numModes);
for (int i = 0; i < numModes; i++) {
if (modes[i]->w == desktopMode.w && modes[i]->h == desktopMode.h) {
if (modes[i]->refresh_rate > bestMode.refresh_rate) {
bestMode = *modes[i];
}
}
}
if (modes) {
SDL_free(modes);
}
#else
for (int i = 0; i < SDL_GetNumDisplayModes(displayIndex); i++) {
SDL_DisplayMode mode;
if (SDL_GetDisplayMode(displayIndex, i, &mode) == 0) {
Expand All @@ -222,6 +250,7 @@ void SystemProperties::refreshDisplaysInternal()
}
}
}
#endif

// Try to normalize values around our our standard refresh rates.
// Some displays/OSes report values that are slightly off.
Expand All @@ -236,6 +265,11 @@ void SystemProperties::refreshDisplaysInternal()
}
}
}
#if SDL_VERSION_ATLEAST(3, 0, 0)
if (displays) {
SDL_free((void*)displays);
}
#endif

SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
155 changes: 155 additions & 0 deletions app/gui/sdlgamepadkeynavigation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,21 @@ void SdlGamepadKeyNavigation::enable()
// arrival events. Additionally, there's a race condition between
// our QML objects being destroyed and SDL being deinitialized that
// this solves too.
#if SDL_VERSION_ATLEAST(3, 0, 0)
if (SDL_InitSubSystem(SDL_INIT_GAMEPAD) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_InitSubSystem(SDL_INIT_GAMEPAD) failed: %s",
SDL_GetError());
return;
}
#else
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
SDL_GetError());
return;
}
#endif

MappingManager mappingManager;
mappingManager.applyMappings();
Expand All @@ -51,6 +60,22 @@ void SdlGamepadKeyNavigation::enable()
// overlapping lifetimes of SdlGamepadKeyNavigation instances, so we
// will attach ourselves.
SDL_PumpEvents();
#if SDL_VERSION_ATLEAST(3, 0, 0)
SDL_FlushEvent(SDL_EVENT_GAMEPAD_ADDED);

// Open all currently attached game controllers
int numGamepads = 0;
SDL_JoystickID *gamepads = SDL_GetGamepads(&numGamepads);
for (int i = 0; i < numGamepads; i++) {
SDL_Gamepad* gp = SDL_OpenGamepad(gamepads[i]);
if (gp != nullptr) {
m_Gamepads.append(gp);
}
}
if (gamepads) {
SDL_free((void*)gamepads);
}
#else
SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);

// Open all currently attached game controllers
Expand All @@ -62,6 +87,7 @@ void SdlGamepadKeyNavigation::enable()
}
}
}
#endif

// Flush events on the first poll
m_FirstPoll = true;
Expand All @@ -80,12 +106,21 @@ void SdlGamepadKeyNavigation::disable()

m_PollingTimer->stop();

#if SDL_VERSION_ATLEAST(3, 0, 0)
while (!m_Gamepads.isEmpty()) {
SDL_CloseGamepad(m_Gamepads[0]);
m_Gamepads.removeAt(0);
}

SDL_QuitSubSystem(SDL_INIT_GAMEPAD);
#else
while (!m_Gamepads.isEmpty()) {
SDL_GameControllerClose(m_Gamepads[0]);
m_Gamepads.removeAt(0);
}

SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
#endif

m_Enabled = false;
}
Expand All @@ -99,14 +134,120 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
// stale input data from the stream session (like the quit combo).
if (m_FirstPoll) {
SDL_PumpEvents();
#if SDL_VERSION_ATLEAST(3, 0, 0)
SDL_FlushEvent(SDL_EVENT_GAMEPAD_BUTTON_DOWN);
SDL_FlushEvent(SDL_EVENT_GAMEPAD_BUTTON_UP);
#else
SDL_FlushEvent(SDL_CONTROLLERBUTTONDOWN);
SDL_FlushEvent(SDL_CONTROLLERBUTTONUP);
#endif

m_FirstPoll = false;
}

while (SDL_PollEvent(&event)) {
switch (event.type) {
#if SDL_VERSION_ATLEAST(3, 0, 0)
case SDL_EVENT_QUIT:
// SDL may send us a quit event since we initialize
// the video subsystem on startup. If we get one,
// forward it on for Qt to take care of.
QCoreApplication::instance()->quit();
break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
{
QEvent::Type type =
event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN ?
QEvent::Type::KeyPress : QEvent::Type::KeyRelease;

// Swap face buttons if needed
if (prefs.swapFaceButtons) {
switch (event.button.button) {
case SDL_GAMEPAD_BUTTON_SOUTH:
event.button.button = SDL_GAMEPAD_BUTTON_EAST;
break;
case SDL_GAMEPAD_BUTTON_EAST:
event.button.button = SDL_GAMEPAD_BUTTON_SOUTH;
break;
case SDL_GAMEPAD_BUTTON_WEST:
event.button.button = SDL_GAMEPAD_BUTTON_NORTH;
break;
case SDL_GAMEPAD_BUTTON_NORTH:
event.button.button = SDL_GAMEPAD_BUTTON_WEST;
break;
}
}

switch (event.button.button) {
case SDL_GAMEPAD_BUTTON_DPAD_UP:
if (m_UiNavMode) {
// Back-tab
sendKey(type, Qt::Key_Tab, Qt::ShiftModifier);
}
else {
sendKey(type, Qt::Key_Up);
}
break;
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
if (m_UiNavMode) {
sendKey(type, Qt::Key_Tab);
}
else {
sendKey(type, Qt::Key_Down);
}
break;
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
sendKey(type, Qt::Key_Left);
break;
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
sendKey(type, Qt::Key_Right);
break;
case SDL_GAMEPAD_BUTTON_SOUTH:
if (m_UiNavMode) {
sendKey(type, Qt::Key_Space);
}
else {
sendKey(type, Qt::Key_Return);
}
break;
case SDL_GAMEPAD_BUTTON_EAST:
sendKey(type, Qt::Key_Escape);
break;
case SDL_GAMEPAD_BUTTON_WEST:
sendKey(type, Qt::Key_Menu);
break;
case SDL_GAMEPAD_BUTTON_NORTH:
case SDL_GAMEPAD_BUTTON_START:
// HACK: We use this keycode to inform main.qml
// to show the settings when Key_Menu is handled
// by the control in focus.
sendKey(type, Qt::Key_Hangup);
break;
default:
break;
}
break;
}
case SDL_EVENT_GAMEPAD_ADDED:
SDL_Gamepad* gp = SDL_OpenGamepad(event.jdevice.which);
if (gp != nullptr) {
// SDL_EVENT_GAMEPAD_ADDED can be reported multiple times for the same
// gamepad in rare cases, because SDL doesn't fixup the device index in
// the SDL_EVENT_GAMEPAD_ADDED event if an unopened gamepad disappears
// before we've processed the add event.
if (!m_Gamepads.contains(gp)) {
m_Gamepads.append(gp);
}
else {
// We already have this game controller open
SDL_CloseGamepad(gp);
}
}
break;
}
}
#else
case SDL_QUIT:
// SDL may send us a quit event since we initialize
// the video subsystem on startup. If we get one,
Expand Down Expand Up @@ -206,11 +347,18 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
break;
}
}
#endif

// Handle analog sticks by polling
#if SDL_VERSION_ATLEAST(3, 0, 0)
for (auto gp : m_Gamepads) {
short leftX = SDL_GetGamepadAxis(gp, SDL_GAMEPAD_AXIS_LEFTX);
short leftY = SDL_GetGamepadAxis(gp, SDL_GAMEPAD_AXIS_LEFTY);
#else
for (auto gc : m_Gamepads) {
short leftX = SDL_GameControllerGetAxis(gc, SDL_CONTROLLER_AXIS_LEFTX);
short leftY = SDL_GameControllerGetAxis(gc, SDL_CONTROLLER_AXIS_LEFTY);
#endif
if (SDL_GetTicks() - m_LastAxisNavigationEventTime < AXIS_NAVIGATION_REPEAT_DELAY) {
// Do nothing
}
Expand Down Expand Up @@ -272,11 +420,18 @@ int SdlGamepadKeyNavigation::getConnectedGamepads()
Q_ASSERT(m_Enabled);

int count = 0;
#if SDL_VERSION_ATLEAST(3, 0, 0)
SDL_JoystickID *gamepads = SDL_GetGamepads(&count);
if (gamepads) {
SDL_free((void*)gamepads);
}
#else
for (int i = 0; i < SDL_NumJoysticks(); i++) {
if (SDL_IsGameController(i)) {
count++;
}
}
#endif

return count;
}
8 changes: 8 additions & 0 deletions app/gui/sdlgamepadkeynavigation.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
#include <QTimer>
#include <QEvent>

#if HAVE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL.h>
#endif

class SdlGamepadKeyNavigation : public QObject
{
Expand All @@ -30,7 +34,11 @@ private slots:

private:
QTimer* m_PollingTimer;
#if SDL_VERSION_ATLEAST(3, 0, 0)
QList<SDL_Gamepad*> m_Gamepads;
#else
QList<SDL_GameController*> m_Gamepads;
#endif
bool m_Enabled;
bool m_UiNavMode;
bool m_FirstPoll;
Expand Down
5 changes: 5 additions & 0 deletions app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@
// doing the same thing. This needs to be before any headers
// that might include SDL.h themselves.
#define SDL_MAIN_HANDLED
#if HAVE_SDL3
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#else
#include <SDL.h>
#endif

#ifdef HAVE_FFMPEG
#include "streaming/video/ffmpeg.h"
Expand Down
4 changes: 4 additions & 0 deletions app/masterhook.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
// redirection that happens when _FILE_OFFSET_BITS=64!
// See masterhook_internal.c for details.

#if HAVE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL.h>
#endif
#include <dlfcn.h>
#include <unistd.h>
#include <errno.h>
Expand Down
4 changes: 4 additions & 0 deletions app/masterhook_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

#define _GNU_SOURCE

#if HAVE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL.h>
#endif
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
Expand Down
Loading