// This file is part of Desktop App Toolkit, // a set of libraries for developing nice desktop applications. // // For license and copyright information please follow this link: // https://github.com/desktop-app/legal/blob/master/LEGAL // #include "ui/gl/gl_window.h" #include "ui/gl/gl_detection.h" #include "ui/widgets/rp_window.h" #include "base/event_filter.h" #include "base/platform/base_platform_info.h" #include "base/debug_log.h" #ifdef Q_OS_WIN #include "ui/platform/win/ui_window_win.h" #endif // Q_OS_WIN #include #include namespace Ui::GL { namespace { constexpr auto kUseNativeChild = false;// ::Platform::IsWindows(); class RpWidgetOpenGL : public RpWidget { protected: #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) std::optional rhiConfig() const override { return { QPlatformBackingStoreRhiConfig::OpenGL }; } #endif // Qt >= 6.4.0 }; class RpWindowOpenGL : public RpWindow { protected: #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) std::optional rhiConfig() const override { return { QPlatformBackingStoreRhiConfig::OpenGL }; } #endif // Qt >= 6.4.0 }; [[nodiscard]] Fn ChooseBackendWrap( Fn chooseBackend) { return [=](Capabilities capabilities) { const auto backend = chooseBackend(capabilities); const auto use = backend == Backend::OpenGL; LOG(("OpenGL: %1 (Window)").arg(use ? "[TRUE]" : "[FALSE]")); return backend; }; } } // namespace Window::Window() : Window(ChooseBackendDefault) { } Window::Window(Fn chooseBackend) : _window(createWindow(ChooseBackendWrap(chooseBackend))) , _bodyNativeWrap(createNativeBodyWrap(ChooseBackendWrap(chooseBackend))) , _body(_bodyNativeWrap ? _bodyNativeWrap.get() : _window->body().get()) { } Window::~Window() = default; Backend Window::backend() const { return _backend; } not_null Window::window() const { return _window.get(); } not_null Window::widget() const { return _body.get(); } std::unique_ptr Window::createWindow( const Fn &chooseBackend) { std::unique_ptr result = std::make_unique(); if constexpr (!kUseNativeChild) { _backend = chooseBackend(CheckCapabilities(result.get())); if (_backend != Backend::OpenGL) { // We have to create a new window, if OpenGL initialization failed. result = std::make_unique(); } } return result; } std::unique_ptr Window::createNativeBodyWrap( const Fn &chooseBackend) { if constexpr (!kUseNativeChild) { return nullptr; } const auto create = [] { auto result = std::make_unique(); result->setWindowFlags(Qt::FramelessWindowHint | Qt::Window); result->setAttribute(Qt::WA_NativeWindow); result->setAttribute(Qt::WA_DontCreateNativeAncestors); result->setAttribute(Qt::WA_OpaquePaintEvent); result->setAttribute(Qt::WA_NoSystemBackground); return result; }; auto result = create(); _backend = chooseBackend(CheckCapabilities(result.get())); if (_backend != Backend::OpenGL) { // We have to create a new window, if OpenGL initialization failed. result = create(); } const auto nativeParent = _window->body(); nativeParent->setAttribute(Qt::WA_OpaquePaintEvent); nativeParent->setAttribute(Qt::WA_NoSystemBackground); const auto raw = result.get(); raw->setParent(nativeParent); raw->show(); raw->update(); #ifdef Q_OS_WIN // In case a child native window fully covers the parent window, // the system never sends a WM_PAINT message to the parent window. // // In this case if you minimize / hide the parent window, it receives // QExposeEvent with isExposed() == false in window state change handler. // // But it never receives QExposeEvent with isExposed() == true, because // window state change handler doesn't send it, instead the WM_PAINT is // supposed to send it. No WM_PAINT -> no expose -> broken UI updating. const auto childWindow = raw->windowHandle(); base::install_event_filter(childWindow, [=](not_null event) { if (event->type() == QEvent::Expose && childWindow->isExposed()) { Platform::SendWMPaintForce(_window.get()); } return base::EventFilterResult::Continue; }); _window->sizeValue( ) | rpl::start_with_next([=](QSize size) { auto geometry = QRect(QPoint(), size); if constexpr (::Platform::IsWindows()) { if (const auto screen = _window->screen()) { if (screen->size() == size) { // Fix flicker in FullScreen OpenGL window on Windows. geometry = geometry.marginsAdded({ 0, 0, 0, 1 }); } } } raw->setGeometry(geometry); }, raw->lifetime()); #endif // Q_OS_WIN return result; } } // namespace Ui::GL