docs
Loading...
Searching...
No Matches
Window.h
Go to the documentation of this file.
1///
2/// Copyright (C) 2026 Ultralight, Inc. All rights reserved.
3/// A license is required for commercial use. https://ultralig.ht
4///
5#pragma once
6#include <Ultralight/CAPI/CAPI_DOMWindow.h>
10#include <Ultralight/dom/detail/Receivers.h>
11
12#include <string_view>
13#include <type_traits>
14#include <utility>
15
16namespace ultralight {
17namespace dom {
18
19class Selection;
20
21///
22/// The viewport of a DOM document.
23///
24/// A Window is a handle to the visual window that displays a document. You use it to inspect
25/// viewport dimensions and to listen for events that fire only on the window, such as `load` and
26/// `resize`.
27///
28/// This example updates a native HUD when the viewport resizes:
29///
30/// ```
31/// dom::Window window = document.defaultView();
32/// window.addEventListener("resize", [window] {
33/// FitHud(window.innerWidth(), window.innerHeight(),
34/// window.devicePixelRatio());
35/// });
36/// ```
37///
38/// ## Getting a Window
39///
40/// You can access a window through the View or a specific document:
41///
42/// - **Pass a View to Window(view) for the main frame.**
43/// - **Call Document::defaultView() on any frame's document.** This returns the window of that
44/// specific frame inside the page.
45///
46/// You should obtain a Window in LoadListener::OnDOMReady() or later. Before your first page loads,
47/// a View holds only the frame's initial blank page, and its window goes away when the new page
48/// loads.
49///
50/// ## Viewport Coordinates
51///
52/// Viewport sizes and scroll positions use CSS pixels. To convert CSS pixels to View pixels,
53/// multiply by View::device_scale() (or devicePixelRatio()), or divide View pixels by the scale
54/// factor to convert back.
55///
56/// ## Window Events
57///
58/// Events such as `load` and `resize` fire on the window only, so document listeners never receive
59/// them. Viewport `scroll` events fire on the document first and bubble up to the window.
60///
61/// Listeners receive `resize` and `scroll` events when the View next paints, rather than during the
62/// call that caused the change.
63///
64/// A `load` listener added in LoadListener::OnDOMReady() still receives the page's `load` event,
65/// which fires once all external resources finish loading.
66///
67/// @note Like other DOM handles, a Window is Valid, Empty, or Gone, and never keeps its page alive
68/// (see dom::Element).
69///
70/// @see dom::Document::defaultView(), LoadListener::OnDOMReady(),
71/// dom::Element::addEventListener(), View::device_scale()
72///
73class Window {
74 public:
75 ///
76 /// Create an empty Window.
77 ///
78 Window() = default;
79
80 ///
81 /// Get the window of a View's main frame.
82 ///
83 /// To get the window of a frame inside the page, call Document::defaultView() on that frame's
84 /// document.
85 ///
86 /// @param view The View to get the window from (nullptr gives an empty Window).
87 ///
88 /// @note Before your first page commits, this is the window of the frame's initial blank page,
89 /// and it goes away when your page commits. Get it in LoadListener::OnDOMReady() or later.
90 ///
91 explicit Window(View* view) : Window(Document(view).defaultView()) {}
92
93 ///
94 /// Copy constructor (both handles refer to the same window).
95 ///
96 /// @param other The Window to copy.
97 ///
98 Window(const Window& other)
99 : handle_(other.handle_ ? ulCreateDOMWindowRef(other.handle_) : nullptr) {}
100
101 ///
102 /// Move constructor (`other` becomes empty).
103 ///
104 /// @param other The Window to move from.
105 ///
106 Window(Window&& other) noexcept : handle_(other.handle_) { other.handle_ = nullptr; }
107
108 ///
109 /// Assignment (copies or moves).
110 ///
111 /// @param other The Window to assign from.
112 ///
113 /// @return Returns this Window.
114 ///
115 Window& operator=(Window other) noexcept {
116 std::swap(handle_, other.handle_);
117 return *this;
118 }
119
120 ///
121 /// Destroy this handle (the window itself isn't affected).
122 ///
123 ~Window() { ulDestroyDOMWindow(handle_); }
124
125 ///
126 /// Whether or not this Window is valid (see IsAlive()).
127 ///
128 explicit operator bool() const { return IsAlive(); }
129
130 ///
131 /// Whether or not this Window is empty (it holds no handle).
132 ///
133 bool IsEmpty() const { return handle_ == nullptr; }
134
135 ///
136 /// Whether or not this Window is valid (it isn't empty and its page is still alive).
137 ///
138 /// @note Safe to call from any thread.
139 ///
140 bool IsAlive() const { return handle_ && ulDOMWindowIsAlive(handle_); }
141
142 // --- Viewport metrics (read-only properties are calls) -------------------------------------
143
144 ///
145 /// Get the viewport width (innerWidth).
146 ///
147 /// @return Returns the width in CSS pixels, including the vertical scrollbar if there is one.
148 ///
149 int innerWidth() const { return ulDOMWindowGetInnerWidth(handle_); }
150
151 ///
152 /// Get the viewport height (innerHeight).
153 ///
154 /// @return Returns the height in CSS pixels, including the horizontal scrollbar if there is
155 /// one.
156 ///
157 int innerHeight() const { return ulDOMWindowGetInnerHeight(handle_); }
158
159 ///
160 /// Get the ratio of device pixels to CSS pixels (devicePixelRatio).
161 ///
162 /// @return Returns the View's device scale (see View::device_scale()).
163 ///
164 double devicePixelRatio() const { return ulDOMWindowGetDevicePixelRatio(handle_); }
165
166 ///
167 /// Get the viewport's horizontal scroll position (scrollX).
168 ///
169 /// @return Returns the position in CSS pixels (the library currently reports whole pixels).
170 ///
171 double scrollX() const { return ulDOMWindowGetScrollX(handle_); }
172
173 ///
174 /// Get the viewport's vertical scroll position (scrollY).
175 ///
176 /// @return Returns the position in CSS pixels (the library currently reports whole pixels).
177 ///
178 double scrollY() const { return ulDOMWindowGetScrollY(handle_); }
179
180 // --- Scrolling ------------------------------------------------------------------------------
181
182 ///
183 /// Scroll the viewport to a position (scrollTo).
184 ///
185 /// The page scrolls at once (CSS `scroll-behavior` is ignored), and the position stays within the
186 /// scrollable area.
187 ///
188 /// @param x The horizontal position in CSS pixels (any fraction is dropped).
189 ///
190 /// @param y The vertical position in CSS pixels (any fraction is dropped).
191 ///
192 void scrollTo(double x, double y) const { ulDOMWindowScrollTo(handle_, x, y); }
193
194 ///
195 /// Scroll the viewport by an offset (scrollBy).
196 ///
197 /// The page scrolls the same way as with scrollTo().
198 ///
199 /// @param x The horizontal offset in CSS pixels.
200 ///
201 /// @param y The vertical offset in CSS pixels.
202 ///
203 void scrollBy(double x, double y) const { ulDOMWindowScrollBy(handle_, x, y); }
204
205 // --- Computed styles --------------------------------------------------------------------------
206
207 ///
208 /// Get an element's computed style (getComputedStyle).
209 ///
210 /// This is the same as dom::getComputedStyle(), which you can call without a Window.
211 ///
212 /// @param element The element to read.
213 ///
214 /// @return Returns a read-only view of the element's computed style (see ComputedStyle).
215 ///
216 ComputedStyle getComputedStyle(const Element& element) const {
217 return dom::getComputedStyle(element);
218 }
219
220 // --- Document and selection -------------------------------------------------------------------
221
222 ///
223 /// Get the window's document (document).
224 ///
225 /// @return Returns the document (empty if this Window is empty).
226 ///
227 Document document() const { return Document::Adopt(ulDOMWindowGetDocument(handle_)); }
228
229 ///
230 /// Get the page's selection (getSelection), the caret or the highlighted text.
231 ///
232 /// @return Returns the selection of this window's document (the same one
233 /// Document::getSelection() returns).
234 ///
235 /// @note Include `<Ultralight/dom/Selection.h>` (or `<Ultralight/DOM.h>`) to use this.
236 ///
237 Selection getSelection() const;
238
239 // --- Events -----------------------------------------------------------------------------------
240
241 ///
242 /// Dispatch a synthetic event to the window (dispatchEvent).
243 ///
244 /// This works like Element::dispatchEvent().
245 ///
246 /// @param type The event type to dispatch.
247 ///
248 /// @param init The event's bubbles, cancelable, and composed flags (see EventInit).
249 ///
250 /// @return Returns false if a listener canceled the event with Event::preventDefault() (which
251 /// needs `init.cancelable`), or true otherwise.
252 ///
253 bool dispatchEvent(std::string_view type, const EventInit& init = {}) const {
254 detail::CString t(type);
255 return ulDOMWindowDispatchEvent(handle_, t.c_str(), detail::EventInitFlags(init),
256 nullptr);
257 }
258
259 ///
260 /// Dispatch a synthetic CustomEvent with a string payload to the window.
261 ///
262 /// This works like Element::dispatchCustomEvent().
263 ///
264 /// @param type The event type to dispatch.
265 ///
266 /// @param event_detail The payload as UTF-8 text, which listeners read as the event's `detail`
267 /// (see Element::dispatchCustomEvent()).
268 ///
269 /// @param init The event's bubbles, cancelable, and composed flags (see EventInit).
270 ///
271 /// @return Returns false if a listener canceled the event with Event::preventDefault() (which
272 /// needs `init.cancelable`), or true otherwise.
273 ///
274 bool dispatchCustomEvent(std::string_view type, std::string_view event_detail,
275 const EventInit& init = {}) const {
276 detail::CString t(type);
277 detail::CString d(event_detail);
278 return ulDOMWindowDispatchCustomEvent(handle_, t.c_str(),
279 detail::EventInitFlags(init), d.c_str(),
280 nullptr);
281 }
282
283 ///
284 /// Listen for an event on the window (addEventListener).
285 ///
286 /// This works like Element::addEventListener(). The window receives `load`, `resize`, and
287 /// viewport `scroll` events (see the Window class).
288 ///
289 /// @param type The event type to listen for (eg, `resize`).
290 ///
291 /// @param callback The callable to run on each event, taking (dom::Event) or ().
292 ///
293 /// @param options The listener's options (see AddEventListenerOptions).
294 ///
295 /// @return Returns a handle for removing the listener, which you can ignore. It's empty when
296 /// nothing was added (the page is gone or `options.signal` is already aborted).
297 ///
298 /// @note A `load` or viewport `scroll` event reports the document as its target, so
299 /// Event::target() reads empty.
300 ///
301 template <typename F>
302 EventListener addEventListener(std::string_view type, F&& callback,
303 const AddEventListenerOptions& options = {}) const {
304 using Fn = std::decay_t<F>;
305 static_assert(detail::InvocableWithEvent<Fn> || std::is_invocable_v<Fn&>,
306 "addEventListener takes a callable invocable with (dom::Event) or ()");
307 detail::CString t(type);
308 ULDOMEventCallback thunk = &detail::EventThunk<Fn>;
309 ULUserDataDestroyCallback destroy = &detail::DeleteCallable<Fn>;
310 return detail::AddListener<Fn>(std::forward<F>(callback), options,
311 [&](unsigned flags, void* fn) {
312 return ulDOMWindowAddEventListener(handle_, t.c_str(), flags,
313 thunk, fn, destroy);
314 });
315 }
316
317 ///
318 /// Listen for an event on the window, with options as flags (eg, `dom::Once | dom::Capture`).
319 ///
320 /// @param type The event type to listen for.
321 ///
322 /// @param callback The callable to run on each event, taking (dom::Event) or ().
323 ///
324 /// @param flags The listener's options (see EventListenerFlags).
325 ///
326 /// @return Returns a handle for removing the listener, which you can ignore (empty when the
327 /// page is gone).
328 ///
329 template <typename F>
330 EventListener addEventListener(std::string_view type, F&& callback, EventListenerFlags flags) const {
331 return addEventListener(type, std::forward<F>(callback), detail::ToOptions(flags));
332 }
333
334 ///
335 /// Listen by calling a member function on an object you keep alive.
336 ///
337 /// @param type The event type to listen for.
338 ///
339 /// @param receiver The object to call `method` on.
340 ///
341 /// @param method The member function to call, taking (dom::Event) or ().
342 ///
343 /// @param options The listener's options (see AddEventListenerOptions).
344 ///
345 /// @return Returns a handle for removing the listener, which you can ignore. It's empty when
346 /// nothing was added (the page is gone or `options.signal` is already aborted).
347 ///
348 /// @warning The listener calls `receiver` for as long as it lives, so `receiver` must outlive
349 /// the page, or the listener must be added with the signal of an AbortController
350 /// that `receiver` owns. The smart-pointer overload with a std::weak_ptr skips calls
351 /// once the object is gone instead.
352 ///
353 template <typename C, typename M>
354 requires(std::is_class_v<C> && std::is_member_function_pointer_v<M>
356 EventListener addEventListener(std::string_view type, C& receiver, M method,
357 const AddEventListenerOptions& options = {}) const {
358 return addEventListener(type, detail::WrapBorrowedMember(receiver, method), options);
359 }
360
361 ///
362 /// Listen by calling a member function on an object you keep alive, with options as flags.
363 ///
364 /// @param type The event type to listen for.
365 ///
366 /// @param receiver The object to call `method` on.
367 ///
368 /// @param method The member function to call, taking (dom::Event) or ().
369 ///
370 /// @param flags The listener's options (see EventListenerFlags).
371 ///
372 /// @return Returns a handle for removing the listener, which you can ignore (empty when the
373 /// page is gone).
374 ///
375 /// @warning The listener calls `receiver` for as long as it lives, so `receiver` must outlive
376 /// the page. To tie the listener to `receiver` instead, use the options overload
377 /// with the signal of an AbortController that `receiver` owns.
378 ///
379 template <typename C, typename M>
380 requires(std::is_class_v<C> && std::is_member_function_pointer_v<M>
381 && !LockableHolder<C>)
382 EventListener addEventListener(std::string_view type, C& receiver, M method,
383 EventListenerFlags flags) const {
384 return addEventListener(type, detail::WrapBorrowedMember(receiver, method), flags);
385 }
386
387 ///
388 /// Listen by calling a member function through a smart pointer that's checked before each call.
389 ///
390 /// @param type The event type to listen for.
391 ///
392 /// @param holder A shared_ptr, a weak_ptr, or another smart pointer with a HolderTraits
393 /// specialization (see LockableHolder). While it's expired, events are skipped.
394 ///
395 /// @param method The member function to call, taking (dom::Event) or ().
396 ///
397 /// @param options The listener's options (see AddEventListenerOptions).
398 ///
399 /// @return Returns a handle for removing the listener, which you can ignore. It's empty when
400 /// nothing was added (the page is gone or `options.signal` is already aborted).
401 ///
402 template <typename H, typename M>
403 requires(LockableHolder<H> && std::is_member_function_pointer_v<M>)
404 EventListener addEventListener(std::string_view type, H holder, M method,
405 const AddEventListenerOptions& options = {}) const {
406 return addEventListener(type, detail::WrapHolderMember(std::move(holder), method), options);
407 }
408
409 ///
410 /// Listen by calling a member function through a smart pointer, with options as flags.
411 ///
412 /// @param type The event type to listen for.
413 ///
414 /// @param holder A shared_ptr, a weak_ptr, or another smart pointer with a HolderTraits
415 /// specialization (see LockableHolder). While it's expired, events are skipped.
416 ///
417 /// @param method The member function to call, taking (dom::Event) or ().
418 ///
419 /// @param flags The listener's options (see EventListenerFlags).
420 ///
421 /// @return Returns a handle for removing the listener, which you can ignore (empty when the
422 /// page is gone).
423 ///
424 template <typename H, typename M>
425 requires(LockableHolder<H> && std::is_member_function_pointer_v<M>)
426 EventListener addEventListener(std::string_view type, H holder, M method,
427 EventListenerFlags flags) const {
428 return addEventListener(type, detail::WrapHolderMember(std::move(holder), method), flags);
429 }
430
431 // --- Interop with the C API (most embedders never touch raw handles) -----------------------
432
433 ///
434 /// Wrap a C handle you own, taking ownership of it.
435 ///
436 /// @param handle A handle from the C API that you would otherwise destroy with
437 /// ulDestroyDOMWindow() (NULL gives an empty Window).
438 ///
439 /// @return Returns a Window that destroys `handle` when it's done.
440 ///
441 static Window Adopt(ULDOMWindow handle) { return Window(handle); }
442
443 ///
444 /// Wrap a C handle the library owns, adding a reference.
445 ///
446 /// @param handle The borrowed handle (NULL gives an empty Window).
447 ///
448 /// @return Returns a Window with its own reference.
449 ///
450 static Window FromBorrowed(ULDOMWindow handle) {
451 return Window(handle ? ulCreateDOMWindowRef(handle) : nullptr);
452 }
453
454 ///
455 /// Get the C handle, for passing to the `<Ultralight/CAPI/CAPI_DOMWindow.h>` functions.
456 ///
457 /// @return Returns the handle (NULL for an empty Window). This Window still owns it, so don't
458 /// destroy it.
459 ///
460 ULDOMWindow raw() const { return handle_; }
461
462 ///
463 /// Give up ownership of the C handle and return it. This Window becomes empty.
464 ///
465 /// @return Returns the handle. You must call ulDestroyDOMWindow() when finished.
466 ///
467 ULDOMWindow LeakRef() {
468 ULDOMWindow handle = handle_;
469 handle_ = nullptr;
470 return handle;
471 }
472
473 protected:
474 explicit Window(ULDOMWindow handle) : handle_(handle) {}
475
476 private:
477 ULDOMWindow handle_ = nullptr;
478};
479
481 return Window::Adopt(ulDOMDocumentGetWindow(handle_));
482}
483
484} // namespace dom
485} // namespace ultralight
Web-page container rendered to an offscreen surface.
Definition View.h:483
A read-only view of an element's computed style (getComputedStyle).
Definition ComputedStyle.h:122
The root of a page's DOM tree in a View or frame.
Definition Document.h:106
static Document Adopt(ULDOMDocument handle)
Wrap a C handle you own, taking ownership of it.
Definition Document.h:940
Window defaultView() const
Get the document's window (defaultView).
Definition Window.h:480
A handle to an element on a page.
Definition Element.h:142
A handle to a registered DOM event listener.
Definition EventListener.h:151
A handle to the active user selection or caret in a document.
Definition Selection.h:101
The viewport of a DOM document.
Definition Window.h:73
EventListener addEventListener(std::string_view type, F &&callback, EventListenerFlags flags) const
Listen for an event on the window, with options as flags (eg, dom::Once | dom::Capture).
Definition Window.h:330
static Window Adopt(ULDOMWindow handle)
Wrap a C handle you own, taking ownership of it.
Definition Window.h:441
Window(View *view)
Get the window of a View's main frame.
Definition Window.h:91
~Window()
Destroy this handle (the window itself isn't affected).
Definition Window.h:123
EventListener addEventListener(std::string_view type, C &receiver, M method, EventListenerFlags flags) const
Listen by calling a member function on an object you keep alive, with options as flags.
Definition Window.h:382
EventListener addEventListener(std::string_view type, H holder, M method, const AddEventListenerOptions &options={}) const
Listen by calling a member function through a smart pointer that's checked before each call.
Definition Window.h:404
double scrollX() const
Get the viewport's horizontal scroll position (scrollX).
Definition Window.h:171
void scrollBy(double x, double y) const
Scroll the viewport by an offset (scrollBy).
Definition Window.h:203
int innerHeight() const
Get the viewport height (innerHeight).
Definition Window.h:157
Window(const Window &other)
Copy constructor (both handles refer to the same window).
Definition Window.h:98
EventListener addEventListener(std::string_view type, F &&callback, const AddEventListenerOptions &options={}) const
Listen for an event on the window (addEventListener).
Definition Window.h:302
Selection getSelection() const
Get the page's selection (getSelection), the caret or the highlighted text.
Definition Selection.h:555
Window()=default
Create an empty Window.
double devicePixelRatio() const
Get the ratio of device pixels to CSS pixels (devicePixelRatio).
Definition Window.h:164
Document document() const
Get the window's document (document).
Definition Window.h:227
static Window FromBorrowed(ULDOMWindow handle)
Wrap a C handle the library owns, adding a reference.
Definition Window.h:450
Window(Window &&other) noexcept
Move constructor (other becomes empty).
Definition Window.h:106
ComputedStyle getComputedStyle(const Element &element) const
Get an element's computed style (getComputedStyle).
Definition Window.h:216
bool IsEmpty() const
Whether or not this Window is empty (it holds no handle).
Definition Window.h:133
bool IsAlive() const
Whether or not this Window is valid (it isn't empty and its page is still alive).
Definition Window.h:140
bool dispatchEvent(std::string_view type, const EventInit &init={}) const
Dispatch a synthetic event to the window (dispatchEvent).
Definition Window.h:253
EventListener addEventListener(std::string_view type, H holder, M method, EventListenerFlags flags) const
Listen by calling a member function through a smart pointer, with options as flags.
Definition Window.h:426
ULDOMWindow raw() const
Get the C handle, for passing to the <Ultralight/CAPI/CAPI_DOMWindow.h> functions.
Definition Window.h:460
int innerWidth() const
Get the viewport width (innerWidth).
Definition Window.h:149
bool dispatchCustomEvent(std::string_view type, std::string_view event_detail, const EventInit &init={}) const
Dispatch a synthetic CustomEvent with a string payload to the window.
Definition Window.h:274
void scrollTo(double x, double y) const
Scroll the viewport to a position (scrollTo).
Definition Window.h:192
EventListener addEventListener(std::string_view type, C &receiver, M method, const AddEventListenerOptions &options={}) const
Listen by calling a member function on an object you keep alive.
Definition Window.h:356
Window(ULDOMWindow handle)
Definition Window.h:474
ULDOMWindow LeakRef()
Give up ownership of the C handle and return it.
Definition Window.h:467
Window & operator=(Window other) noexcept
Assignment (copies or moves).
Definition Window.h:115
double scrollY() const
Get the viewport's vertical scroll position (scrollY).
Definition Window.h:178
Whether or not the DOM API can hold an object through H (ignoring const and references),...
Definition Holders.h:41
Direct C++ access to modify page elements and handle events.
EventListenerFlags
Options for adding an event listener, as flags (addEventListener() and On()).
Definition EventListener.h:41
ComputedStyle getComputedStyle(const Element &element)
Get an element's computed style (getComputedStyle).
Definition ComputedStyle.h:232
Root namespace for every public Ultralight type, function, and enumeration.
Options for adding an event listener, like the web's options object for addEventListener().
Definition EventListener.h:526
Options for an event you dispatch yourself (the web's EventInit).
Definition Event.h:30