From c66adb187bcce922a0e0fa525ba5725e22b4948c Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 18 Jun 2026 20:23:13 +0200 Subject: [PATCH 1/5] Limit default search path of build-scripts/check_stdlib_usage.py --- build-scripts/check_stdlib_usage.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/build-scripts/check_stdlib_usage.py b/build-scripts/check_stdlib_usage.py index a0b6e64e6806c..f944e27dedf4b 100755 --- a/build-scripts/check_stdlib_usage.py +++ b/build-scripts/check_stdlib_usage.py @@ -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_()' line comment.") From a089caf2938646eec91b52b6eb6c1ca87dd03579 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 18 Jun 2026 10:55:52 +0200 Subject: [PATCH 2/5] ci: bump Ubuntu runner of Intel oneAPI --- .github/workflows/create-test-plan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index a98b583dfb942..6b1c4ef232756 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -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, ), From d5fa74054759781fa791918b16e2ac5c6cbbab32 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 18 Jun 2026 10:36:52 +0200 Subject: [PATCH 3/5] ci: avoid brew creating noisy annotations --- .github/workflows/generic.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index ac733edd1a291..e4313ef99e9bb 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -116,7 +116,7 @@ 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 @@ -138,9 +138,13 @@ jobs: - 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 }} From ff5e589cbb972ecac9b56c4dd4364e63f5786003 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 18 Jun 2026 20:46:54 +0200 Subject: [PATCH 4/5] ci: disable clang-tidy on Ubuntu 22.04 Its clang-tidy is not compatible with c++17, required by Qt6 --- .github/workflows/create-test-plan.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 6b1c4ef232756..c4d10524ad5a6 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -496,11 +496,13 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool, ctest_args "libswscale-dev", )) match = re.match(r"ubuntu-(?P[0-9]+)\.(?P[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 )) From 652d255cc79322804d1f81b85ae0145099b5eb64 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 17 Jun 2026 20:59:16 +0200 Subject: [PATCH 5/5] Add qt6 example [sdl-ci-filter *] --- .github/workflows/create-test-plan.py | 4 + .github/workflows/generic.yml | 8 +- test/CMakeLists.txt | 12 ++- test/qt6/CMakeLists.txt | 10 +++ test/qt6/QSDLCanvas.cpp | 111 ++++++++++++++++++++++++++ test/qt6/QSDLCanvas.h | 58 ++++++++++++++ test/qt6/main.cpp | 66 +++++++++++++++ test/qt6/mainwindow.cpp | 77 ++++++++++++++++++ test/qt6/mainwindow.h | 25 ++++++ 9 files changed, 362 insertions(+), 9 deletions(-) create mode 100644 test/qt6/CMakeLists.txt create mode 100644 test/qt6/QSDLCanvas.cpp create mode 100644 test/qt6/QSDLCanvas.h create mode 100644 test/qt6/main.cpp create mode 100644 test/qt6/mainwindow.cpp create mode 100644 test/qt6/mainwindow.h diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index c4d10524ad5a6..24505ab41962d 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -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" @@ -494,6 +495,8 @@ 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[0-9]+)\.(?P[0-9]+|latest).*", spec.os.value) ubuntu_ge_24 = True @@ -790,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 diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index e4313ef99e9bb..4111d07191fcb 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -119,12 +119,6 @@ jobs: # 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: | @@ -133,7 +127,7 @@ 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 != '' }} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 074c21035da96..928b29dde0a31 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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) @@ -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") diff --git a/test/qt6/CMakeLists.txt b/test/qt6/CMakeLists.txt new file mode 100644 index 0000000000000..04f94488b1c22 --- /dev/null +++ b/test/qt6/CMakeLists.txt @@ -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) diff --git a/test/qt6/QSDLCanvas.cpp b/test/qt6/QSDLCanvas.cpp new file mode 100644 index 0000000000000..d741382d20ca5 --- /dev/null +++ b/test/qt6/QSDLCanvas.cpp @@ -0,0 +1,111 @@ +/* + Copyright (C) 1997-2026 Sam Lantinga + + 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); + } +} diff --git a/test/qt6/QSDLCanvas.h b/test/qt6/QSDLCanvas.h new file mode 100644 index 0000000000000..51c68f739a7d8 --- /dev/null +++ b/test/qt6/QSDLCanvas.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 1997-2026 Sam Lantinga + + 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 +#include + +#include + +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; +}; diff --git a/test/qt6/main.cpp b/test/qt6/main.cpp new file mode 100644 index 0000000000000..8f1158802cfb0 --- /dev/null +++ b/test/qt6/main.cpp @@ -0,0 +1,66 @@ +/* + Copyright (C) 1997-2026 Sam Lantinga + + 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 +#include +#include + +#include + +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(); + 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; +} diff --git a/test/qt6/mainwindow.cpp b/test/qt6/mainwindow.cpp new file mode 100644 index 0000000000000..bcb58a6871651 --- /dev/null +++ b/test/qt6/mainwindow.cpp @@ -0,0 +1,77 @@ +/* + Copyright (C) 1997-2026 Sam Lantinga + + 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 + +#include "mainwindow.h" +#include "QSDLCanvas.h" + +MainWindow::MainWindow() +{ + QWidget *widget = new QWidget; + setCentralWidget(widget); + + m_canvas = new QSDLCanvas(this); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins(0, 4, 0, 0); + layout->addWidget(m_canvas); + widget->setLayout(layout); + + createMenus(); + + setWindowTitle(tr("SDL Qt Demo")); + setMinimumSize(160, 160); + resize(640, 480); +} + +void MainWindow::createMenus() +{ + // Create "File" menu + QMenu *fileMenu = menuBar()->addMenu(tr("&File")); +#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) + QAction *exitAct = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::ApplicationExit), tr("E&xit"), this); +#else + QAction *exitAct = new QAction(tr("E&xit"), this); +#endif + exitAct->setShortcuts(QKeySequence::Quit); + connect(exitAct, &QAction::triggered, this, &QWidget::close); + fileMenu->addAction(exitAct); + + // Create Renderer menu + QMenu *rendererMenu = menuBar()->addMenu(tr("&Renderer")); + QActionGroup* renderGroup = new QActionGroup(this); + renderGroup->setExclusive(true); + { + QAction *defaultDriverAction = new QAction(tr("(default)"), this); + defaultDriverAction->setCheckable(true); + defaultDriverAction->setChecked(true); + renderGroup->addAction(defaultDriverAction); + rendererMenu->addAction(defaultDriverAction); + connect(defaultDriverAction, &QAction::triggered, [this] { m_canvas->changeRenderer(""); }); + } + int count_render_drivers = SDL_GetNumRenderDrivers(); + for (int i = 0; i < count_render_drivers; i++) { + QString driver_name = SDL_GetRenderDriver(i); + QAction *driverAction = new QAction(driver_name, this); + driverAction->setCheckable(true); + driverAction->setChecked(false); + renderGroup->addAction(driverAction); + rendererMenu->addAction(driverAction); + connect(driverAction, &QAction::triggered, [this, driver_name] { m_canvas->changeRenderer(driver_name); }); + } + + // Create Help menu + QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); + QAction *aboutQtAction = new QAction(tr("About &Qt"), this); + connect(aboutQtAction, &QAction::triggered, qApp, &QApplication::aboutQt); + helpMenu->addAction(aboutQtAction); +} diff --git a/test/qt6/mainwindow.h b/test/qt6/mainwindow.h new file mode 100644 index 0000000000000..395523eead2bc --- /dev/null +++ b/test/qt6/mainwindow.h @@ -0,0 +1,25 @@ +/* + Copyright (C) 1997-2026 Sam Lantinga + + 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 + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(); + +private: + void createMenus(); + + class QSDLCanvas *m_canvas; +};