druid_shell/window.rs
1// Copyright 2018 The Druid Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Platform independent window types.
16
17use std::any::Any;
18use std::time::Duration;
19
20use crate::application::Application;
21use crate::backend::window as backend;
22use crate::common_util::Counter;
23use crate::dialog::{FileDialogOptions, FileInfo};
24use crate::error::Error;
25use crate::keyboard::KeyEvent;
26use crate::kurbo::{Insets, Point, Rect, Size};
27use crate::menu::Menu;
28use crate::mouse::{Cursor, CursorDesc, MouseEvent};
29use crate::region::Region;
30use crate::scale::Scale;
31use crate::text::{Event, InputHandler};
32use piet_common::PietText;
33#[cfg(feature = "raw-win-handle")]
34use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
35
36/// A token that uniquely identifies a running timer.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)]
38pub struct TimerToken(u64);
39
40impl TimerToken {
41 /// A token that does not correspond to any timer.
42 pub const INVALID: TimerToken = TimerToken(0);
43
44 /// Create a new token.
45 pub fn next() -> TimerToken {
46 static TIMER_COUNTER: Counter = Counter::new();
47 TimerToken(TIMER_COUNTER.next())
48 }
49
50 /// Create a new token from a raw value.
51 pub const fn from_raw(id: u64) -> TimerToken {
52 TimerToken(id)
53 }
54
55 /// Get the raw value for a token.
56 pub const fn into_raw(self) -> u64 {
57 self.0
58 }
59}
60
61/// Uniquely identifies a text input field inside a window.
62#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)]
63pub struct TextFieldToken(u64);
64
65impl TextFieldToken {
66 /// A token that does not correspond to any text input.
67 pub const INVALID: TextFieldToken = TextFieldToken(0);
68
69 /// Create a new token; this should for the most part be called only by platform code.
70 pub fn next() -> TextFieldToken {
71 static TEXT_FIELD_COUNTER: Counter = Counter::new();
72 TextFieldToken(TEXT_FIELD_COUNTER.next())
73 }
74
75 /// Create a new token from a raw value.
76 pub const fn from_raw(id: u64) -> TextFieldToken {
77 TextFieldToken(id)
78 }
79
80 /// Get the raw value for a token.
81 pub const fn into_raw(self) -> u64 {
82 self.0
83 }
84}
85
86//NOTE: this has a From<backend::Handle> impl for construction
87/// A handle that can enqueue tasks on the window loop.
88#[derive(Clone)]
89pub struct IdleHandle(backend::IdleHandle);
90
91impl IdleHandle {
92 /// Add an idle handler, which is called (once) when the message loop
93 /// is empty. The idle handler will be run from the main UI thread, and
94 /// won't be scheduled if the associated view has been dropped.
95 ///
96 /// Note: the name "idle" suggests that it will be scheduled with a lower
97 /// priority than other UI events, but that's not necessarily the case.
98 pub fn add_idle<F>(&self, callback: F)
99 where
100 F: FnOnce(&mut dyn WinHandler) + Send + 'static,
101 {
102 self.0.add_idle_callback(callback)
103 }
104
105 /// Request a callback from the runloop. Your `WinHander::idle` method will
106 /// be called with the `token` that was passed in.
107 pub fn schedule_idle(&mut self, token: IdleToken) {
108 self.0.add_idle_token(token)
109 }
110}
111
112/// A token that uniquely identifies a idle schedule.
113#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)]
114pub struct IdleToken(usize);
115
116impl IdleToken {
117 /// Create a new `IdleToken` with the given raw `usize` id.
118 pub const fn new(raw: usize) -> IdleToken {
119 IdleToken(raw)
120 }
121}
122
123/// A token that uniquely identifies a file dialog request.
124#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)]
125pub struct FileDialogToken(u64);
126
127impl FileDialogToken {
128 /// A token that does not correspond to any file dialog.
129 pub const INVALID: FileDialogToken = FileDialogToken(0);
130
131 /// Create a new token.
132 pub fn next() -> FileDialogToken {
133 static COUNTER: Counter = Counter::new();
134 FileDialogToken(COUNTER.next())
135 }
136
137 /// Create a new token from a raw value.
138 pub const fn from_raw(id: u64) -> FileDialogToken {
139 FileDialogToken(id)
140 }
141
142 /// Get the raw value for a token.
143 pub const fn into_raw(self) -> u64 {
144 self.0
145 }
146}
147
148/// Levels in the window system - Z order for display purposes.
149/// Describes the purpose of a window and should be mapped appropriately to match platform
150/// conventions.
151#[derive(Clone, PartialEq, Eq)]
152pub enum WindowLevel {
153 /// A top level app window.
154 AppWindow,
155 /// A window that should stay above app windows - like a tooltip
156 Tooltip(WindowHandle),
157 /// A user interface element such as a dropdown menu or combo box
158 DropDown(WindowHandle),
159 /// A modal dialog
160 Modal(WindowHandle),
161}
162
163/// Contains the different states a Window can be in.
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165pub enum WindowState {
166 Maximized,
167 Minimized,
168 Restored,
169}
170
171/// A handle to a platform window object.
172#[derive(Clone, Default, PartialEq, Eq)]
173pub struct WindowHandle(pub(crate) backend::WindowHandle);
174
175impl WindowHandle {
176 /// Make this window visible.
177 pub fn show(&self) {
178 self.0.show()
179 }
180
181 /// Close the window.
182 pub fn close(&self) {
183 self.0.close()
184 }
185
186 /// Hide the window
187 pub fn hide(&self) {
188 self.0.hide()
189 }
190
191 /// Set whether the window should be resizable
192 pub fn resizable(&self, resizable: bool) {
193 self.0.resizable(resizable)
194 }
195
196 /// Sets the state of the window.
197 pub fn set_window_state(&mut self, state: WindowState) {
198 self.0.set_window_state(state);
199 }
200
201 /// Gets the state of the window.
202 pub fn get_window_state(&self) -> WindowState {
203 self.0.get_window_state()
204 }
205
206 /// Informs the system that the current location of the mouse should be treated as part of the
207 /// window's titlebar. This can be used to implement a custom titlebar widget. Note that
208 /// because this refers to the current location of the mouse, you should probably call this
209 /// function in response to every relevant [`WinHandler::mouse_move`].
210 ///
211 /// This is currently only implemented on Windows and GTK.
212 pub fn handle_titlebar(&self, val: bool) {
213 self.0.handle_titlebar(val);
214 }
215
216 /// Set whether the window should show titlebar.
217 pub fn show_titlebar(&self, show_titlebar: bool) {
218 self.0.show_titlebar(show_titlebar)
219 }
220
221 /// Sets the position of the window.
222 ///
223 /// The position is given in [display points], measured relative to the parent window if there
224 /// is one, or the origin of the virtual screen if there is no parent.
225 ///
226 /// [display points]: crate::Scale
227 pub fn set_position(&self, position: impl Into<Point>) {
228 self.0.set_position(position.into())
229 }
230
231 /// Sets whether the window is always on top of other windows.
232 ///
233 /// How and if this works is system dependent, by either setting a flag, or setting the level.
234 /// On Wayland systems, the user needs to manually set this in the titlebar.
235 pub fn set_always_on_top(&self, always_on_top: bool) {
236 self.0.set_always_on_top(always_on_top);
237 }
238
239 /// Sets where in the window the user can interact with the program.
240 ///
241 /// This enables irregularly shaped windows. For example, you can make it simply
242 /// not rectangular or you can make a sub-window which can be moved even on Wayland.
243 ///
244 /// The contents of `region` are added together, and are specified in [display points], so
245 /// you do not need to deal with scale yourself.
246 ///
247 /// On GTK and Wayland, this is specified as where the user can interact with the program.
248 /// On Windows, this is specified as both where you can interact, and where the window is
249 /// visible. So on Windows it will hide all regions not specified.
250 /// On macOS, this does nothing, but you can make the window transparent for the same effect.
251 /// On Web, this does nothing.
252 ///
253 /// [display points]: crate::Scale
254 pub fn set_input_region(&self, region: Option<Region>) {
255 self.0.set_input_region(region)
256 }
257
258 /// Returns the position of the top left corner of the window.
259 ///
260 /// The position is returned in [display points], measured relative to the parent window if
261 /// there is one, of the origin of the virtual screen if there is no parent.
262 ///
263 /// [display points]: crate::Scale
264 pub fn get_position(&self) -> Point {
265 self.0.get_position()
266 }
267
268 /// Returns the insets of the window content from its position and size in [display points].
269 ///
270 /// This is to account for any window system provided chrome, e.g. title bars. For example, if
271 /// you want your window to have room for contents of size `contents`, then you should call
272 /// [`WindowHandle::get_size`] with an argument of `(contents.to_rect() + insets).size()`,
273 /// where `insets` is the return value of this function.
274 ///
275 /// The details of this function are somewhat platform-dependent. For example, on Windows both
276 /// the insets and the window size include the space taken up by the title bar and window
277 /// decorations; on GTK neither the insets nor the window size include the title bar or window
278 /// decorations.
279 ///
280 /// [display points]: crate::Scale
281 pub fn content_insets(&self) -> Insets {
282 self.0.content_insets()
283 }
284
285 /// Set the window's size in [display points].
286 ///
287 /// The actual window size in pixels will depend on the platform DPI settings.
288 ///
289 /// This should be considered a request to the platform to set the size of the window. The
290 /// platform might choose a different size depending on its DPI or other platform-dependent
291 /// configuration. To know the actual size of the window you should handle the
292 /// [`WinHandler::size`] method.
293 ///
294 /// [display points]: crate::Scale
295 pub fn set_size(&self, size: impl Into<Size>) {
296 self.0.set_size(size.into())
297 }
298
299 /// Gets the window size, in [display points].
300 ///
301 /// [display points]: crate::Scale
302 pub fn get_size(&self) -> Size {
303 self.0.get_size()
304 }
305
306 /// Bring this window to the front of the window stack and give it focus.
307 pub fn bring_to_front_and_focus(&self) {
308 self.0.bring_to_front_and_focus()
309 }
310
311 /// Request that [`prepare_paint`] and [`paint`] be called next time there's the opportunity to
312 /// render another frame. This differs from [`invalidate`] and [`invalidate_rect`] in that it
313 /// doesn't invalidate any part of the window.
314 ///
315 /// [`invalidate`]: WindowHandle::invalidate
316 /// [`invalidate_rect`]: WindowHandle::invalidate_rect
317 /// [`paint`]: WinHandler::paint
318 /// [`prepare_paint`]: WinHandler::prepare_paint
319 pub fn request_anim_frame(&self) {
320 self.0.request_anim_frame();
321 }
322
323 /// Request invalidation of the entire window contents.
324 pub fn invalidate(&self) {
325 self.0.invalidate();
326 }
327
328 /// Request invalidation of a region of the window.
329 pub fn invalidate_rect(&self, rect: Rect) {
330 self.0.invalidate_rect(rect);
331 }
332
333 /// Set the title for this menu.
334 pub fn set_title(&self, title: &str) {
335 self.0.set_title(title)
336 }
337
338 /// Set the top-level menu for this window.
339 pub fn set_menu(&self, menu: Menu) {
340 self.0.set_menu(menu.into_inner())
341 }
342
343 /// Get access to a type that can perform text layout.
344 pub fn text(&self) -> PietText {
345 self.0.text()
346 }
347
348 /// Register a new text input receiver for this window.
349 ///
350 /// This method should be called any time a new editable text field is
351 /// created inside a window. Any text field with a `TextFieldToken` that
352 /// has not yet been destroyed with `remove_text_field` *must* be ready to
353 /// accept input from the platform via `WinHandler::text_input` at any time,
354 /// even if it is not currently focused.
355 ///
356 /// Returns the `TextFieldToken` associated with this new text input.
357 pub fn add_text_field(&self) -> TextFieldToken {
358 self.0.add_text_field()
359 }
360
361 /// Unregister a previously registered text input receiver.
362 ///
363 /// If `token` is the text field currently focused, the platform automatically
364 /// sets the focused field to `None`.
365 pub fn remove_text_field(&self, token: TextFieldToken) {
366 self.0.remove_text_field(token)
367 }
368
369 /// Notify the platform that the focused text input receiver has changed.
370 ///
371 /// This must be called any time focus changes to a different text input, or
372 /// when focus switches away from a text input.
373 pub fn set_focused_text_field(&self, active_field: Option<TextFieldToken>) {
374 self.0.set_focused_text_field(active_field)
375 }
376
377 /// Notify the platform that some text input state has changed, such as the
378 /// selection, contents, etc.
379 ///
380 /// This method should *never* be called in response to edits from a
381 /// `InputHandler`; only in response to changes from the application:
382 /// scrolling, remote edits, etc.
383 pub fn update_text_field(&self, token: TextFieldToken, update: Event) {
384 self.0.update_text_field(token, update)
385 }
386
387 /// Schedule a timer.
388 ///
389 /// This causes a [`WinHandler::timer`] call at the deadline. The
390 /// return value is a token that can be used to associate the request
391 /// with the handler call.
392 ///
393 /// Note that this is not a precise timer. On Windows, the typical
394 /// resolution is around 10ms. Therefore, it's best used for things
395 /// like blinking a cursor or triggering tooltips, not for anything
396 /// requiring precision.
397 pub fn request_timer(&self, deadline: Duration) -> TimerToken {
398 self.0.request_timer(instant::Instant::now() + deadline)
399 }
400
401 /// Set the cursor icon.
402 pub fn set_cursor(&mut self, cursor: &Cursor) {
403 self.0.set_cursor(cursor)
404 }
405
406 pub fn make_cursor(&self, desc: &CursorDesc) -> Option<Cursor> {
407 self.0.make_cursor(desc)
408 }
409
410 /// Prompt the user to choose a file to open.
411 ///
412 /// This won't block immediately; the file dialog will be shown whenever control returns to
413 /// `druid-shell`, and the [`WinHandler::open_file`] method will be called when the dialog is
414 /// closed.
415 pub fn open_file(&mut self, options: FileDialogOptions) -> Option<FileDialogToken> {
416 self.0.open_file(options)
417 }
418
419 /// Prompt the user to choose a path for saving.
420 ///
421 /// This won't block immediately; the file dialog will be shown whenever control returns to
422 /// `druid-shell`, and the [`WinHandler::save_as`] method will be called when the dialog is
423 /// closed.
424 pub fn save_as(&mut self, options: FileDialogOptions) -> Option<FileDialogToken> {
425 self.0.save_as(options)
426 }
427
428 /// Display a pop-up menu at the given position.
429 ///
430 /// `pos` is in the coordinate space of the window.
431 pub fn show_context_menu(&self, menu: Menu, pos: Point) {
432 self.0.show_context_menu(menu.into_inner(), pos)
433 }
434
435 /// Get a handle that can be used to schedule an idle task.
436 pub fn get_idle_handle(&self) -> Option<IdleHandle> {
437 self.0.get_idle_handle().map(IdleHandle)
438 }
439
440 /// Get the DPI scale of the window.
441 ///
442 /// The returned [`Scale`](crate::Scale) is a copy and thus its information will be stale after
443 /// the platform DPI changes. This means you should not stash it and rely on it later; it is
444 /// only guaranteed to be valid for the current pass of the runloop.
445 // TODO: Can we get rid of the Result/Error for ergonomics?
446 pub fn get_scale(&self) -> Result<Scale, Error> {
447 self.0.get_scale().map_err(Into::into)
448 }
449}
450
451#[cfg(feature = "raw-win-handle")]
452unsafe impl HasRawWindowHandle for WindowHandle {
453 fn raw_window_handle(&self) -> RawWindowHandle {
454 self.0.raw_window_handle()
455 }
456}
457
458/// A builder type for creating new windows.
459pub struct WindowBuilder(backend::WindowBuilder);
460
461impl WindowBuilder {
462 /// Create a new `WindowBuilder`.
463 ///
464 /// Takes the [`Application`](crate::Application) that this window is for.
465 pub fn new(app: Application) -> WindowBuilder {
466 WindowBuilder(backend::WindowBuilder::new(app.backend_app))
467 }
468
469 /// Set the [`WinHandler`] for this window.
470 ///
471 /// This is the object that will receive callbacks from this window.
472 pub fn set_handler(&mut self, handler: Box<dyn WinHandler>) {
473 self.0.set_handler(handler)
474 }
475
476 /// Set the window's initial drawing area size in [display points].
477 ///
478 /// The actual window size in pixels will depend on the platform DPI settings.
479 ///
480 /// This should be considered a request to the platform to set the size of the window. The
481 /// platform might choose a different size depending on its DPI or other platform-dependent
482 /// configuration. To know the actual size of the window you should handle the
483 /// [`WinHandler::size`] method.
484 ///
485 /// [display points]: crate::Scale
486 pub fn set_size(&mut self, size: Size) {
487 self.0.set_size(size)
488 }
489
490 /// Set the window's minimum drawing area size in [display points].
491 ///
492 /// The actual minimum window size in pixels will depend on the platform DPI settings.
493 ///
494 /// This should be considered a request to the platform to set the minimum size of the window.
495 /// The platform might increase the size a tiny bit due to DPI.
496 ///
497 /// [display points]: crate::Scale
498 pub fn set_min_size(&mut self, size: Size) {
499 self.0.set_min_size(size)
500 }
501
502 /// Set whether the window should be resizable.
503 pub fn resizable(&mut self, resizable: bool) {
504 self.0.resizable(resizable)
505 }
506
507 /// Set whether the window should have a titlebar and decorations.
508 pub fn show_titlebar(&mut self, show_titlebar: bool) {
509 self.0.show_titlebar(show_titlebar)
510 }
511
512 /// Set whether the window should be always positioned above all other windows.
513 pub fn set_always_on_top(&mut self, always_on_top: bool) {
514 self.0.set_always_on_top(always_on_top);
515 }
516
517 /// Set whether the window background should be transparent
518 pub fn set_transparent(&mut self, transparent: bool) {
519 self.0.set_transparent(transparent)
520 }
521
522 /// Sets the initial window position in display points.
523 /// For windows with a parent, the position is relative to the parent.
524 /// For windows without a parent, it is relative to the origin of the virtual screen.
525 /// See also [set_level]
526 ///
527 /// [set_level]: crate::WindowBuilder::set_level
528 pub fn set_position(&mut self, position: Point) {
529 self.0.set_position(position);
530 }
531
532 /// Sets the initial [`WindowLevel`].
533 pub fn set_level(&mut self, level: WindowLevel) {
534 self.0.set_level(level);
535 }
536
537 /// Set the window's initial title.
538 pub fn set_title(&mut self, title: impl Into<String>) {
539 self.0.set_title(title)
540 }
541
542 /// Set the window's menu.
543 pub fn set_menu(&mut self, menu: Menu) {
544 self.0.set_menu(menu.into_inner())
545 }
546
547 /// Sets the initial state of the window.
548 pub fn set_window_state(&mut self, state: WindowState) {
549 self.0.set_window_state(state);
550 }
551
552 /// Attempt to construct the platform window.
553 ///
554 /// If this fails, your application should exit.
555 pub fn build(self) -> Result<WindowHandle, Error> {
556 self.0.build().map(WindowHandle).map_err(Into::into)
557 }
558}
559
560/// App behavior, supplied by the app.
561///
562/// Many of the "window procedure" messages map to calls to this trait.
563/// The methods are non-mut because the window procedure can be called
564/// recursively; implementers are expected to use `RefCell` or the like,
565/// but should be careful to keep the lifetime of the borrow short.
566pub trait WinHandler {
567 /// Provide the handler with a handle to the window so that it can
568 /// invalidate or make other requests.
569 ///
570 /// This method passes the `WindowHandle` directly, because the handler may
571 /// wish to stash it.
572 fn connect(&mut self, handle: &WindowHandle);
573
574 /// Called when the size of the window has changed.
575 ///
576 /// The `size` parameter is the new size in [display points](crate::Scale).
577 #[allow(unused_variables)]
578 fn size(&mut self, size: Size) {}
579
580 /// Called when the [scale](crate::Scale) of the window has changed.
581 ///
582 /// This is always called before the accompanying [`size`](WinHandler::size).
583 #[allow(unused_variables)]
584 fn scale(&mut self, scale: Scale) {}
585
586 /// Request the handler to prepare to paint the window contents. In particular, if there are
587 /// any regions that need to be repainted on the next call to `paint`, the handler should
588 /// invalidate those regions by calling [`WindowHandle::invalidate_rect`] or
589 /// [`WindowHandle::invalidate`].
590 fn prepare_paint(&mut self);
591
592 /// Request the handler to paint the window contents. `invalid` is the region in [display
593 /// points](crate::Scale) that needs to be repainted; painting outside the invalid region will
594 /// have no effect.
595 fn paint(&mut self, piet: &mut piet_common::Piet, invalid: &Region);
596
597 /// Called when the resources need to be rebuilt.
598 ///
599 /// Discussion: this function is mostly motivated by using
600 /// `GenericRenderTarget` on Direct2D. If we move to `DeviceContext`
601 /// instead, then it's possible we don't need this.
602 #[allow(unused_variables)]
603 fn rebuild_resources(&mut self) {}
604
605 /// Called when a menu item is selected.
606 #[allow(unused_variables)]
607 fn command(&mut self, id: u32) {}
608
609 /// Called when a "Save As" dialog is closed.
610 ///
611 /// `token` is the value returned by [`WindowHandle::save_as`]. `file` contains the information
612 /// of the chosen path, or `None` if the save dialog was cancelled.
613 #[allow(unused_variables)]
614 fn save_as(&mut self, token: FileDialogToken, file: Option<FileInfo>) {}
615
616 /// Called when an "Open" dialog is closed.
617 ///
618 /// `token` is the value returned by [`WindowHandle::open_file`]. `file` contains the information
619 /// of the chosen path, or `None` if the save dialog was cancelled.
620 #[allow(unused_variables)]
621 fn open_file(&mut self, token: FileDialogToken, file: Option<FileInfo>) {}
622
623 /// Called when an "Open" dialog with multiple selection is closed.
624 ///
625 /// `token` is the value returned by [`WindowHandle::open_file`]. `files` contains the information
626 /// of the chosen paths, or `None` if the save dialog was cancelled.
627 #[allow(unused_variables)]
628 fn open_files(&mut self, token: FileDialogToken, files: Vec<FileInfo>) {}
629
630 /// Called on a key down event.
631 ///
632 /// Return `true` if the event is handled.
633 #[allow(unused_variables)]
634 fn key_down(&mut self, event: KeyEvent) -> bool {
635 false
636 }
637
638 /// Called when a key is released. This corresponds to the WM_KEYUP message
639 /// on Windows, or keyUp(withEvent:) on macOS.
640 #[allow(unused_variables)]
641 fn key_up(&mut self, event: KeyEvent) {}
642
643 /// Take a lock for the text document specified by `token`.
644 ///
645 /// All calls to this method must be balanced with a call to
646 /// [`release_input_lock`].
647 ///
648 /// If `mutable` is true, the lock should be a write lock, and allow calling
649 /// mutating methods on InputHandler. This method is called from the top
650 /// level of the event loop and expects to acquire a lock successfully.
651 ///
652 /// For more information, see [the text input documentation](crate::text).
653 ///
654 /// [`release_input_lock`]: WinHandler::release_input_lock
655 #[allow(unused_variables)]
656 fn acquire_input_lock(
657 &mut self,
658 token: TextFieldToken,
659 mutable: bool,
660 ) -> Box<dyn InputHandler> {
661 panic!("acquire_input_lock was called on a WinHandler that did not expect text input.")
662 }
663
664 /// Release a lock previously acquired by [`acquire_input_lock`].
665 ///
666 /// [`acquire_input_lock`]: WinHandler::acquire_input_lock
667 #[allow(unused_variables)]
668 fn release_input_lock(&mut self, token: TextFieldToken) {
669 panic!("release_input_lock was called on a WinHandler that did not expect text input.")
670 }
671
672 /// Called on a mouse wheel event.
673 ///
674 /// The polarity is the amount to be added to the scroll position,
675 /// in other words the opposite of the direction the content should
676 /// move on scrolling. This polarity is consistent with the
677 /// deltaX and deltaY values in a web [WheelEvent].
678 ///
679 /// [WheelEvent]: https://w3c.github.io/uievents/#event-type-wheel
680 #[allow(unused_variables)]
681 fn wheel(&mut self, event: &MouseEvent) {}
682
683 /// Called when a platform-defined zoom gesture occurs (such as pinching
684 /// on the trackpad).
685 #[allow(unused_variables)]
686 fn zoom(&mut self, delta: f64) {}
687
688 /// Called when the mouse moves.
689 #[allow(unused_variables)]
690 fn mouse_move(&mut self, event: &MouseEvent) {}
691
692 /// Called on mouse button down.
693 #[allow(unused_variables)]
694 fn mouse_down(&mut self, event: &MouseEvent) {}
695
696 /// Called on mouse button up.
697 #[allow(unused_variables)]
698 fn mouse_up(&mut self, event: &MouseEvent) {}
699
700 /// Called when the mouse cursor has left the application window
701 fn mouse_leave(&mut self) {}
702
703 /// Called on timer event.
704 ///
705 /// This is called at (approximately) the requested deadline by a
706 /// [`WindowHandle::request_timer()`] call. The token argument here is the same
707 /// as the return value of that call.
708 #[allow(unused_variables)]
709 fn timer(&mut self, token: TimerToken) {}
710
711 /// Called when this window becomes the focused window.
712 #[allow(unused_variables)]
713 fn got_focus(&mut self) {}
714
715 /// Called when this window stops being the focused window.
716 #[allow(unused_variables)]
717 fn lost_focus(&mut self) {}
718
719 /// Called when the shell requests to close the window, for example because the user clicked
720 /// the little "X" in the titlebar.
721 ///
722 /// If you want to actually close the window in response to this request, call
723 /// [`WindowHandle::close`]. If you don't implement this method, clicking the titlebar "X" will
724 /// have no effect.
725 fn request_close(&mut self) {}
726
727 /// Called when the window is being destroyed. Note that this happens
728 /// earlier in the sequence than drop (at WM_DESTROY, while the latter is
729 /// WM_NCDESTROY).
730 #[allow(unused_variables)]
731 fn destroy(&mut self) {}
732
733 /// Called when a idle token is requested by [`IdleHandle::schedule_idle()`] call.
734 #[allow(unused_variables)]
735 fn idle(&mut self, token: IdleToken) {}
736
737 /// Get a reference to the handler state. Used mostly by idle handlers.
738 fn as_any(&mut self) -> &mut dyn Any;
739}
740
741impl From<backend::WindowHandle> for WindowHandle {
742 fn from(src: backend::WindowHandle) -> WindowHandle {
743 WindowHandle(src)
744 }
745}
746
747#[cfg(test)]
748mod test {
749 use super::*;
750
751 use static_assertions as sa;
752
753 sa::assert_not_impl_any!(WindowHandle: Send, Sync);
754 sa::assert_impl_all!(IdleHandle: Send, Sync);
755}