Skip to content
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
12 changes: 9 additions & 3 deletions .github/workflows/create-test-plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class JobSpec:
"steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)", priority=False, os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt3", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest" ),
"steamrt4": JobSpec(name="Steam Linux Runtime 4.0 (x86_64)", priority=True, os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt4", container="registry.gitlab.steamos.cloud/steamrt/steamrt4/sdk:latest", more_hard_deps = True, ),
"steamrt4-arm64": JobSpec(name="Steam Linux Runtime 4.0 (arm64)", priority=False, os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt4-arm64", container="registry.gitlab.steamos.cloud/steamrt/steamrt4/sdk/arm64:latest", more_hard_deps = True, ),
"ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", priority=False, os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ),
"ubuntu-intel-icx": JobSpec(name="Ubuntu 24.04 (Intel oneAPI)", priority=False, os=JobOs.Ubuntu24_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ),
"ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", priority=False, os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ),
"macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", priority=False, os=JobOs.Macos14, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ),
"macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", priority=True, os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ),
Expand Down Expand Up @@ -378,6 +378,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool, ctest_args
job.clang_tidy = False
case _:
raise ValueError(f"Invalid intel={spec.intel}")
job.apt_packages.append("intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic")
job.source_cmd = f"source /opt/intel/oneapi/setvars.sh;"
job.intel = True
job.shell = "bash"
Expand Down Expand Up @@ -494,13 +495,17 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool, ctest_args
"libavutil-dev",
"libswresample-dev",
"libswscale-dev",
# testqt6
"qt6-base-dev",
))
match = re.match(r"ubuntu-(?P<year>[0-9]+)\.(?P<month>[0-9]+|latest).*", spec.os.value)
ubuntu_ge_22 = True
ubuntu_ge_24 = True
if match and match["month"] != "latest":
ubuntu_year, ubuntu_month = [int(match["year"]), int(match["month"])]
ubuntu_ge_22 = ubuntu_year >= 22
ubuntu_ge_24 = ubuntu_year >= 24
job.apt_packages.extend(("libpipewire-0.3-dev", "libdecor-0-dev"))
if not ubuntu_ge_24:
job.clang_tidy = False
job.apt_packages.extend((
"libunwind-dev", # For SDL_test memory tracking
))
Expand Down Expand Up @@ -788,6 +793,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool, ctest_args
if spec.msys2_platform not in (Msys2Platform.Mingw32, ):
job.msys2_packages.append(f"{msys2_env}-perl")
job.msys2_packages.append(f"{msys2_env}-clang-tools-extra")
job.msys2_packages.append(f"{msys2_env}-qt6")
if job.ccache:
job.msys2_packages.append(f"{msys2_env}-ccache")
job.microsoft_gameinput = True
Expand Down
20 changes: 9 additions & 11 deletions .github/workflows/generic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,9 @@ jobs:
# Download the key to system keyring
wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \
| gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null

# Add signed entry to apt sources and configure the APT client to use Intel repository:
echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list

# Update package list
sudo apt-get update -y

# Install oneAPI
sudo apt-get install -y intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic
- name: 'Install apk packages'
if: ${{ matrix.platform.apk-packages != '' }}
run: |
Expand All @@ -133,14 +127,18 @@ jobs:
- name: 'Install apt packages'
if: ${{ matrix.platform.apt-packages != '' }}
run: |
${{ matrix.platform.sudo }} apt-get update
${{ matrix.platform.sudo }} apt-get update -y
${{ matrix.platform.sudo }} apt-get install -y ${{ matrix.platform.apt-packages }}
- name: 'Install brew packages'
if: ${{ matrix.platform.brew-packages != '' }}
run: |
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
brew update
brew install ${{ matrix.platform.brew-packages }}
# Unset these GitHub environment variable to keep brew from emitting a few noisy annotions
unset GITHUB_ACTIONS
unset GITHUB_OUTPUT
unset GITHUB_PATH

brew update --auto-update
brew install --quiet ${{ matrix.platform.brew-packages }}
- name: 'Setup Python'
uses: 'actions/setup-python@main'
if: ${{ matrix.platform.setup-python }}
Expand Down
14 changes: 8 additions & 6 deletions build-scripts/check_stdlib_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,17 @@ def find_symbols_in_dir(path: pathlib.Path) -> int:

def main():
parser = argparse.ArgumentParser(fromfile_prefix_chars="@")
parser.add_argument("path", default=SDL_ROOT, nargs="?", type=pathlib.Path, help="Path to look for stdlib symbols")
parser.add_argument("paths", default=[SDL_ROOT / "src", SDL_ROOT / "test"], nargs="*", type=pathlib.Path, help="Paths to look for stdlib symbols")
args = parser.parse_args()

print(f"Looking for stdlib usage in {args.path}...")
print(f"Looking for stdlib usage in {', '.join(str(p) for p in args.paths)}...")

if args.path.is_file():
match_count = find_symbols_in_file(args.path)
else:
match_count = find_symbols_in_dir(args.path)
match_count = 0
for path in args.paths:
if path.is_file():
match_count = find_symbols_in_file(path)
else:
match_count = find_symbols_in_dir(path)

if match_count:
print("If the stdlib usage is intentional, add a '// This should NOT be SDL_<symbol>()' line comment.")
Expand Down
12 changes: 10 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ include(sdlcompilers)
check_language(CXX)
if(CMAKE_CXX_COMPILER)
enable_language(CXX)

find_package(Qt6 QUIET COMPONENTS Widgets)
if(Qt6_FOUND)

if(cxx_std_17 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
add_subdirectory(qt6)
endif()
endif()
endif()

find_package(Python3 COMPONENTS Interpreter)
Expand Down Expand Up @@ -710,8 +718,8 @@ function(add_sdl_test TEST TARGET)
set(installedtestsdir "${CMAKE_INSTALL_FULL_LIBEXECDIR}/installed-tests/SDL3")
configure_file(template.test.in "${exe}.test" @ONLY)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/${exe}.test"
DESTINATION ${CMAKE_INSTALL_DATADIR}/installed-tests/SDL3
FILES "${CMAKE_CURRENT_BINARY_DIR}/${exe}.test"
DESTINATION ${CMAKE_INSTALL_DATADIR}/installed-tests/SDL3
)
endif()
if(TARGET pretest AND NOT "${TARGET}" MATCHES "pretest")
Expand Down
10 changes: 10 additions & 0 deletions test/qt6/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
qt_add_executable(testqt6 WIN32
main.cpp
mainwindow.h
mainwindow.cpp
QSDLCanvas.h
QSDLCanvas.cpp
)
target_compile_features(testqt6 PRIVATE cxx_std_17)
target_link_libraries(testqt6 PRIVATE Qt6::Widgets SDL3::SDL3)
set_property(TARGET testqt6 PROPERTY AUTOMOC TRUE)
111 changes: 111 additions & 0 deletions test/qt6/QSDLCanvas.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/
#include "QSDLCanvas.h"


QSDLCanvas::QSDLCanvas(QWidget *parent) : QWidget(parent), m_drawTimer(this)
{
// Allow SDL to draw to the window
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_NoSystemBackground);
}

QSDLCanvas::~QSDLCanvas()
{
if (m_renderer) {
SDL_DestroyRenderer(m_renderer);
}
if (m_window) {
SDL_DestroyWindow(m_window);
}
}

void QSDLCanvas::onUpdate()
{
SDL_Event event;
while (SDL_PollEvent(&event)) {
onEvent(&event);
}

onDraw();
}

void QSDLCanvas::changeRenderer(const QString &name)
{
m_rendererName = name;
m_rendererNameChanged = true;

recreateRenderer();
}

void QSDLCanvas::onDraw()
{
SDL_SetRenderDrawColor(m_renderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(m_renderer);

// Do your drawing here

SDL_RenderPresent(m_renderer);
}

void QSDLCanvas::onEvent(SDL_Event *event)
{

}

void QSDLCanvas::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);

if (!m_window) {
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetPointerProperty(props, "sdl2-compat.external_window", (void *)winId());
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, false);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
m_window = SDL_CreateWindowWithProperties(props);
SDL_DestroyProperties(props);
}
if (!m_window) {
SDL_Log("Couldn't create SDL window: %s", SDL_GetError());
return;
}

recreateRenderer();

int ms = (int)(1000.0f / framerate());
connect(&m_drawTimer, SIGNAL(timeout()), this, SLOT(onUpdate()));
m_drawTimer.start(ms);
}

void QSDLCanvas::recreateRenderer()
{
if (m_rendererNameChanged) {
m_rendererNameChanged = false;
QByteArray name_byte_array = m_rendererName.toUtf8();
const char *name_bytes = name_byte_array.data();
if (m_rendererName.length() == 0) {
name_bytes = NULL;
}
if (m_renderer) {
SDL_DestroyRenderer(m_renderer);
m_renderer = nullptr;
}
m_renderer = SDL_CreateRenderer(m_window, name_bytes);
if (!m_renderer) {
SDL_Log("Couldn't create SDL renderer(%s): %s", name_bytes, SDL_GetError());
return;
}
SDL_Log("Render driver changed to %s", name_bytes);
}
}
58 changes: 58 additions & 0 deletions test/qt6/QSDLCanvas.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/
#include <QTimer>
#include <QWidget>

#include <SDL3/SDL.h>

class QSDLCanvas : public QWidget
{
Q_OBJECT

public:
QSDLCanvas(QWidget *parent = nullptr);
virtual ~QSDLCanvas();

public Q_SLOTS:
void changeRenderer(const QString &name);

protected Q_SLOTS:
virtual void onUpdate();

protected:

void recreateRenderer();

// Override this to set the update framerate, this is called when the widget is shown
virtual float framerate() { return 60.0f; }

// Override this to draw to the canvas
virtual void onDraw();

// Override this to handle SDL events
// This example assumes there is only one canvas and it should process all SDL events
virtual void onEvent(SDL_Event *event);

// Handle the Qt show event
virtual void showEvent(QShowEvent *event) override;

// Let Qt know that we're going to do our own drawing
virtual QPaintEngine *paintEngine() const override { return nullptr; }

protected:
SDL_Window *m_window = nullptr;
SDL_Renderer *m_renderer = nullptr;
QTimer m_drawTimer;

QString m_rendererName;
bool m_rendererNameChanged = true;
};
66 changes: 66 additions & 0 deletions test/qt6/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/

#include "mainwindow.h"

#include <QApplication>
#include <QCommandLineParser>
#include <QErrorMessage>

#include <SDL3/SDL.h>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QCoreApplication::setApplicationName("sdl3-qt-demp");
QCoreApplication::setApplicationVersion(SDL_GetRevision());

QCommandLineParser parser;
parser.setApplicationDescription("SDL3 example demonstrating Qt6 integration");
parser.addHelpOption();
parser.addVersionOption();

parser.process(app);

QString app_platform_name = app.platformName();

if (app_platform_name == "xcb") {
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "x11", SDL_HINT_OVERRIDE);
#if defined(QT_FEATURE_wayland) && QT_CONFIG(wayland) == 1
} else if (app_platform_name == "wayland" || app_platform_name == "wayland-egl") {
/* Get the wl_display object from Qt */
QNativeInterface::QWaylandApplication *qtWlApp = app.nativeInterface<QNativeInterface::QWaylandApplication>();
SDL_SetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, qtWlApp->display());
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
#endif
} else if (app_platform_name == "windows") {
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "windows", SDL_HINT_OVERRIDE);
} else if (app_platform_name == "qnx") {
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "qnx", SDL_HINT_OVERRIDE);
} else if (app_platform_name == "cocoa") {
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "cocoa", SDL_HINT_OVERRIDE);
} else if (app_platform_name == "ios") {
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "ios", SDL_HINT_OVERRIDE);
} else {
QErrorMessage error_message;
error_message.showMessage(QString("Don't know SDL platform equivalent for qt platform: ") + app.platformName());
app.exec();
return 1;
}

MainWindow window;
window.show();

const int ret = app.exec();
SDL_Quit();
return ret;
}
Loading
Loading