Program Listing for File slint_platform.h

Return to documentation for file (/home/runner/work/slint/slint/api/cpp/include/slint_platform.h)

// Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial

#pragma once

#ifndef SLINT_FEATURE_EXPERIMENTAL
#    warning "slint_platform.h API only available when SLINT_FEATURE_EXPERIMENTAL is activated"
#else

#    include "slint.h"

struct xcb_connection_t;
struct wl_surface;
struct wl_display;

namespace slint {

namespace experimental {

namespace platform {

template<typename R>
concept Renderer = requires(R r)
{
    r.init(static_cast<const cbindgen_private::WindowAdapterRcOpaque *>(nullptr));
    cbindgen_private::RendererPtr { r.renderer_handle() };
};

class AbstractWindowAdapter
{
public:
    virtual ~AbstractWindowAdapter() = default;
    AbstractWindowAdapter(const AbstractWindowAdapter &) = delete;
    AbstractWindowAdapter &operator=(const AbstractWindowAdapter &) = delete;
    AbstractWindowAdapter() = default;

    virtual void show() const { }
    virtual void hide() const { }

    virtual void request_redraw() const { }

private:
    friend class Platform;
    virtual cbindgen_private::WindowAdapterRcOpaque initialize() = 0;
};


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 {};
    // Whether this WindowAdapter was already given to the slint runtime
    const R m_renderer;
    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(); }, &self);
        m_renderer.init(&self);
        was_initialized = true;
        return self;
    }

public:
    template<typename... Args>
    explicit WindowAdapter(Args... a) : m_renderer(std::forward<Args>(a)...)
    {
    }

    const R &renderer() const { return m_renderer; }

    const Window &window() const
    {
        if (!was_initialized)
            std::abort();
        // This works because cbindgen_private::WindowAdapterRcOpaque and Window have the same
        // layout
        return *reinterpret_cast<const Window *>(&self);
    }

    Window &window()
    {
        if (!was_initialized)
            std::abort();
        // This works because cbindgen_private::WindowAdapterRcOpaque and Window have the same
        // layout
        return *reinterpret_cast<Window *>(&self);
    }

    // Note: in rust, this is on the Window. FIXME: use a public event type
    void dispatch_pointer_event(const cbindgen_private::MouseEvent &event)
    {
        private_api::assert_main_thread();
        if (was_initialized) {
            cbindgen_private::slint_windowrc_dispatch_pointer_event(&self, event);
        }
    }

    // Note: in rust, this is on the Window. FIXME: use a public event type
    void dispatch_key_event(const cbindgen_private::KeyInputEvent &event)
    {
        private_api::assert_main_thread();
        if (was_initialized) {
            cbindgen_private::slint_windowrc_dispatch_key_event(&self, event);
        }
    }

    bool has_active_animations() const
    {
        return cbindgen_private::slint_windowrc_has_active_animations(&self);
    }
};

class Platform
{
public:
    virtual ~Platform() = default;
    Platform(const Platform &) = delete;
    Platform &operator=(const Platform &) = delete;
    Platform() = default;

    virtual std::unique_ptr<AbstractWindowAdapter> create_window_adapter() const = 0;

    static void register_platform(std::unique_ptr<Platform> platform)
    {
        cbindgen_private::slint_platform_register(
                platform.release(), [](void *p) { delete reinterpret_cast<const Platform *>(p); },
                [](void *p, cbindgen_private::WindowAdapterRcOpaque *out) {
                    auto w = reinterpret_cast<const Platform *>(p)->create_window_adapter();
                    *out = w->initialize();
                    (void)w.release();
                });
    }
};

template<int MAX_BUFFER_AGE = 0>
class SoftwareRenderer
{
    mutable cbindgen_private::SoftwareRendererOpaque inner;

public:
    virtual ~SoftwareRenderer()
    {
        if (inner) {
            cbindgen_private::slint_software_renderer_drop(MAX_BUFFER_AGE, inner);
        }
    };
    SoftwareRenderer(const SoftwareRenderer &) = delete;
    SoftwareRenderer &operator=(const SoftwareRenderer &) = delete;
    SoftwareRenderer() = default;

    void init(const cbindgen_private::WindowAdapterRcOpaque *win) const
    {
        if (inner) {
            cbindgen_private::slint_software_renderer_drop(MAX_BUFFER_AGE, inner);
        }
        inner = cbindgen_private::slint_software_renderer_new(MAX_BUFFER_AGE, win);
    }

    cbindgen_private::RendererPtr renderer_handle() const
    {
        return cbindgen_private::slint_software_renderer_handle(MAX_BUFFER_AGE, inner);
    }

    void render(std::span<slint::cbindgen_private::Rgb8Pixel> buffer, std::size_t stride) const
    {
        cbindgen_private::slint_software_renderer_render_rgb8(MAX_BUFFER_AGE, inner, buffer.data(),
                                                              buffer.size(), stride);
    }
};


class SkiaRenderer
{
    mutable cbindgen_private::SkiaRendererOpaque inner;

public:
    virtual ~SkiaRenderer()
    {
        if (inner) {
            cbindgen_private::slint_skia_renderer_drop(inner);
        }
    };
    SkiaRenderer(const SkiaRenderer &) = delete;
    SkiaRenderer &operator=(const SkiaRenderer &) = delete;
    SkiaRenderer() = default;

    void init(const cbindgen_private::WindowAdapterRcOpaque *win) const
    {
        if (inner) {
            cbindgen_private::slint_skia_renderer_drop(inner);
        }
        inner = cbindgen_private::slint_skia_renderer_new(win);
    }

    cbindgen_private::RendererPtr renderer_handle() const
    {
        return cbindgen_private::slint_skia_renderer_handle(inner);
    }

    void render(PhysicalSize size) const
    {
        cbindgen_private::slint_skia_renderer_render(inner, size);
    }

    void resize(PhysicalSize size) const
    {
        cbindgen_private::slint_skia_renderer_resize(inner, size);
    }

    void hide() const { cbindgen_private::slint_skia_renderer_hide(inner); }

#    if !defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)
    void show(uint32_t /*xcb_window_t*/ window, uint32_t /*xcb_visualid_t*/ visual_id,
              xcb_connection_t *connection, int screen, PhysicalSize size) const
    {
        cbindgen_private::slint_skia_renderer_show_x11(inner, window, visual_id, connection, screen,
                                                       size);
    }

    void show(wl_surface *surface, wl_display *display, PhysicalSize size) const
    {
        cbindgen_private::slint_skia_renderer_show_wayland(inner, surface, display, size);
    }

#    elif defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)

    void show(void *nsview, void *nswindow, PhysicalSize size) const
    {
        cbindgen_private::slint_skia_renderer_show_appkit(inner, nsview, nswindow, size);
    }

#    elif !defined(__APPLE__) && (defined(_WIN32) || !defined(_WIN64))

    void show(void *HWND, void *hinstance, PhysicalSize size) const
    {
        cbindgen_private::slint_skia_renderer_show_win32(inner, HWND, hinstance, size);
    }
#    endif
};

inline void update_timers_and_animations()
{
    cbindgen_private::slint_platform_update_timers_and_animations();
}

}
}
}
#endif