#ifdef PANDA3DS_ENABLE_OPENGL #include "opengl.hpp" #endif // opengl.hpp must be included at the very top. This comment exists to make clang-format not reorder it :p #include #include #include #include #include #include #if !defined(_WIN32) && !defined(APPLE) #include #endif #include "panda_qt/screen/screen.hpp" #include "panda_qt/screen/screen_gl.hpp" #include "panda_qt/screen/screen_mtl.hpp" // Screen widget, based on https://github.com/stenzek/duckstation/blob/master/src/duckstation-qt/displaywidget.cpp // and https://github.com/melonDS-emu/melonDS/blob/master/src/frontend/qt_sdl/main.cpp #ifdef PANDA3DS_ENABLE_OPENGL ScreenWidget::ScreenWidget(API api, ResizeCallback resizeCallback, QWidget* parent) : api(api), QWidget(parent), resizeCallback(resizeCallback) { // Create a native window for use with our graphics API of choice setAutoFillBackground(false); setAttribute(Qt::WA_NativeWindow, true); setAttribute(Qt::WA_NoSystemBackground, true); setAttribute(Qt::WA_PaintOnScreen, true); setAttribute(Qt::WA_KeyCompression, false); setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); // The graphics context, as well as resizing and showing the widget, is handled by the screen backend } void ScreenWidget::resizeEvent(QResizeEvent* event) { previousWidth = surfaceWidth; previousHeight = surfaceHeight; QWidget::resizeEvent(event); // Update surfaceWidth/surfaceHeight following the resize std::optional windowInfo = getWindowInfo(); if (windowInfo) { this->windowInfo = *windowInfo; } reloadScreenCoordinates(); resizeDisplay(); } void ScreenWidget::reloadScreenCoordinates() { ScreenLayout::calculateCoordinates(screenCoordinates, u32(width()), u32(height()), topScreenSize, screenLayout); } void ScreenWidget::reloadScreenLayout(ScreenLayout::Layout newLayout, float newTopScreenSize) { screenLayout = newLayout; topScreenSize = newTopScreenSize; reloadScreenCoordinates(); } qreal ScreenWidget::devicePixelRatioFromScreen() const { const QScreen* screenForRatio = windowHandle()->screen(); if (!screenForRatio) { screenForRatio = QGuiApplication::primaryScreen(); } return screenForRatio ? screenForRatio->devicePixelRatio() : static_cast(1); } int ScreenWidget::scaledWindowWidth() const { return std::max(static_cast(std::ceil(static_cast(width()) * devicePixelRatioFromScreen())), 1); } int ScreenWidget::scaledWindowHeight() const { return std::max(static_cast(std::ceil(static_cast(height()) * devicePixelRatioFromScreen())), 1); } std::optional ScreenWidget::getWindowInfo() { WindowInfo wi; // Windows and Apple are easy here since there's no display connection. #if defined(_WIN32) wi.type = WindowInfo::Type::Win32; wi.window_handle = reinterpret_cast(winId()); #elif defined(__APPLE__) wi.type = WindowInfo::Type::MacOS; wi.window_handle = reinterpret_cast(winId()); #else QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); const QString platform_name = QGuiApplication::platformName(); if (platform_name == QStringLiteral("xcb")) { wi.type = WindowInfo::Type::X11; wi.display_connection = pni->nativeResourceForWindow("display", windowHandle()); wi.window_handle = reinterpret_cast(winId()); } else if (platform_name == QStringLiteral("wayland")) { wi.type = WindowInfo::Type::Wayland; QWindow* handle = windowHandle(); if (handle == nullptr) { return std::nullopt; } wi.display_connection = pni->nativeResourceForWindow("display", handle); wi.window_handle = pni->nativeResourceForWindow("surface", handle); } else { qCritical() << "Unknown PNI platform " << platform_name; return std::nullopt; } #endif wi.surface_width = static_cast(scaledWindowWidth()); wi.surface_height = static_cast(scaledWindowHeight()); wi.surface_scale = static_cast(devicePixelRatioFromScreen()); surfaceWidth = wi.surface_width; surfaceHeight = wi.surface_height; return wi; } #endif ScreenWidget* ScreenWidget::getWidget(API api, ResizeCallback resizeCallback, QWidget* parent) { if (api == API::OpenGL) { return new ScreenWidgetGL(api, resizeCallback, parent); } else if (api == API::Metal) { return new ScreenWidgetMTL(api, resizeCallback, parent); } else if (api == API::Vulkan) { Helpers::panic("Vulkan is not yet supported on Panda3DS-Qt. Try SDL instead"); } else { Helpers::panic("ScreenWidget::getWidget: Unimplemented graphics API"); } }