Simplify C++ WindowAdapter <> Renderer interface further

Instead of the WindowAdapter being a template for a concept, let's just
use an abstract base class for the renderer. Since we provide the
renderers, this simplifies two things:

- Ownership becomes clear to the user by creating the renderer instance
in a field of theirs.
- All template use goes away on the user side.
This commit is contained in:
Simon Hausmann 2023-05-17 17:27:41 +02:00 committed by Simon Hausmann
parent fabe3ec189
commit baba30370a
4 changed files with 76 additions and 86 deletions

View file

@ -25,23 +25,55 @@ namespace experimental {
/// Namespace to be used when you implement your own Platform /// Namespace to be used when you implement your own Platform
namespace platform { namespace platform {
/// The Renderer is one of the Type provided by Slint to do the rendering of a scene. /// Internal interface for a renderer for use with the WindowAdapter.
/// class AbstractRenderer
/// See SoftwareRenderer or SkiaRenderer
template<typename R>
concept Renderer = requires(R r)
{ {
cbindgen_private::RendererPtr { r.renderer_handle() }; private:
/// \private
virtual cbindgen_private::RendererPtr renderer_handle() const = 0;
friend class WindowAdapter;
}; };
/// Base class common to all WindowAdapter<R>. See the documentation of WindowAdapter /// Base class for the layer between a slint::Window and the internal window from the platform
class AbstractWindowAdapter ///
/// Re-implement this class to do the link between the two.
///
class WindowAdapter
{ {
// This is a pointer to the rust window that own us.
// Note that we do not have ownership (there is no reference increase for this)
// because it would otherwise be a reference loop
cbindgen_private::WindowAdapterRcOpaque self {};
// Whether this WindowAdapter was already given to the slint runtime
bool was_initialized = false;
private:
friend class Platform;
cbindgen_private::WindowAdapterRcOpaque initialize()
{
cbindgen_private::slint_window_adapter_new(
this, [](void *wa) { delete reinterpret_cast<const WindowAdapter *>(wa); },
[](void *wa) {
return reinterpret_cast<const WindowAdapter *>(wa)
->renderer()
.renderer_handle();
},
[](void *wa) { reinterpret_cast<const WindowAdapter *>(wa)->show(); },
[](void *wa) { reinterpret_cast<const WindowAdapter *>(wa)->hide(); },
[](void *wa) { reinterpret_cast<const WindowAdapter *>(wa)->request_redraw(); },
[](void *wa) -> cbindgen_private::IntSize {
return reinterpret_cast<const WindowAdapter *>(wa)->physical_size();
},
&self);
was_initialized = true;
return self;
}
public: public:
virtual ~AbstractWindowAdapter() = default; /// Construct a WindowAdapter
AbstractWindowAdapter(const AbstractWindowAdapter &) = delete; explicit WindowAdapter() { }
AbstractWindowAdapter &operator=(const AbstractWindowAdapter &) = delete; virtual ~WindowAdapter() = default;
AbstractWindowAdapter() = default;
/// This function is called by Slint when the slint window is shown. /// This function is called by Slint when the slint window is shown.
/// ///
@ -63,56 +95,9 @@ public:
/// Returns the actual physical size of the window /// Returns the actual physical size of the window
virtual slint::PhysicalSize physical_size() const = 0; virtual slint::PhysicalSize physical_size() const = 0;
private: /// Re-implement this function to provide a reference to the renderer for use with the window
friend class Platform; /// adapter.
virtual cbindgen_private::WindowAdapterRcOpaque initialize() = 0; virtual AbstractRenderer &renderer() const = 0;
};
/// Base class for the layer between a slint::Window and the internal window from the platform
///
/// Re-implement this class to do the link between the two.
///
/// The R template parameter is the Renderer which is one of the renderer type provided by Slint
template<Renderer R>
class WindowAdapter : public AbstractWindowAdapter
{
// This is a pointer to the rust window that own us.
// Note that we do not have ownership (there is no reference increase for this)
// because it would otherwise be a reference loop
cbindgen_private::WindowAdapterRcOpaque self {};
std::unique_ptr<R> m_renderer;
// Whether this WindowAdapter was already given to the slint runtime
bool was_initialized = false;
private:
cbindgen_private::WindowAdapterRcOpaque initialize() final
{
using WA = WindowAdapter<R>;
cbindgen_private::slint_window_adapter_new(
this, [](void *wa) { delete reinterpret_cast<const WA *>(wa); },
[](void *wa) {
return reinterpret_cast<const WA *>(wa)->m_renderer->renderer_handle();
},
[](void *wa) { reinterpret_cast<const WA *>(wa)->show(); },
[](void *wa) { reinterpret_cast<const WA *>(wa)->hide(); },
[](void *wa) { reinterpret_cast<const WA *>(wa)->request_redraw(); },
[](void *wa) -> cbindgen_private::IntSize {
return reinterpret_cast<const WA *>(wa)->physical_size();
},
&self);
was_initialized = true;
return self;
}
public:
/// Construct a WindowAdapter
explicit WindowAdapter() { }
void set_renderer(std::unique_ptr<R> renderer) { m_renderer = std::move(renderer); }
/// Return a reference to the renderer that can be used to do the rendering.
const R &renderer() const { return *m_renderer; }
/// Return the slint::Window associated with this window. /// Return the slint::Window associated with this window.
/// ///
@ -178,7 +163,7 @@ public:
Platform() = default; Platform() = default;
/// Returns a new WindowAdapter /// Returns a new WindowAdapter
virtual std::unique_ptr<AbstractWindowAdapter> create_window_adapter() const = 0; virtual std::unique_ptr<WindowAdapter> create_window_adapter() const = 0;
/// Register the platform to Slint. Must be called before Slint window are created. Can only /// Register the platform to Slint. Must be called before Slint window are created. Can only
/// be called once in an application. /// be called once in an application.
@ -199,7 +184,7 @@ public:
/// To be used as a template parameter of the WindowAdapter. /// To be used as a template parameter of the WindowAdapter.
/// ///
/// Use the render() function to render in a buffer /// Use the render() function to render in a buffer
class SoftwareRenderer class SoftwareRenderer : public AbstractRenderer
{ {
mutable cbindgen_private::SoftwareRendererOpaque inner; mutable cbindgen_private::SoftwareRendererOpaque inner;
@ -213,7 +198,7 @@ public:
} }
/// \private /// \private
cbindgen_private::RendererPtr renderer_handle() const cbindgen_private::RendererPtr renderer_handle() const override
{ {
return cbindgen_private::slint_software_renderer_handle(inner); return cbindgen_private::slint_software_renderer_handle(inner);
} }
@ -311,7 +296,7 @@ public:
/// of the homonymous functions /// of the homonymous functions
/// ///
/// Use render to perform the rendering. /// Use render to perform the rendering.
class SkiaRenderer class SkiaRenderer : public AbstractRenderer
{ {
mutable cbindgen_private::SkiaRendererOpaque inner; mutable cbindgen_private::SkiaRendererOpaque inner;
@ -327,7 +312,7 @@ public:
} }
/// \private /// \private
cbindgen_private::RendererPtr renderer_handle() const cbindgen_private::RendererPtr renderer_handle() const override
{ {
return cbindgen_private::slint_skia_renderer_handle(inner); return cbindgen_private::slint_skia_renderer_handle(inner);
} }

View file

@ -17,7 +17,7 @@ namespace slint_platform = slint::experimental::platform;
struct MyPlatform : public slint_platform::Platform struct MyPlatform : public slint_platform::Platform
{ {
mutable std::unique_ptr<MyWindowAdapter> the_window; mutable std::unique_ptr<MyWindowAdapter> the_window;
std::unique_ptr<slint_platform::AbstractWindowAdapter> create_window_adapter() const override std::unique_ptr<slint_platform::WindowAdapter> create_window_adapter() const override
{ {
return std::move(the_window); return std::move(the_window);
} }

View file

@ -19,10 +19,11 @@ struct Geometry
uint32_t height = 0; uint32_t height = 0;
}; };
struct MyWindowAdapter : public slint_platform::WindowAdapter<slint_platform::SkiaRenderer> struct MyWindowAdapter : public slint_platform::WindowAdapter
{ {
HWND hwnd; HWND hwnd;
Geometry geometry = { 0, 0, 600, 300 }; Geometry geometry = { 0, 0, 600, 300 };
std::unique_ptr<slint_platform::SkiaRenderer> m_renderer;
MyWindowAdapter(HWND winId) MyWindowAdapter(HWND winId)
{ {
@ -55,13 +56,15 @@ struct MyWindowAdapter : public slint_platform::WindowAdapter<slint_platform::Sk
NULL // Additional application data NULL // Additional application data
); );
set_renderer(std::make_unique<slint_platform::SkiaRenderer>( m_renderer = std::make_unique<slint_platform::SkiaRenderer>(
slint_platform::NativeWindowHandle::from_win32(hwnd, hInstance), slint_platform::NativeWindowHandle::from_win32(hwnd, hInstance),
slint::PhysicalSize({ 600, 300 }))); slint::PhysicalSize({ 600, 300 }));
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
} }
slint_platform::AbstractRenderer &renderer() const override { return *m_renderer.get(); }
slint::PhysicalSize physical_size() const override slint::PhysicalSize physical_size() const override
{ {
RECT r; RECT r;
@ -72,20 +75,20 @@ struct MyWindowAdapter : public slint_platform::WindowAdapter<slint_platform::Sk
void show() const override void show() const override
{ {
ShowWindow(hwnd, SW_SHOWNORMAL); ShowWindow(hwnd, SW_SHOWNORMAL);
renderer().show(); m_renderer->show();
} }
void hide() const override void hide() const override
{ {
// TODO: destroy window // TODO: destroy window
renderer().hide(); m_renderer->hide();
} }
void request_redraw() const override { InvalidateRect(hwnd, nullptr, false); } void request_redraw() const override { InvalidateRect(hwnd, nullptr, false); }
void render() void render()
{ {
renderer().render(window(), physical_size()); m_renderer->render(window(), physical_size());
if (has_active_animations()) if (has_active_animations())
request_redraw(); request_redraw();
} }
@ -93,7 +96,7 @@ struct MyWindowAdapter : public slint_platform::WindowAdapter<slint_platform::Sk
void resize(uint32_t width, uint32_t height) void resize(uint32_t width, uint32_t height)
{ {
slint::PhysicalSize windowSize({ width, height }); slint::PhysicalSize windowSize({ width, height });
renderer().resize(windowSize); m_renderer->resize(windowSize);
dispatch_resize_event(slint::LogicalSize({ (float)width, (float)height })); dispatch_resize_event(slint::LogicalSize({ (float)width, (float)height }));
} }

View file

@ -49,18 +49,20 @@ static slint_platform::NativeWindowHandle window_handle_for_qt_window(QWindow *w
#endif #endif
} }
class MyWindow : public QWindow, public slint_platform::WindowAdapter<slint_platform::SkiaRenderer> class MyWindow : public QWindow, public slint_platform::WindowAdapter
{ {
std::unique_ptr<slint_platform::SkiaRenderer> m_renderer;
public: public:
MyWindow(QWindow *parentWindow = nullptr) MyWindow(QWindow *parentWindow = nullptr) : QWindow(parentWindow)
: QWindow(parentWindow), slint_platform::WindowAdapter<slint_platform::SkiaRenderer>()
{ {
set_renderer(std::make_unique<slint_platform::SkiaRenderer>( m_renderer = std::make_unique<slint_platform::SkiaRenderer>(
window_handle_for_qt_window(this), window_handle_for_qt_window(this),
slint::PhysicalSize({ uint32_t(width()), uint32_t(height()) }))); slint::PhysicalSize({ uint32_t(width()), uint32_t(height()) }));
} }
slint_platform::AbstractRenderer &renderer() const override { return *m_renderer.get(); }
/*void keyEvent(QKeyEvent *event) override /*void keyEvent(QKeyEvent *event) override
{ {
renderer()->dispatch_key_event(slint::cbingen_private::UglyEnum {... }) renderer()->dispatch_key_event(slint::cbingen_private::UglyEnum {... })
@ -71,7 +73,7 @@ public:
slint_platform::update_timers_and_animations(); slint_platform::update_timers_and_animations();
auto windowSize = slint::PhysicalSize({ uint32_t(width()), uint32_t(height()) }); auto windowSize = slint::PhysicalSize({ uint32_t(width()), uint32_t(height()) });
renderer().render(window(), windowSize); m_renderer->render(window(), windowSize);
if (has_active_animations()) { if (has_active_animations()) {
requestUpdate(); requestUpdate();
@ -92,11 +94,11 @@ public:
{ {
auto window = const_cast<QWindow *>(static_cast<const QWindow *>(this)); auto window = const_cast<QWindow *>(static_cast<const QWindow *>(this));
window->QWindow::show(); window->QWindow::show();
renderer().show(); m_renderer->show();
} }
void hide() const override void hide() const override
{ {
renderer().hide(); m_renderer->hide();
const_cast<MyWindow *>(this)->QWindow::hide(); const_cast<MyWindow *>(this)->QWindow::hide();
} }
slint::PhysicalSize physical_size() const override slint::PhysicalSize physical_size() const override
@ -111,9 +113,9 @@ public:
{ {
auto windowSize = slint::PhysicalSize( auto windowSize = slint::PhysicalSize(
{ uint32_t(ev->size().width()), uint32_t(ev->size().height()) }); { uint32_t(ev->size().width()), uint32_t(ev->size().height()) });
renderer().resize(windowSize); m_renderer->resize(windowSize);
float scale_factor = devicePixelRatio(); float scale_factor = devicePixelRatio();
WindowAdapter<slint_platform::SkiaRenderer>::dispatch_resize_event( WindowAdapter::dispatch_resize_event(
slint::LogicalSize({ float(windowSize.width) / scale_factor, slint::LogicalSize({ float(windowSize.width) / scale_factor,
float(windowSize.height) / scale_factor })); float(windowSize.height) / scale_factor }));
} }
@ -152,7 +154,7 @@ struct MyPlatform : public slint_platform::Platform
std::unique_ptr<QWindow> parentWindow; std::unique_ptr<QWindow> parentWindow;
std::unique_ptr<slint_platform::AbstractWindowAdapter> create_window_adapter() const override std::unique_ptr<slint_platform::WindowAdapter> create_window_adapter() const override
{ {
return std::make_unique<MyWindow>(parentWindow.get()); return std::make_unique<MyWindow>(parentWindow.get());
} }