| 1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
| 2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 |
| 3 | |
| 4 | #pragma once |
| 5 | |
| 6 | #include "slint_internal.h" |
| 7 | |
| 8 | #ifndef SLINT_FEATURE_FREESTANDING |
| 9 | # include <thread> |
| 10 | # include <iostream> |
| 11 | #endif |
| 12 | |
| 13 | namespace slint { |
| 14 | #if !defined(DOXYGEN) |
| 15 | namespace platform { |
| 16 | class SkiaRenderer; |
| 17 | class SoftwareRenderer; |
| 18 | } |
| 19 | #endif |
| 20 | |
| 21 | namespace private_api { |
| 22 | /// Internal function that checks that the API that must be called from the main |
| 23 | /// thread is indeed called from the main thread, or abort the program otherwise |
| 24 | /// |
| 25 | /// Most API should be called from the main thread. When using thread one must |
| 26 | /// use slint::invoke_from_event_loop |
| 27 | inline void assert_main_thread() |
| 28 | { |
| 29 | #ifndef SLINT_FEATURE_FREESTANDING |
| 30 | # ifndef NDEBUG |
| 31 | static auto main_thread_id = std::this_thread::get_id(); |
| 32 | if (main_thread_id != std::this_thread::get_id()) { |
| 33 | std::cerr << "A function that should be only called from the main thread was called from a " |
| 34 | "thread." |
| 35 | << std::endl; |
| 36 | std::cerr << "Most API should be called from the main thread. When using thread one must " |
| 37 | "use slint::invoke_from_event_loop." |
| 38 | << std::endl; |
| 39 | std::abort(); |
| 40 | } |
| 41 | # endif |
| 42 | #endif |
| 43 | } |
| 44 | |
| 45 | using ItemTreeRc = vtable::VRc<cbindgen_private::ItemTreeVTable>; |
| 46 | using slint::LogicalPosition; |
| 47 | |
| 48 | class WindowAdapterRc |
| 49 | { |
| 50 | public: |
| 51 | explicit WindowAdapterRc(cbindgen_private::WindowAdapterRcOpaque adopted_inner) |
| 52 | { |
| 53 | assert_main_thread(); |
| 54 | cbindgen_private::slint_windowrc_clone(source: &adopted_inner, target: &inner); |
| 55 | } |
| 56 | WindowAdapterRc() { cbindgen_private::slint_windowrc_init(out: &inner); } |
| 57 | ~WindowAdapterRc() { cbindgen_private::slint_windowrc_drop(handle: &inner); } |
| 58 | WindowAdapterRc(const WindowAdapterRc &other) : WindowAdapterRc(other.inner) { } |
| 59 | WindowAdapterRc(WindowAdapterRc &&) = delete; |
| 60 | WindowAdapterRc &operator=(WindowAdapterRc &&) = delete; |
| 61 | WindowAdapterRc &operator=(const WindowAdapterRc &other) |
| 62 | { |
| 63 | assert_main_thread(); |
| 64 | if (this != &other) { |
| 65 | cbindgen_private::slint_windowrc_drop(handle: &inner); |
| 66 | cbindgen_private::slint_windowrc_clone(source: &other.inner, target: &inner); |
| 67 | } |
| 68 | return *this; |
| 69 | } |
| 70 | |
| 71 | void show() const { slint_windowrc_show(handle: &inner); } |
| 72 | void hide() const { slint_windowrc_hide(handle: &inner); } |
| 73 | bool is_visible() const { return slint_windowrc_is_visible(handle: &inner); } |
| 74 | |
| 75 | float scale_factor() const { return slint_windowrc_get_scale_factor(handle: &inner); } |
| 76 | void set_scale_factor(float value) const { slint_windowrc_set_scale_factor(handle: &inner, value); } |
| 77 | |
| 78 | cbindgen_private::ColorScheme color_scheme() const |
| 79 | { |
| 80 | return slint_windowrc_color_scheme(&inner); |
| 81 | } |
| 82 | bool () const |
| 83 | { |
| 84 | return slint_windowrc_supports_native_menu_bar(&inner); |
| 85 | } |
| 86 | |
| 87 | template<typename Component, typename SubMenu, typename Activated> |
| 88 | void (Component component, SubMenu , Activated activated) const |
| 89 | { |
| 90 | if (!supports_native_menu_bar()) { |
| 91 | return; |
| 92 | } |
| 93 | struct |
| 94 | { |
| 95 | Component component; |
| 96 | SubMenu ; |
| 97 | Activated activated; |
| 98 | }; |
| 99 | static cbindgen_private::MenuVTable = { |
| 100 | .drop = [](auto data) { delete reinterpret_cast<MenuWrapper *>(data.instance); }, |
| 101 | .sub_menu = |
| 102 | [](auto data, const cbindgen_private::MenuEntry *entry, |
| 103 | slint::SharedVector<cbindgen_private::MenuEntry> *result) { |
| 104 | auto wrapper = reinterpret_cast<MenuWrapper *>(data.instance); |
| 105 | auto model = wrapper->submenu(wrapper->component, entry); |
| 106 | result->clear(); |
| 107 | if (model) { |
| 108 | auto count = model->row_count(); |
| 109 | for (size_t i = 0; i < count; ++i) { |
| 110 | result->push_back(*model->row_data(i)); |
| 111 | } |
| 112 | } |
| 113 | }, |
| 114 | .activate = |
| 115 | [](auto data, const cbindgen_private::MenuEntry *entry) { |
| 116 | auto wrapper = reinterpret_cast<MenuWrapper *>(data.instance); |
| 117 | wrapper->activated(wrapper->component, *entry); |
| 118 | }, |
| 119 | }; |
| 120 | auto instance = new MenuWrapper { component, std::move(submenu), std::move(activated) }; |
| 121 | cbindgen_private::slint_windowrc_setup_native_menu_bar(&inner, &menu_vtable, instance); |
| 122 | } |
| 123 | |
| 124 | bool text_input_focused() const { return slint_windowrc_get_text_input_focused(handle: &inner); } |
| 125 | void set_text_input_focused(bool value) const |
| 126 | { |
| 127 | slint_windowrc_set_text_input_focused(handle: &inner, value); |
| 128 | } |
| 129 | |
| 130 | template<typename Component, typename ItemArray> |
| 131 | void unregister_item_tree(Component *c, ItemArray items) const |
| 132 | { |
| 133 | cbindgen_private::slint_unregister_item_tree( |
| 134 | component: vtable::VRef<cbindgen_private::ItemTreeVTable> { &Component::static_vtable, c }, |
| 135 | item_array: items, window_handle: &inner); |
| 136 | } |
| 137 | |
| 138 | void set_focus_item(const ItemTreeRc &component_rc, uint32_t item_index, bool set_focus) |
| 139 | { |
| 140 | cbindgen_private::ItemRc item_rc { .item_tree: component_rc, .index: item_index }; |
| 141 | cbindgen_private::slint_windowrc_set_focus_item(&inner, &item_rc, set_focus); |
| 142 | } |
| 143 | |
| 144 | void set_component(const cbindgen_private::ItemTreeWeak &weak) const |
| 145 | { |
| 146 | auto item_tree_rc = (*weak.lock()).into_dyn(); |
| 147 | slint_windowrc_set_component(handle: &inner, component: &item_tree_rc); |
| 148 | } |
| 149 | |
| 150 | template<typename Component, typename Parent, typename PosGetter> |
| 151 | uint32_t (const Parent *parent_component, PosGetter pos, |
| 152 | cbindgen_private::PopupClosePolicy close_policy, |
| 153 | cbindgen_private::ItemRc parent_item) const |
| 154 | { |
| 155 | auto = Component::create(parent_component); |
| 156 | auto p = pos(popup); |
| 157 | auto = popup.into_dyn(); |
| 158 | auto id = cbindgen_private::slint_windowrc_show_popup(handle: &inner, popup: &popup_dyn, position: p, close_on_click: close_policy, |
| 159 | parent_item: &parent_item, false); |
| 160 | popup->user_init(); |
| 161 | return id; |
| 162 | } |
| 163 | |
| 164 | void (uint32_t ) const |
| 165 | { |
| 166 | if (popup_id > 0) { |
| 167 | cbindgen_private::slint_windowrc_close_popup(&inner, popup_id); |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | template<typename Component, typename SharedGlobals, typename InitFn> |
| 172 | uint32_t (SharedGlobals *globals, LogicalPosition pos, |
| 173 | cbindgen_private::ItemRc , InitFn init) const |
| 174 | { |
| 175 | // if (cbindgen_private::slint_windowrc_show_native_context_menu(....)) { return } |
| 176 | |
| 177 | auto = Component::create(globals); |
| 178 | init(&*popup); |
| 179 | auto = popup.into_dyn(); |
| 180 | auto id = cbindgen_private::slint_windowrc_show_popup( |
| 181 | &inner, &popup_dyn, pos, cbindgen_private::PopupClosePolicy::CloseOnClickOutside, |
| 182 | &context_menu_rc, true); |
| 183 | popup->user_init(); |
| 184 | return id; |
| 185 | } |
| 186 | |
| 187 | template<std::invocable<RenderingState, GraphicsAPI> F> |
| 188 | std::optional<SetRenderingNotifierError> set_rendering_notifier(F callback) const |
| 189 | { |
| 190 | auto actual_cb = [](RenderingState state, GraphicsAPI graphics_api, void *data) { |
| 191 | (*reinterpret_cast<F *>(data))(state, graphics_api); |
| 192 | }; |
| 193 | SetRenderingNotifierError err; |
| 194 | if (cbindgen_private::slint_windowrc_set_rendering_notifier( |
| 195 | handle: &inner, callback: actual_cb, |
| 196 | drop_user_data: [](void *user_data) { delete reinterpret_cast<F *>(user_data); }, |
| 197 | user_data: new F(std::move(callback)), error: &err)) { |
| 198 | return {}; |
| 199 | } else { |
| 200 | return err; |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | // clang-format off |
| 205 | template<std::invocable F> |
| 206 | requires(std::is_convertible_v<std::invoke_result_t<F>, CloseRequestResponse>) |
| 207 | void on_close_requested(F callback) const |
| 208 | // clang-format on |
| 209 | { |
| 210 | auto actual_cb = [](void *data) { return (*reinterpret_cast<F *>(data))(); }; |
| 211 | cbindgen_private::slint_windowrc_on_close_requested( |
| 212 | handle: &inner, callback: actual_cb, drop_user_data: [](void *user_data) { delete reinterpret_cast<F *>(user_data); }, |
| 213 | user_data: new F(std::move(callback))); |
| 214 | } |
| 215 | |
| 216 | void request_redraw() const { cbindgen_private::slint_windowrc_request_redraw(handle: &inner); } |
| 217 | |
| 218 | slint::PhysicalPosition position() const |
| 219 | { |
| 220 | slint::PhysicalPosition pos; |
| 221 | cbindgen_private::slint_windowrc_position(handle: &inner, pos: &pos); |
| 222 | return pos; |
| 223 | } |
| 224 | |
| 225 | void set_logical_position(const slint::LogicalPosition &pos) |
| 226 | { |
| 227 | cbindgen_private::slint_windowrc_set_logical_position(handle: &inner, pos: &pos); |
| 228 | } |
| 229 | |
| 230 | void set_physical_position(const slint::PhysicalPosition &pos) |
| 231 | { |
| 232 | cbindgen_private::slint_windowrc_set_physical_position(handle: &inner, pos: &pos); |
| 233 | } |
| 234 | |
| 235 | slint::PhysicalSize size() const |
| 236 | { |
| 237 | return slint::PhysicalSize(cbindgen_private::slint_windowrc_size(handle: &inner)); |
| 238 | } |
| 239 | |
| 240 | void set_logical_size(const slint::LogicalSize &size) |
| 241 | { |
| 242 | cbindgen_private::slint_windowrc_set_logical_size(handle: &inner, size: &size); |
| 243 | } |
| 244 | |
| 245 | void set_physical_size(const slint::PhysicalSize &size) |
| 246 | { |
| 247 | cbindgen_private::slint_windowrc_set_physical_size(handle: &inner, size: &size); |
| 248 | } |
| 249 | |
| 250 | /// Send a pointer event to this window |
| 251 | void dispatch_pointer_event(const cbindgen_private::MouseEvent &event) |
| 252 | { |
| 253 | private_api::assert_main_thread(); |
| 254 | cbindgen_private::slint_windowrc_dispatch_pointer_event(handle: &inner, event); |
| 255 | } |
| 256 | |
| 257 | /// Registers a font by the specified path. The path must refer to an existing |
| 258 | /// TrueType font. |
| 259 | /// \returns an empty optional on success, otherwise an error string |
| 260 | inline std::optional<SharedString> register_font_from_path(const SharedString &path) |
| 261 | { |
| 262 | SharedString maybe_err; |
| 263 | cbindgen_private::slint_register_font_from_path(win: &inner, path: &path, error_str: &maybe_err); |
| 264 | if (!maybe_err.empty()) { |
| 265 | return maybe_err; |
| 266 | } else { |
| 267 | return {}; |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | /// Registers a font by the data. The data must be valid TrueType font data. |
| 272 | /// \returns an empty optional on success, otherwise an error string |
| 273 | inline std::optional<SharedString> register_font_from_data(const uint8_t *data, std::size_t len) |
| 274 | { |
| 275 | SharedString maybe_err; |
| 276 | cbindgen_private::slint_register_font_from_data( |
| 277 | win: &inner, data: { const_cast<uint8_t *>(data), len }, error_str: &maybe_err); |
| 278 | if (!maybe_err.empty()) { |
| 279 | return maybe_err; |
| 280 | } else { |
| 281 | return {}; |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | /// Registers a bitmap font for use with the software renderer. |
| 286 | inline void register_bitmap_font(const cbindgen_private::BitmapFont &font) |
| 287 | { |
| 288 | cbindgen_private::slint_register_bitmap_font(win: &inner, font_data: &font); |
| 289 | } |
| 290 | |
| 291 | inline float default_font_size() const |
| 292 | { |
| 293 | return cbindgen_private::slint_windowrc_default_font_size(&inner); |
| 294 | } |
| 295 | |
| 296 | /// \private |
| 297 | const cbindgen_private::WindowAdapterRcOpaque &handle() const { return inner; } |
| 298 | |
| 299 | private: |
| 300 | friend class slint::platform::SkiaRenderer; |
| 301 | friend class slint::platform::SoftwareRenderer; |
| 302 | cbindgen_private::WindowAdapterRcOpaque inner; |
| 303 | }; |
| 304 | |
| 305 | } |
| 306 | |
| 307 | /// This class represents a window towards the windowing system, that's used to render the |
| 308 | /// scene of a component. It provides API to control windowing system specific aspects such |
| 309 | /// as the position on the screen. |
| 310 | class Window |
| 311 | { |
| 312 | public: |
| 313 | /// \private |
| 314 | /// Internal function used by the generated code to construct a new instance of this |
| 315 | /// public API wrapper. |
| 316 | explicit Window(const private_api::WindowAdapterRc &windowrc) : inner(windowrc) { } |
| 317 | Window(const Window &other) = delete; |
| 318 | Window &operator=(const Window &other) = delete; |
| 319 | Window(Window &&other) = delete; |
| 320 | Window &operator=(Window &&other) = delete; |
| 321 | /// Destroys this window. Window instances are explicitly shared and reference counted. |
| 322 | /// If this window instance is the last one referencing the window towards the windowing |
| 323 | /// system, then it will also become hidden and destroyed. |
| 324 | ~Window() = default; |
| 325 | |
| 326 | /// Shows the window on the screen. An additional strong reference on the |
| 327 | /// associated component is maintained while the window is visible. |
| 328 | /// |
| 329 | /// Call hide() to make the window invisible again, and drop the additional |
| 330 | /// strong reference. |
| 331 | void show() |
| 332 | { |
| 333 | private_api::assert_main_thread(); |
| 334 | inner.show(); |
| 335 | } |
| 336 | /// Hides the window, so that it is not visible anymore. The additional strong |
| 337 | /// reference on the associated component, that was created when show() was called, is |
| 338 | /// dropped. |
| 339 | void hide() |
| 340 | { |
| 341 | private_api::assert_main_thread(); |
| 342 | inner.hide(); |
| 343 | } |
| 344 | |
| 345 | /// Returns the visibility state of the window. This function can return false even if you |
| 346 | /// previously called show() on it, for example if the user minimized the window. |
| 347 | bool is_visible() const |
| 348 | { |
| 349 | private_api::assert_main_thread(); |
| 350 | return inner.is_visible(); |
| 351 | } |
| 352 | |
| 353 | /// This function allows registering a callback that's invoked during the different phases of |
| 354 | /// rendering. This allows custom rendering on top or below of the scene. |
| 355 | /// |
| 356 | /// The provided callback must be callable with a slint::RenderingState and the |
| 357 | /// slint::GraphicsAPI argument. |
| 358 | /// |
| 359 | /// On success, the function returns a std::optional without value. On error, the function |
| 360 | /// returns the error code as value in the std::optional. |
| 361 | template<std::invocable<RenderingState, GraphicsAPI> F> |
| 362 | std::optional<SetRenderingNotifierError> set_rendering_notifier(F &&callback) const |
| 363 | { |
| 364 | private_api::assert_main_thread(); |
| 365 | return inner.set_rendering_notifier(std::forward<F>(callback)); |
| 366 | } |
| 367 | |
| 368 | /// This function allows registering a callback that's invoked when the user tries to close |
| 369 | /// a window. |
| 370 | /// The callback has to return a CloseRequestResponse. |
| 371 | // clang-format off |
| 372 | template<std::invocable F> |
| 373 | requires(std::is_convertible_v<std::invoke_result_t<F>, CloseRequestResponse>) |
| 374 | void on_close_requested(F &&callback) const |
| 375 | // clang-format on |
| 376 | { |
| 377 | private_api::assert_main_thread(); |
| 378 | return inner.on_close_requested(std::forward<F>(callback)); |
| 379 | } |
| 380 | |
| 381 | /// This function issues a request to the windowing system to redraw the contents of the window. |
| 382 | void request_redraw() const |
| 383 | { |
| 384 | private_api::assert_main_thread(); |
| 385 | inner.request_redraw(); |
| 386 | } |
| 387 | |
| 388 | /// Returns the position of the window on the screen, in physical screen coordinates and |
| 389 | /// including a window frame (if present). |
| 390 | slint::PhysicalPosition position() const |
| 391 | { |
| 392 | private_api::assert_main_thread(); |
| 393 | return inner.position(); |
| 394 | } |
| 395 | |
| 396 | /// Sets the position of the window on the screen, in physical screen coordinates and including |
| 397 | /// a window frame (if present). |
| 398 | /// Note that on some windowing systems, such as Wayland, this functionality is not available. |
| 399 | void set_position(const slint::LogicalPosition &pos) |
| 400 | { |
| 401 | private_api::assert_main_thread(); |
| 402 | inner.set_logical_position(pos); |
| 403 | } |
| 404 | /// Sets the position of the window on the screen, in physical screen coordinates and including |
| 405 | /// a window frame (if present). |
| 406 | /// Note that on some windowing systems, such as Wayland, this functionality is not available. |
| 407 | void set_position(const slint::PhysicalPosition &pos) |
| 408 | { |
| 409 | private_api::assert_main_thread(); |
| 410 | inner.set_physical_position(pos); |
| 411 | } |
| 412 | |
| 413 | /// Returns the size of the window on the screen, in physical screen coordinates and excluding |
| 414 | /// a window frame (if present). |
| 415 | slint::PhysicalSize size() const |
| 416 | { |
| 417 | private_api::assert_main_thread(); |
| 418 | return inner.size(); |
| 419 | } |
| 420 | |
| 421 | /// Resizes the window to the specified size on the screen, in logical pixels and excluding |
| 422 | /// a window frame (if present). |
| 423 | void set_size(const slint::LogicalSize &size) |
| 424 | { |
| 425 | private_api::assert_main_thread(); |
| 426 | inner.set_logical_size(size); |
| 427 | } |
| 428 | /// Resizes the window to the specified size on the screen, in physical pixels and excluding |
| 429 | /// a window frame (if present). |
| 430 | void set_size(const slint::PhysicalSize &size) |
| 431 | { |
| 432 | private_api::assert_main_thread(); |
| 433 | inner.set_physical_size(size); |
| 434 | } |
| 435 | |
| 436 | /// This function returns the scale factor that allows converting between logical and |
| 437 | /// physical pixels. |
| 438 | float scale_factor() const |
| 439 | { |
| 440 | private_api::assert_main_thread(); |
| 441 | return inner.scale_factor(); |
| 442 | } |
| 443 | |
| 444 | /// Returns if the window is currently fullscreen |
| 445 | bool is_fullscreen() const |
| 446 | { |
| 447 | private_api::assert_main_thread(); |
| 448 | return cbindgen_private::slint_windowrc_is_fullscreen(handle: &inner.handle()); |
| 449 | } |
| 450 | /// Set or unset the window to display fullscreen. |
| 451 | void set_fullscreen(bool fullscreen) |
| 452 | { |
| 453 | private_api::assert_main_thread(); |
| 454 | cbindgen_private::slint_windowrc_set_fullscreen(handle: &inner.handle(), value: fullscreen); |
| 455 | } |
| 456 | |
| 457 | /// Returns if the window is currently maximized |
| 458 | bool is_maximized() const |
| 459 | { |
| 460 | private_api::assert_main_thread(); |
| 461 | return cbindgen_private::slint_windowrc_is_maximized(handle: &inner.handle()); |
| 462 | } |
| 463 | /// Maximize or unmaximize the window. |
| 464 | void set_maximized(bool maximized) |
| 465 | { |
| 466 | private_api::assert_main_thread(); |
| 467 | cbindgen_private::slint_windowrc_set_maximized(handle: &inner.handle(), value: maximized); |
| 468 | } |
| 469 | |
| 470 | /// Returns if the window is currently minimized |
| 471 | bool is_minimized() const |
| 472 | { |
| 473 | private_api::assert_main_thread(); |
| 474 | return cbindgen_private::slint_windowrc_is_minimized(handle: &inner.handle()); |
| 475 | } |
| 476 | /// Minimize or unminimze the window. |
| 477 | void set_minimized(bool minimized) |
| 478 | { |
| 479 | private_api::assert_main_thread(); |
| 480 | cbindgen_private::slint_windowrc_set_minimized(handle: &inner.handle(), value: minimized); |
| 481 | } |
| 482 | |
| 483 | /// Dispatch a key press event to the scene. |
| 484 | /// |
| 485 | /// Use this when you're implementing your own backend and want to forward user input events. |
| 486 | /// |
| 487 | /// The \a text is the unicode representation of the key. |
| 488 | void dispatch_key_press_event(const SharedString &text) |
| 489 | { |
| 490 | private_api::assert_main_thread(); |
| 491 | cbindgen_private::slint_windowrc_dispatch_key_event( |
| 492 | handle: &inner.handle(), event_type: cbindgen_private::KeyEventType::KeyPressed, text: &text, repeat: false); |
| 493 | } |
| 494 | |
| 495 | /// Dispatch an auto-repeated key press event to the scene. |
| 496 | /// |
| 497 | /// Use this when you're implementing your own backend and want to forward user input events. |
| 498 | /// |
| 499 | /// The \a text is the unicode representation of the key. |
| 500 | void dispatch_key_press_repeat_event(const SharedString &text) |
| 501 | { |
| 502 | private_api::assert_main_thread(); |
| 503 | cbindgen_private::slint_windowrc_dispatch_key_event( |
| 504 | handle: &inner.handle(), event_type: cbindgen_private::KeyEventType::KeyPressed, text: &text, repeat: true); |
| 505 | } |
| 506 | |
| 507 | /// Dispatch a key release event to the scene. |
| 508 | /// |
| 509 | /// Use this when you're implementing your own backend and want to forward user input events. |
| 510 | /// |
| 511 | /// The \a text is the unicode representation of the key. |
| 512 | void dispatch_key_release_event(const SharedString &text) |
| 513 | { |
| 514 | private_api::assert_main_thread(); |
| 515 | cbindgen_private::slint_windowrc_dispatch_key_event( |
| 516 | handle: &inner.handle(), event_type: cbindgen_private::KeyEventType::KeyReleased, text: &text, repeat: false); |
| 517 | } |
| 518 | |
| 519 | /// Dispatches a pointer or mouse press event to the scene. |
| 520 | /// |
| 521 | /// Use this function when you're implementing your own backend and want to forward user |
| 522 | /// pointer/mouse events. |
| 523 | /// |
| 524 | /// \a pos represents the logical position of the pointer relative to the window. |
| 525 | /// \a button is the button that was pressed. |
| 526 | void dispatch_pointer_press_event(LogicalPosition pos, PointerEventButton button) |
| 527 | { |
| 528 | private_api::assert_main_thread(); |
| 529 | using slint::cbindgen_private::MouseEvent; |
| 530 | MouseEvent event { .tag = MouseEvent::Tag::Pressed, |
| 531 | .pressed = MouseEvent::Pressed_Body { .position = { .x: pos.x, .y: pos.y }, |
| 532 | .button = button, |
| 533 | .click_count = 0 } }; |
| 534 | inner.dispatch_pointer_event(event); |
| 535 | } |
| 536 | /// Dispatches a pointer or mouse release event to the scene. |
| 537 | /// |
| 538 | /// Use this function when you're implementing your own backend and want to forward user |
| 539 | /// pointer/mouse events. |
| 540 | /// |
| 541 | /// \a pos represents the logical position of the pointer relative to the window. |
| 542 | /// \a button is the button that was released. |
| 543 | void dispatch_pointer_release_event(LogicalPosition pos, PointerEventButton button) |
| 544 | { |
| 545 | private_api::assert_main_thread(); |
| 546 | using slint::cbindgen_private::MouseEvent; |
| 547 | MouseEvent event { .tag = MouseEvent::Tag::Released, |
| 548 | .released = MouseEvent::Released_Body { .position = { .x: pos.x, .y: pos.y }, |
| 549 | .button = button, |
| 550 | .click_count = 0 } }; |
| 551 | inner.dispatch_pointer_event(event); |
| 552 | } |
| 553 | /// Dispatches a pointer exit event to the scene. |
| 554 | /// |
| 555 | /// Use this function when you're implementing your own backend and want to forward user |
| 556 | /// pointer/mouse events. |
| 557 | /// |
| 558 | /// This event is triggered when the pointer exits the window. |
| 559 | void dispatch_pointer_exit_event() |
| 560 | { |
| 561 | private_api::assert_main_thread(); |
| 562 | using slint::cbindgen_private::MouseEvent; |
| 563 | MouseEvent event { .tag = MouseEvent::Tag::Exit, .moved = {} }; |
| 564 | inner.dispatch_pointer_event(event); |
| 565 | } |
| 566 | |
| 567 | /// Dispatches a pointer move event to the scene. |
| 568 | /// |
| 569 | /// Use this function when you're implementing your own backend and want to forward user |
| 570 | /// pointer/mouse events. |
| 571 | /// |
| 572 | /// \a pos represents the logical position of the pointer relative to the window. |
| 573 | void dispatch_pointer_move_event(LogicalPosition pos) |
| 574 | { |
| 575 | private_api::assert_main_thread(); |
| 576 | using slint::cbindgen_private::MouseEvent; |
| 577 | MouseEvent event { .tag = MouseEvent::Tag::Moved, |
| 578 | .moved = MouseEvent::Moved_Body { .position = { .x: pos.x, .y: pos.y } } }; |
| 579 | inner.dispatch_pointer_event(event); |
| 580 | } |
| 581 | |
| 582 | /// Dispatches a scroll (or wheel) event to the scene. |
| 583 | /// |
| 584 | /// Use this function when you're implementing your own backend and want to forward user wheel |
| 585 | /// events. |
| 586 | /// |
| 587 | /// \a parameter represents the logical position of the pointer relative to the window. |
| 588 | /// \a delta_x and \a delta_y represent the scroll delta values in the X and Y |
| 589 | /// directions in logical pixels. |
| 590 | void dispatch_pointer_scroll_event(LogicalPosition pos, float delta_x, float delta_y) |
| 591 | { |
| 592 | private_api::assert_main_thread(); |
| 593 | using slint::cbindgen_private::MouseEvent; |
| 594 | MouseEvent event { .tag = MouseEvent::Tag::Wheel, |
| 595 | .wheel = MouseEvent::Wheel_Body { .position = { .x: pos.x, .y: pos.y }, |
| 596 | .delta_x = delta_x, |
| 597 | .delta_y = delta_y } }; |
| 598 | inner.dispatch_pointer_event(event); |
| 599 | } |
| 600 | |
| 601 | /// Set the logical size of this window after a resize event |
| 602 | /// |
| 603 | /// The backend must send this event to ensure that the `width` and `height` property of the |
| 604 | /// root Window element are properly set. |
| 605 | void dispatch_resize_event(slint::LogicalSize s) |
| 606 | { |
| 607 | private_api::assert_main_thread(); |
| 608 | using slint::cbindgen_private::WindowEvent; |
| 609 | WindowEvent event { .resized = |
| 610 | WindowEvent::Resized_Body { .tag = WindowEvent::Tag::Resized, |
| 611 | .size = { .width: s.width, .height: s.height } } }; |
| 612 | cbindgen_private::slint_windowrc_dispatch_event(handle: &inner.handle(), event: &event); |
| 613 | } |
| 614 | |
| 615 | /// The window's scale factor has changed. This can happen for example when the display's |
| 616 | /// resolution changes, the user selects a new scale factor in the system settings, or the |
| 617 | /// window is moved to a different screen. Platform implementations should dispatch this event |
| 618 | /// also right after the initial window creation, to set the initial scale factor the windowing |
| 619 | /// system provided for the window. |
| 620 | void dispatch_scale_factor_change_event(float factor) |
| 621 | { |
| 622 | private_api::assert_main_thread(); |
| 623 | using slint::cbindgen_private::WindowEvent; |
| 624 | WindowEvent event { .scale_factor_changed = WindowEvent::ScaleFactorChanged_Body { |
| 625 | .tag = WindowEvent::Tag::ScaleFactorChanged, |
| 626 | .scale_factor = factor } }; |
| 627 | cbindgen_private::slint_windowrc_dispatch_event(handle: &inner.handle(), event: &event); |
| 628 | } |
| 629 | |
| 630 | /// The Window was activated or de-activated. |
| 631 | /// |
| 632 | /// The backend should dispatch this event with true when the window gains focus |
| 633 | /// and false when the window loses focus. |
| 634 | void dispatch_window_active_changed_event(bool active) |
| 635 | { |
| 636 | private_api::assert_main_thread(); |
| 637 | using slint::cbindgen_private::WindowEvent; |
| 638 | WindowEvent event { .window_active_changed = WindowEvent::WindowActiveChanged_Body { |
| 639 | .tag = WindowEvent::Tag::WindowActiveChanged, ._0 = active } }; |
| 640 | cbindgen_private::slint_windowrc_dispatch_event(handle: &inner.handle(), event: &event); |
| 641 | } |
| 642 | |
| 643 | /// The user requested to close the window. |
| 644 | /// |
| 645 | /// The backend should send this event when the user tries to close the window,for example by |
| 646 | /// pressing the close button. |
| 647 | /// |
| 648 | /// This will have the effect of invoking the callback set in Window::on_close_requested() and |
| 649 | /// then hiding the window depending on the return value of the callback. |
| 650 | void dispatch_close_requested_event() |
| 651 | { |
| 652 | private_api::assert_main_thread(); |
| 653 | using slint::cbindgen_private::WindowEvent; |
| 654 | WindowEvent event { .tag = WindowEvent::Tag::CloseRequested }; |
| 655 | cbindgen_private::slint_windowrc_dispatch_event(handle: &inner.handle(), event: &event); |
| 656 | } |
| 657 | |
| 658 | /// Returns true if there is an animation currently active on any property in the Window. |
| 659 | bool has_active_animations() const |
| 660 | { |
| 661 | private_api::assert_main_thread(); |
| 662 | return cbindgen_private::slint_windowrc_has_active_animations(handle: &inner.handle()); |
| 663 | } |
| 664 | |
| 665 | /// Takes a snapshot of the window contents and returns it as RGBA8 encoded pixel buffer. |
| 666 | /// |
| 667 | /// Note that this function may be slow to call as it may need to re-render the scene. |
| 668 | std::optional<SharedPixelBuffer<Rgba8Pixel>> take_snapshot() const |
| 669 | { |
| 670 | SharedPixelBuffer<Rgba8Pixel> result; |
| 671 | if (cbindgen_private::slint_windowrc_take_snapshot(&inner.handle(), &result.m_data, |
| 672 | &result.m_width, &result.m_height)) { |
| 673 | return result; |
| 674 | } else { |
| 675 | return {}; |
| 676 | } |
| 677 | } |
| 678 | |
| 679 | /// \private |
| 680 | private_api::WindowAdapterRc &window_handle() { return inner; } |
| 681 | /// \private |
| 682 | const private_api::WindowAdapterRc &window_handle() const { return inner; } |
| 683 | |
| 684 | private: |
| 685 | private_api::WindowAdapterRc inner; |
| 686 | }; |
| 687 | |
| 688 | } |
| 689 | |