1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
3
4#pragma once
5
6#include "slint.h"
7
8#include <cassert>
9#include <utility>
10
11struct xcb_connection_t;
12struct wl_surface;
13struct wl_display;
14
15#if defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)
16# ifdef __OBJC__
17@class NSView;
18@class NSWindow;
19# else
20typedef struct objc_object NSView;
21typedef struct objc_object NSWindow;
22# endif
23#endif
24
25namespace slint {
26
27/// Use the types in this namespace when implementing a custom Slint platform.
28///
29/// Slint comes with built-in support for different windowing systems, called backends. A backend
30/// is a module that implements the Platform interface in this namespace, interacts with a
31/// windowing system, and uses one of Slint's renderers to display a scene to the windowing system.
32/// A typical Slint application uses one of the built-in backends. Implement your own Platform if
33/// you're using Slint in an environment without a windowing system, such as with microcontrollers,
34/// or you're embedding a Slint UI as plugin in other applications.
35///
36/// Examples of custom platform implementation can be found in the Slint repository:
37/// - https://github.com/slint-ui/slint/tree/master/examples/cpp/platform_native
38/// - https://github.com/slint-ui/slint/tree/master/examples/cpp/platform_qt
39/// - https://github.com/slint-ui/slint/blob/master/api/cpp/esp-idf/slint/src/slint-esp.cpp
40///
41/// The entry point to re-implement a platform is the Platform class. Derive
42/// from slint::platform::Platform, and call slint::platform::set_platform
43/// to set it as the Slint platform.
44///
45/// Another important class to subclass is the WindowAdapter.
46namespace platform {
47
48/// Internal interface for a renderer for use with the WindowAdapter.
49///
50/// This class is not intended to be re-implemented. In places where this class is required, use
51/// of one the existing implementations such as SoftwareRenderer or SkiaRenderer.
52class AbstractRenderer
53{
54private:
55 virtual ~AbstractRenderer() { }
56 AbstractRenderer(const AbstractRenderer &) = delete;
57 AbstractRenderer &operator=(const AbstractRenderer &) = delete;
58 AbstractRenderer() = default;
59
60 /// \private
61 virtual cbindgen_private::RendererPtr renderer_handle() const = 0;
62 friend class WindowAdapter;
63 friend class SoftwareRenderer;
64 friend class SkiaRenderer;
65};
66
67/// Base class for the layer between a slint::Window and the windowing system specific window type,
68/// such as a Win32 `HWND` handle or a `wayland_surface_t`.
69///
70/// Re-implement this class to establish the link between the two, and pass messages in both
71/// directions:
72///
73/// - When receiving messages from the windowing system about state changes, such as the window
74/// being resized, the user requested the window to be closed, input being received, etc. you
75/// need to call the corresponding event functions on the Window, such as
76/// Window::dispatch_resize_event(), Window::dispatch_mouse_press_event(), or
77/// Window::dispatch_close_requested_event().
78///
79/// - Slint sends requests to change visibility, position, size, etc. via virtual functions such as
80/// set_visible(), set_size(), set_position(), or update_window_properties().
81/// Re-implement these functions and delegate the requests to the windowing system.
82///
83/// If the implementation of this bi-directional message passing protocol is incomplete, the user
84/// may experience unexpected behavior, or the intention of the developer calling functions on the
85/// Window API may not be fulfilled.
86///
87/// Your WindowAdapter subclass must hold a renderer (either a SoftwareRenderer or a SkiaRenderer).
88/// In the renderer() method, you must return a reference to it.
89///
90/// # Example
91/// ```cpp
92/// class MyWindowAdapter : public slint::platform::WindowAdapter {
93/// slint::platform::SoftwareRenderer m_renderer;
94/// NativeHandle m_native_window; // a handle to the native window
95/// public:
96/// void request_redraw() override { m_native_window.refresh(); }
97/// slint::PhysicalSize size() const override {
98/// return slint::PhysicalSize({m_native_window.width, m_native_window.height});
99/// }
100/// slint::platform::AbstractRenderer &renderer() override { return m_renderer; }
101/// void set_visible(bool v) override {
102/// if (v) {
103/// m_native_window.show();
104/// } else {
105/// m_native_window.hide();
106/// }
107/// }
108/// // ...
109/// void repaint_callback();
110/// }
111/// ```
112///
113/// Rendering is typically asynchronous, and your windowing system or event loop would invoke
114/// a callback when it is time to render.
115/// ```cpp
116/// void MyWindowAdapter::repaint_callback()
117/// {
118/// slint::platform::update_timers_and_animations();
119/// m_renderer.render(m_native_window.buffer(), m_native_window.width);
120/// // if animations are running, schedule the next frame
121/// if (window().has_active_animations()) m_native_window.refresh();
122/// }
123/// ```
124class WindowAdapter
125{
126 // This is a pointer to the rust window that own us.
127 // Note that we do not have ownership (there is no reference increase for this)
128 // because it would otherwise be a reference loop
129 cbindgen_private::WindowAdapterRcOpaque self {};
130 // Whether this WindowAdapter was already given to the slint runtime
131 bool was_initialized = false;
132
133 cbindgen_private::WindowAdapterRcOpaque initialize()
134 {
135 cbindgen_private::slint_window_adapter_new(
136 user_data: this, drop: [](void *wa) { delete reinterpret_cast<WindowAdapter *>(wa); },
137 get_renderer_ref: [](void *wa) {
138 return reinterpret_cast<WindowAdapter *>(wa)->renderer().renderer_handle();
139 },
140 set_visible: [](void *wa, bool visible) {
141 reinterpret_cast<WindowAdapter *>(wa)->set_visible(visible);
142 },
143 request_redraw: [](void *wa) { reinterpret_cast<WindowAdapter *>(wa)->request_redraw(); },
144 size: [](void *wa) -> cbindgen_private::IntSize {
145 return reinterpret_cast<WindowAdapter *>(wa)->size();
146 },
147 set_size: [](void *wa, cbindgen_private::IntSize size) {
148 reinterpret_cast<WindowAdapter *>(wa)->set_size(
149 slint::PhysicalSize({ .width: size.width, .height: size.height }));
150 },
151 update_window_properties: [](void *wa, const cbindgen_private::WindowProperties *p) {
152 reinterpret_cast<WindowAdapter *>(wa)->update_window_properties(
153 *reinterpret_cast<const WindowProperties *>(p));
154 },
155 position: [](void *wa, cbindgen_private::Point2D<int32_t> *point) -> bool {
156 if (auto pos = reinterpret_cast<WindowAdapter *>(wa)->position()) {
157 *point = *pos;
158 return true;
159 } else {
160 return false;
161 }
162 },
163 set_position: [](void *wa, cbindgen_private::Point2D<int32_t> point) {
164 reinterpret_cast<WindowAdapter *>(wa)->set_position(
165 slint::PhysicalPosition({ .x: point.x, .y: point.y }));
166 },
167 target: &self);
168 was_initialized = true;
169 return self;
170 }
171
172 friend inline void set_platform(std::unique_ptr<class Platform> platform);
173
174public:
175 /// Construct a WindowAdapter
176 explicit WindowAdapter() { }
177 virtual ~WindowAdapter() = default;
178
179 /// This function is called by Slint when the slint window is shown or hidden.
180 ///
181 /// Re-implement this function to forward the call to show/hide the native window
182 ///
183 /// When the window becomes visible, this is a good time to call
184 /// slint::Window::dispatch_scale_factor_change_event to initialise the scale factor.
185 virtual void set_visible(bool) { }
186
187 /// This function is called when Slint detects that the window need to be repainted.
188 ///
189 /// Reimplement this function to forward the call to the window manager.
190 ///
191 /// You should not render the window in the implementation of this call. Instead you should
192 /// do that in the next iteration of the event loop, or in a callback from the window manager.
193 virtual void request_redraw() { }
194
195 /// Request a new size for the window to the specified size on the screen, in physical or
196 /// logical pixels and excluding a window frame (if present).
197 ///
198 /// This is called from slint::Window::set_size().
199 ///
200 /// The default implementation does nothing
201 ///
202 /// This function should sent the size to the Windowing system. If the window size actually
203 /// changes, you should call slint::Window::dispatch_resize_event to propagate the new size
204 /// to the slint view.
205 virtual void set_size(slint::PhysicalSize) { }
206
207 /// Returns the actual physical size of the window
208 virtual slint::PhysicalSize size() = 0;
209
210 /// Sets the position of the window on the screen, in physical screen coordinates and including
211 /// a window frame (if present).
212 ///
213 /// The default implementation does nothing
214 ///
215 /// Called from slint::Window::set_position().
216 virtual void set_position(slint::PhysicalPosition) { }
217
218 /// Returns the position of the window on the screen, in physical screen coordinates and
219 /// including a window frame (if present).
220 ///
221 /// The default implementation returns std::nullopt.
222 ///
223 /// Called from slint::Window::position().
224 virtual std::optional<slint::PhysicalPosition> position() { return std::nullopt; }
225
226 /// This struct contains getters that provide access to properties of the Window
227 /// element, and is used with WindowAdapter::update_window_properties().
228 struct WindowProperties
229 {
230 /// Returns the title of the window.
231 SharedString title() const
232 {
233 SharedString out;
234 cbindgen_private::slint_window_properties_get_title(wp: inner(), out: &out);
235 return out;
236 }
237
238 /// Returns the background brush of the window.
239 Brush background() const
240 {
241 Brush out;
242 cbindgen_private::slint_window_properties_get_background(wp: inner(), out: &out);
243 return out;
244 }
245
246 /// \deprecated Use is_fullscreen() instead
247 [[deprecated("Renamed is_fullscreen()")]] bool fullscreen() const
248 {
249 return is_fullscreen();
250 }
251
252 /// Returns true if the window should be shown fullscreen; false otherwise.
253 bool is_fullscreen() const
254 {
255 return cbindgen_private::slint_window_properties_get_fullscreen(wp: inner());
256 }
257
258 /// Returns true if the window should be minimized; false otherwise
259 bool is_minimized() const
260 {
261 return cbindgen_private::slint_window_properties_get_minimized(wp: inner());
262 }
263
264 /// Returns true if the window should be maximized; false otherwise
265 bool is_maximized() const
266 {
267 return cbindgen_private::slint_window_properties_get_maximized(wp: inner());
268 }
269
270 /// This struct describes the layout constraints of a window.
271 ///
272 /// It is the return value of WindowProperties::layout_constraints().
273 struct LayoutConstraints
274 {
275 /// This represents the minimum size the window can be. If this is set, the window
276 /// should not be able to be resized smaller than this size. If it is left unset, there
277 /// is no minimum size.
278 std::optional<LogicalSize> min;
279 /// This represents the maximum size the window can be. If this is set, the window
280 /// should not be able to be resized larger than this size. If it is left unset, there
281 /// is no maximum size.
282 std::optional<LogicalSize> max;
283 /// This represents the preferred size of the window. This is the size the window
284 /// should have by default
285 LogicalSize preferred;
286 };
287
288 /// Returns the layout constraints of the window
289 LayoutConstraints layout_constraints() const
290 {
291 auto lc = cbindgen_private::slint_window_properties_get_layout_constraints(wp: inner());
292 return LayoutConstraints {
293 .min = lc.has_min ? std::optional(LogicalSize(lc.min)) : std::nullopt,
294 .max = lc.has_max ? std::optional(LogicalSize(lc.max)) : std::nullopt,
295 .preferred = LogicalSize(lc.preferred)
296 };
297 }
298
299 private:
300 /// This struct is opaque and cannot be constructed by C++
301 WindowProperties() = delete;
302 ~WindowProperties() = delete;
303 WindowProperties(const WindowProperties &) = delete;
304 WindowProperties &operator=(const WindowProperties &) = delete;
305 const cbindgen_private::WindowProperties *inner() const
306 {
307 return reinterpret_cast<const cbindgen_private::WindowProperties *>(this);
308 }
309 };
310
311 /// Re-implement this function to update the properties such as window title or layout
312 /// constraints.
313 ///
314 /// This function is called before `set_visible(true)`, and will be called again when the
315 /// properties that were queried on the last call are changed. If you do not query any
316 /// properties, it may not be called again.
317 virtual void update_window_properties(const WindowProperties &) { }
318
319 /// Re-implement this function to provide a reference to the renderer for use with the window
320 /// adapter.
321 ///
322 /// Your re-implementation should contain a renderer such as SoftwareRenderer or SkiaRenderer
323 /// and you must return a reference to it.
324 virtual AbstractRenderer &renderer() = 0;
325
326 /// Return the slint::Window associated with this window.
327 ///
328 /// Note that this function can only be called if the window was initialized, which is only
329 /// the case after it has been returned from a call to Platform::create_window_adapter
330 const Window &window() const
331 {
332 if (!was_initialized)
333 std::abort();
334 // This works because cbindgen_private::WindowAdapterRcOpaque and Window have the same
335 // layout
336 return *reinterpret_cast<const Window *>(&self);
337 }
338
339 /// Overload
340 Window &window()
341 {
342 if (!was_initialized)
343 std::abort();
344 // This works because cbindgen_private::WindowAdapterRcOpaque and Window have the same
345 // layout
346 return *reinterpret_cast<Window *>(&self);
347 }
348};
349
350/// The platform acts as a factory to create WindowAdapter instances.
351///
352/// Call slint::platform::set_platform() before creating any other Slint handles. Any subsequently
353/// created Slint windows will use the WindowAdapter provided by the create_window_adapter function.
354class Platform
355{
356public:
357 virtual ~Platform() = default;
358 Platform(const Platform &) = delete;
359 Platform &operator=(const Platform &) = delete;
360 Platform() = default;
361
362 /// Returns a new WindowAdapter
363 virtual std::unique_ptr<WindowAdapter> create_window_adapter() = 0;
364
365#if defined(SLINT_FEATURE_FREESTANDING) || defined(DOXYGEN)
366 /// Returns the amount of milliseconds since start of the application.
367 ///
368 /// This function should only be implemented if the runtime is compiled with
369 /// SLINT_FEATURE_FREESTANDING
370 virtual std::chrono::milliseconds duration_since_start() = 0;
371#endif
372
373 /// The type of clipboard used in Platform::clipboard_text and PLatform::set_clipboard_text.
374 enum class Clipboard {
375 /// This is the default clipboard used for text action for Ctrl+V, Ctrl+C.
376 /// Corresponds to the secondary selection on X11.
377 DefaultClipboard = static_cast<uint8_t>(cbindgen_private::Clipboard::DefaultClipboard),
378 /// This is the clipboard that is used when text is selected
379 /// Corresponds to the primary selection on X11.
380 /// The Platform implementation should do nothing if copy on select is not supported on that
381 /// platform.
382 SelectionClipboard = static_cast<uint8_t>(cbindgen_private::Clipboard::SelectionClipboard),
383 };
384
385 /// Sends the given text into the system clipboard.
386 ///
387 /// If the platform doesn't support the specified clipboard, this function should do nothing
388 virtual void set_clipboard_text(const SharedString &, Clipboard) { }
389
390 /// Returns a copy of text stored in the system clipboard, if any.
391 ///
392 /// If the platform doesn't support the specified clipboard, the function should return nullopt
393 virtual std::optional<SharedString> clipboard_text(Clipboard)
394 {
395 return {};
396 }
397
398 /// Spins an event loop and renders the visible windows.
399 virtual void run_event_loop() { }
400
401 /// Exits the event loop.
402 ///
403 /// This is what is called by slint::quit_event_loop() and can be called from a different thread
404 /// or re-enter from the event loop
405 virtual void quit_event_loop() { }
406
407 /// An task that is passed to the Platform::run_in_event_loop function and needs to be
408 /// run in the event loop and not in any other thread.
409 class Task
410 {
411 cbindgen_private::PlatformTaskOpaque inner { ._0: nullptr, ._1: nullptr };
412 friend inline void set_platform(std::unique_ptr<Platform> platform);
413 explicit Task(cbindgen_private::PlatformTaskOpaque inner) : inner(inner) { }
414
415 public:
416 ~Task()
417 {
418 if (inner._0) {
419 cbindgen_private::slint_platform_task_drop(
420 event: std::exchange(obj&: inner, new_val: { ._0: nullptr, ._1: nullptr }));
421 }
422 }
423 Task(const Task &) = delete;
424 Task &operator=(const Task &) = delete;
425 /// Move constructor. A moved from Task can no longer be run.
426 Task(Task &&other) : inner(other.inner) { other.inner = { ._0: nullptr, ._1: nullptr }; }
427 /// Move operator.
428 Task &operator=(Task &&other)
429 {
430 std::swap(a&: other.inner, b&: inner);
431 return *this;
432 }
433
434 /// Run the task.
435 ///
436 /// Can only be invoked once and should only be called from the event loop.
437 void run() &&
438 {
439 private_api::assert_main_thread();
440 assert(inner._0 && "calling invoke form a moved-from Task");
441 if (inner._0) {
442 cbindgen_private::slint_platform_task_run(
443 event: std::exchange(obj&: inner, new_val: { ._0: nullptr, ._1: nullptr }));
444 }
445 };
446 };
447
448 /// Run a task from the event loop.
449 ///
450 /// This function is called by slint::invoke_from_event_loop().
451 /// It can be called from any thread, but the passed function must only be called
452 /// from the event loop.
453 /// Reimplements this function and move the event to the event loop before calling
454 /// Task::run()
455 virtual void run_in_event_loop(Task) { }
456};
457
458/// Registers the platform with Slint. Must be called before Slint windows are created.
459/// Can only be called once in an application.
460inline void set_platform(std::unique_ptr<Platform> platform)
461{
462 cbindgen_private::slint_platform_register(
463 user_data: platform.release(), drop: [](void *p) { delete reinterpret_cast<const Platform *>(p); },
464 window_factory: [](void *p, cbindgen_private::WindowAdapterRcOpaque *out) {
465 auto w = reinterpret_cast<Platform *>(p)->create_window_adapter();
466 *out = w->initialize();
467 (void)w.release();
468 },
469 duration_since_start: []([[maybe_unused]] void *p) -> uint64_t {
470#ifndef SLINT_FEATURE_FREESTANDING
471 return 0;
472#else
473 return reinterpret_cast<Platform *>(p)->duration_since_start().count();
474#endif
475 },
476 set_clipboard_text: [](void *p, const SharedString *text, cbindgen_private::Clipboard clipboard) {
477 reinterpret_cast<Platform *>(p)->set_clipboard_text(
478 *text, static_cast<Platform::Clipboard>(clipboard));
479 },
480 clipboard_text: [](void *p, SharedString *out_text, cbindgen_private::Clipboard clipboard) -> bool {
481 auto maybe_clipboard = reinterpret_cast<Platform *>(p)->clipboard_text(
482 static_cast<Platform::Clipboard>(clipboard));
483
484 bool status = maybe_clipboard.has_value();
485 if (status)
486 *out_text = *maybe_clipboard;
487 return status;
488 },
489 run_event_loop: [](void *p) { return reinterpret_cast<Platform *>(p)->run_event_loop(); },
490 quit_event_loop: [](void *p) { return reinterpret_cast<Platform *>(p)->quit_event_loop(); },
491 invoke_from_event_loop: [](void *p, cbindgen_private::PlatformTaskOpaque event) {
492 return reinterpret_cast<Platform *>(p)->run_in_event_loop(Platform::Task(event));
493 });
494}
495
496#ifdef SLINT_FEATURE_RENDERER_SOFTWARE
497
498/// A 16bit pixel that has 5 red bits, 6 green bits and 5 blue bits
499struct Rgb565Pixel
500{
501 /// The blue component, encoded in 5 bits.
502 uint16_t b : 5;
503 /// The green component, encoded in 6 bits.
504 uint16_t g : 6;
505 /// The red component, encoded in 5 bits.
506 uint16_t r : 5;
507
508 /// Default constructor.
509 constexpr Rgb565Pixel() : b(0), g(0), r(0) { }
510
511 /// \brief Constructor that constructs from an Rgb8Pixel.
512 explicit constexpr Rgb565Pixel(const Rgb8Pixel &pixel)
513 : b(pixel.b >> 3), g(pixel.g >> 2), r(pixel.r >> 3)
514 {
515 }
516
517 /// \brief Get the red component as an 8-bit value.
518 ///
519 /// The bits are shifted so that the result is between 0 and 255.
520 /// \return The red component as an 8-bit value.
521 constexpr uint8_t red() const { return (r << 3) | (r >> 2); }
522
523 /// \brief Get the green component as an 8-bit value.
524 ///
525 /// The bits are shifted so that the result is between 0 and 255.
526 /// \return The green component as an 8-bit value.
527 constexpr uint8_t green() const { return (g << 2) | (g >> 4); }
528
529 /// \brief Get the blue component as an 8-bit value.
530 ///
531 /// The bits are shifted so that the result is between 0 and 255.
532 /// \return The blue component as an 8-bit value.
533 constexpr uint8_t blue() const { return (b << 3) | (b >> 2); }
534
535 /// \brief Convert to Rgb8Pixel.
536 constexpr operator Rgb8Pixel() const { return { .r: red(), .g: green(), .b: blue() }; }
537
538 /// Returns true if \a lhs \a rhs are pixels with identical colors.
539 friend bool operator==(const Rgb565Pixel &lhs, const Rgb565Pixel &rhs) = default;
540};
541
542/// Slint's software renderer.
543///
544/// To be used as a template parameter of the WindowAdapter.
545///
546/// Use the render() function to render in a buffer
547class SoftwareRenderer : public AbstractRenderer
548{
549 mutable cbindgen_private::SoftwareRendererOpaque inner;
550
551 /// \private
552 cbindgen_private::RendererPtr renderer_handle() const override
553 {
554 return cbindgen_private::slint_software_renderer_handle(r: inner);
555 }
556
557public:
558 /// Represents a region on the screen, used for partial rendering.
559 ///
560 /// The region may be composed of multiple sub-regions.
561 struct PhysicalRegion
562 {
563 /// Returns the size of the bounding box of this region.
564 PhysicalSize bounding_box_size() const
565 {
566 return PhysicalSize({ .width: uint32_t(inner.width), .height: uint32_t(inner.height) });
567 }
568 /// Returns the origin of the bounding box of this region.
569 PhysicalPosition bounding_box_origin() const
570 {
571 return PhysicalPosition({ .x: inner.x, .y: inner.y });
572 }
573
574 private:
575 cbindgen_private::types::IntRect inner;
576 friend class SoftwareRenderer;
577 PhysicalRegion(cbindgen_private::types::IntRect inner) : inner(inner) { }
578 };
579
580 /// This enum describes which parts of the buffer passed to the SoftwareRenderer may be
581 /// re-used to speed up painting.
582 enum class RepaintBufferType : uint32_t {
583 /// The full window is always redrawn. No attempt at partial rendering will be made.
584 NewBuffer = 0,
585 /// Only redraw the parts that have changed since the previous call to render().
586 ///
587 /// This variant assumes that the same buffer is passed on every call to render() and
588 /// that it still contains the previously rendered frame.
589 ReusedBuffer = 1,
590
591 /// Redraw the part that have changed since the last two frames were drawn.
592 ///
593 /// This is used when using double buffering and swapping of the buffers.
594 SwappedBuffers = 2,
595 };
596
597 virtual ~SoftwareRenderer() { cbindgen_private::slint_software_renderer_drop(r: inner); };
598 SoftwareRenderer(const SoftwareRenderer &) = delete;
599 SoftwareRenderer &operator=(const SoftwareRenderer &) = delete;
600 /// Constructs a new SoftwareRenderer with the \a buffer_type as strategy for handling the
601 /// differences between rendering buffers.
602 explicit SoftwareRenderer(RepaintBufferType buffer_type)
603 {
604 inner = cbindgen_private::slint_software_renderer_new(buffer_age: uint32_t(buffer_type));
605 }
606
607 /// Render the window scene into a pixel buffer
608 ///
609 /// The buffer must be at least as large as the associated slint::Window
610 ///
611 /// The stride is the amount of pixels between two lines in the buffer.
612 /// It is must be at least as large as the width of the window.
613 PhysicalRegion render(std::span<slint::Rgb8Pixel> buffer, std::size_t pixel_stride) const
614 {
615 auto r = cbindgen_private::slint_software_renderer_render_rgb8(r: inner, buffer: buffer.data(),
616 buffer_len: buffer.size(), pixel_stride);
617 return PhysicalRegion { r };
618 }
619
620 /// Render the window scene into an RGB 565 encoded pixel buffer
621 ///
622 /// The buffer must be at least as large as the associated slint::Window
623 ///
624 /// The stride is the amount of pixels between two lines in the buffer.
625 /// It is must be at least as large as the width of the window.
626 PhysicalRegion render(std::span<Rgb565Pixel> buffer, std::size_t pixel_stride) const
627 {
628 auto r = cbindgen_private::slint_software_renderer_render_rgb565(
629 r: inner, buffer: reinterpret_cast<uint16_t *>(buffer.data()), buffer_len: buffer.size(), pixel_stride);
630 return PhysicalRegion { r };
631 }
632
633# ifdef SLINT_FEATURE_EXPERIMENTAL
634 /// This enum describes the rotation that is applied to the buffer when rendering.
635 /// To be used in set_rendering_rotation()
636 enum class RenderingRotation {
637 /// No rotation
638 NoRotation = 0,
639 /// Rotate 90° to the left
640 Rotate90 = 90,
641 /// 180° rotation (upside-down)
642 Rotate180 = 180,
643 /// Rotate 90° to the right
644 Rotate270 = 270,
645 };
646
647 /// Set how the window need to be rotated in the buffer.
648 ///
649 /// This is typically used to implement screen rotation in software
650 void set_rendering_rotation(RenderingRotation rotation)
651 {
652 cbindgen_private::slint_software_renderer_set_rendering_rotation(
653 r: inner, rotation: static_cast<int>(rotation));
654 }
655# endif
656};
657#endif
658
659#ifdef SLINT_FEATURE_RENDERER_SKIA
660/// An opaque, low-level window handle that internalizes everything necessary to exchange messages
661/// with the windowing system. This includes the connection to the display server, if necessary.
662///
663/// Note that this class does not provide any kind of ownership. The caller is responsible for
664/// ensuring that the pointers supplied to the constructor are valid throughout the lifetime of the
665/// NativeWindowHandle.
666class NativeWindowHandle
667{
668 cbindgen_private::CppRawHandleOpaque inner;
669 friend class SkiaRenderer;
670
671 NativeWindowHandle(cbindgen_private::CppRawHandleOpaque inner) : inner(inner) { }
672
673public:
674 NativeWindowHandle() = delete;
675 NativeWindowHandle(const NativeWindowHandle &) = delete;
676 NativeWindowHandle &operator=(const NativeWindowHandle &) = delete;
677 /// Creates a new NativeWindowHandle by moving the handle data from \a other into this
678 /// NativeWindowHandle.
679 NativeWindowHandle(NativeWindowHandle &&other) { inner = std::exchange(obj&: other.inner, new_val: nullptr); }
680 /// Creates a new NativeWindowHandle by moving the handle data from \a other into this
681 /// NativeWindowHandle.
682 NativeWindowHandle &operator=(NativeWindowHandle &&other)
683 {
684 if (this == &other) {
685 return *this;
686 }
687 if (inner) {
688 cbindgen_private::slint_raw_window_handle_drop(handle: inner);
689 }
690 inner = std::exchange(obj&: other.inner, new_val: nullptr);
691 return *this;
692 }
693
694# if (!defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)) || defined(DOXYGEN)
695 /// Creates a new NativeWindowHandle from the given xcb_window_t \a window,
696 /// xcb_visualid_t \a visual_id, XCB \a connection, and \a screen number.
697 static NativeWindowHandle from_x11_xcb(uint32_t /*xcb_window_t*/ window,
698 uint32_t /*xcb_visualid_t*/ visual_id,
699 xcb_connection_t *connection, int screen)
700 {
701
702 return { cbindgen_private::slint_new_raw_window_handle_x11_xcb(window, visual_id,
703 connection, screen) };
704 }
705
706 /// Creates a new NativeWindowHandle from the given XLib \a window,
707 /// VisualID \a visual_id, Display \a display, and \a screen number.
708 static NativeWindowHandle from_x11_xlib(uint32_t /*Window*/ window,
709 unsigned long /*VisualID*/ visual_id,
710 void /*Display*/ *display, int screen)
711 {
712
713 return { cbindgen_private::slint_new_raw_window_handle_x11_xlib(window, visual_id, display,
714 screen) };
715 }
716
717 /// Creates a new NativeWindowHandle from the given wayland \a surface,
718 /// and \a display.
719 static NativeWindowHandle from_wayland(wl_surface *surface, wl_display *display)
720 {
721
722 return { cbindgen_private::slint_new_raw_window_handle_wayland(surface, display) };
723 }
724
725# endif
726# if (defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)) || defined(DOXYGEN)
727
728 /// Creates a new NativeWindowHandle from the given \a nsview, and \a nswindow.
729 static NativeWindowHandle from_appkit(NSView *nsview, NSWindow *nswindow)
730 {
731
732 return { cbindgen_private::slint_new_raw_window_handle_appkit(nsview, nswindow) };
733 }
734
735# endif
736# if (!defined(__APPLE__) && (defined(_WIN32) || !defined(_WIN64))) || defined(DOXYGEN)
737
738 /// Creates a new NativeWindowHandle from the given HWND \a hwnd, and HINSTANCE \a hinstance.
739 static NativeWindowHandle from_win32(void *hwnd, void *hinstance)
740 {
741 return { cbindgen_private::slint_new_raw_window_handle_win32(hwnd, hinstance) };
742 }
743# endif
744 /// Destroys the NativeWindowHandle.
745 ~NativeWindowHandle()
746 {
747 if (inner) {
748 cbindgen_private::slint_raw_window_handle_drop(handle: inner);
749 }
750 }
751};
752
753/// Slint's Skia renderer.
754///
755/// Create the renderer when you have created a native window with a non-zero size.
756/// Call the render() function to render the scene into the window.
757class SkiaRenderer : public AbstractRenderer
758{
759 mutable cbindgen_private::SkiaRendererOpaque inner;
760
761 /// \private
762 cbindgen_private::RendererPtr renderer_handle() const override
763 {
764 return cbindgen_private::slint_skia_renderer_handle(r: inner);
765 }
766
767public:
768 virtual ~SkiaRenderer() { cbindgen_private::slint_skia_renderer_drop(r: inner); }
769 SkiaRenderer(const SkiaRenderer &) = delete;
770 SkiaRenderer &operator=(const SkiaRenderer &) = delete;
771 /// Constructs a new Skia renderer for the given window - referenced by the provided
772 /// WindowHandle - and the specified initial size.
773 explicit SkiaRenderer(const NativeWindowHandle &window_handle, PhysicalSize initial_size)
774 {
775 inner = cbindgen_private::slint_skia_renderer_new(handle_opaque: window_handle.inner, size: initial_size);
776 }
777
778 /// Renders the scene into the window provided to the SkiaRenderer's constructor.
779 void render() const { cbindgen_private::slint_skia_renderer_render(r: inner); }
780};
781#endif
782
783/// Call this function at each iteration of the event loop to call the timer handler and advance
784/// the animations. This should be called before the rendering or processing input events
785inline void update_timers_and_animations()
786{
787 cbindgen_private::slint_platform_update_timers_and_animations();
788}
789
790/// Returns the duration until the next timer if there are pending timers
791inline std::optional<std::chrono::milliseconds> duration_until_next_timer_update()
792{
793 uint64_t val = cbindgen_private::slint_platform_duration_until_next_timer_update();
794 if (val == std::numeric_limits<uint64_t>::max()) {
795 return std::nullopt;
796 } else if (val >= uint64_t(std::chrono::milliseconds::max().count())) {
797 return std::chrono::milliseconds::max();
798 } else {
799 return std::chrono::milliseconds(val);
800 }
801}
802}
803}
804

source code of slint/api/cpp/include/slint-platform.h