use crate::dpi::{Position, Size};
use crate::error::OsError;
use crate::handler::Handler;
use crate::oneoff::oneoff;
use crate::reactor::{EventLoopOp, Reactor};
use crate::sync::{ThreadSafety, __private::Rc};
pub(crate) mod registration;
use registration::Registration;
use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::error::{ExternalError, NotSupportedError};
use winit::event::DeviceId;
use winit::monitor::MonitorHandle;
#[doc(inline)]
pub use winit::window::{
CursorGrabMode, CursorIcon, Fullscreen, Icon, ImePurpose, ResizeDirection, Theme,
UserAttentionType, WindowButtons, WindowLevel,
};
#[derive(Debug, Clone)]
pub struct WindowAttributes {
pub inner_size: Option<Size>,
pub min_inner_size: Option<Size>,
pub max_inner_size: Option<Size>,
pub position: Option<Position>,
pub resizable: bool,
pub enabled_buttons: WindowButtons,
pub title: String,
pub fullscreen: Option<Fullscreen>,
pub maximized: bool,
pub visible: bool,
pub transparent: bool,
pub decorations: bool,
pub window_icon: Option<Icon>,
pub preferred_theme: Option<Theme>,
pub resize_increments: Option<Size>,
pub content_protected: bool,
pub window_level: WindowLevel,
pub active: bool,
}
impl Default for WindowAttributes {
#[inline]
fn default() -> WindowAttributes {
WindowAttributes {
inner_size: None,
min_inner_size: None,
max_inner_size: None,
position: None,
resizable: true,
enabled_buttons: WindowButtons::all(),
title: "winit window".to_owned(),
maximized: false,
fullscreen: None,
visible: true,
transparent: false,
decorations: true,
window_level: Default::default(),
window_icon: None,
preferred_theme: None,
resize_increments: None,
content_protected: false,
active: true,
}
}
}
#[derive(Default)]
pub struct WindowBuilder {
window: WindowAttributes,
pub(crate) platform: crate::platform::PlatformSpecific,
}
impl WindowBuilder {
pub fn new() -> WindowBuilder {
WindowBuilder::default()
}
pub fn attributes(&self) -> &WindowAttributes {
&self.window
}
pub fn window_attributes(&self) -> &WindowAttributes {
&self.window
}
#[inline]
pub fn with_inner_size<S: Into<Size>>(mut self, size: S) -> Self {
self.window.inner_size = Some(size.into());
self
}
#[inline]
pub fn with_min_inner_size<S: Into<Size>>(mut self, min_size: S) -> Self {
self.window.min_inner_size = Some(min_size.into());
self
}
#[inline]
pub fn with_max_inner_size<S: Into<Size>>(mut self, max_size: S) -> Self {
self.window.max_inner_size = Some(max_size.into());
self
}
#[inline]
pub fn with_position<P: Into<Position>>(mut self, position: P) -> Self {
self.window.position = Some(position.into());
self
}
#[inline]
pub fn with_resizable(mut self, resizable: bool) -> Self {
self.window.resizable = resizable;
self
}
#[inline]
pub fn with_enabled_buttons(mut self, buttons: WindowButtons) -> Self {
self.window.enabled_buttons = buttons;
self
}
#[inline]
pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
self.window.title = title.into();
self
}
#[inline]
pub fn with_fullscreen(mut self, fullscreen: Option<Fullscreen>) -> Self {
self.window.fullscreen = fullscreen;
self
}
#[inline]
pub fn with_maximized(mut self, maximized: bool) -> Self {
self.window.maximized = maximized;
self
}
#[inline]
pub fn with_visible(mut self, visible: bool) -> Self {
self.window.visible = visible;
self
}
#[inline]
pub fn with_transparent(mut self, transparent: bool) -> Self {
self.window.transparent = transparent;
self
}
#[inline]
pub fn transparent(&self) -> bool {
self.window.transparent
}
#[inline]
pub fn with_decorations(mut self, decorations: bool) -> Self {
self.window.decorations = decorations;
self
}
#[inline]
pub fn with_window_level(mut self, level: WindowLevel) -> Self {
self.window.window_level = level;
self
}
#[inline]
pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> Self {
self.window.window_icon = window_icon;
self
}
#[inline]
pub fn with_theme(mut self, theme: Option<Theme>) -> Self {
self.window.preferred_theme = theme;
self
}
#[inline]
pub fn with_resize_increments<S: Into<Size>>(mut self, resize_increments: S) -> Self {
self.window.resize_increments = Some(resize_increments.into());
self
}
#[inline]
pub fn with_content_protected(mut self, protected: bool) -> Self {
self.window.content_protected = protected;
self
}
#[inline]
pub fn with_active(mut self, active: bool) -> WindowBuilder {
self.window.active = active;
self
}
pub async fn build<TS: ThreadSafety>(self) -> Result<Window<TS>, OsError> {
let (tx, rx) = oneoff();
let reactor = TS::get_reactor();
reactor
.push_event_loop_op(EventLoopOp::BuildWindow {
builder: Box::new(self),
waker: tx,
})
.await;
let inner = rx.recv().await?;
let registration = reactor.insert_window(inner.id());
Ok(Window {
inner: TS::Rc::new(inner),
registration,
reactor,
})
}
pub(crate) fn into_winit_builder(self) -> winit::window::WindowBuilder {
let mut builder = winit::window::WindowBuilder::new();
if let Some(size) = self.window.inner_size {
builder = builder.with_inner_size(size);
}
if let Some(size) = self.window.min_inner_size {
builder = builder.with_min_inner_size(size);
}
if let Some(size) = self.window.max_inner_size {
builder = builder.with_max_inner_size(size);
}
if let Some(position) = self.window.position {
builder = builder.with_position(position);
}
builder = builder
.with_resizable(self.window.resizable)
.with_enabled_buttons(self.window.enabled_buttons)
.with_title(&self.window.title)
.with_fullscreen(self.window.fullscreen.clone())
.with_maximized(self.window.maximized)
.with_visible(self.window.visible)
.with_transparent(self.window.transparent)
.with_decorations(self.window.decorations);
if let Some(icon) = self.window.window_icon.clone() {
builder = builder.with_window_icon(Some(icon));
}
builder = builder.with_theme(self.window.preferred_theme);
if let Some(size) = self.window.resize_increments {
builder = builder.with_resize_increments(size);
}
builder = builder
.with_content_protected(self.window.content_protected)
.with_window_level(self.window.window_level)
.with_active(self.window.active);
builder = self.platform.apply_to(builder);
builder
}
}
#[derive(Clone)]
pub struct Window<TS: ThreadSafety> {
inner: TS::Rc<winit::window::Window>,
registration: TS::Rc<Registration<TS>>,
reactor: TS::Rc<Reactor<TS>>,
}
impl<TS: ThreadSafety> Drop for Window<TS> {
fn drop(&mut self) {
self.reactor.remove_window(self.inner.id());
}
}
unsafe impl<TS: ThreadSafety> raw_window_handle::HasRawDisplayHandle for Window<TS> {
fn raw_display_handle(&self) -> raw_window_handle::RawDisplayHandle {
self.inner.raw_display_handle()
}
}
unsafe impl<TS: ThreadSafety> raw_window_handle::HasRawWindowHandle for Window<TS> {
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
self.inner.raw_window_handle()
}
}
impl<TS: ThreadSafety> Window<TS> {
pub async fn new() -> Result<Window<TS>, OsError> {
WindowBuilder::new().build().await
}
pub fn window(&self) -> &winit::window::Window {
&self.inner
}
pub fn id(&self) -> winit::window::WindowId {
self.inner.id()
}
pub fn scale_factor(&self) -> f64 {
self.inner.scale_factor()
}
pub fn request_redraw(&self) {
self.inner.request_redraw();
}
}
impl<TS: ThreadSafety> Window<TS> {
pub async fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::InnerPosition {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::OuterPosition {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_outer_position(&self, position: impl Into<Position>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetOuterPosition {
window: self.inner.clone(),
position: position.into(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn inner_size(&self) -> PhysicalSize<u32> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::InnerSize {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn outer_size(&self) -> PhysicalSize<u32> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::OuterSize {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_inner_size(&self, size: impl Into<Size>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetInnerSize {
window: self.inner.clone(),
size: size.into(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_min_inner_size(&self, size: impl Into<Option<Size>>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetMinInnerSize {
window: self.inner.clone(),
size: size.into(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_max_inner_size(&self, size: impl Into<Option<Size>>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetMaxInnerSize {
window: self.inner.clone(),
size: size.into(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::ResizeIncrements {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_resize_increments(&self, size: impl Into<Option<Size>>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetResizeIncrements {
window: self.inner.clone(),
size: size.into(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_title(&self, title: impl Into<String>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetTitle {
window: self.inner.clone(),
title: title.into(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_visible(&self, visible: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetVisible {
window: self.inner.clone(),
visible,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn is_visible(&self) -> Option<bool> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Visible {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_transparent(&self, transparent: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetTransparent {
window: self.inner.clone(),
transparent,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_resizable(&self, resizable: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetResizable {
window: self.inner.clone(),
resizable,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn is_resizable(&self) -> bool {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Resizable {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_minimized(&self, minimized: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetMinimized {
window: self.inner.clone(),
minimized,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn is_minimized(&self) -> Option<bool> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Minimized {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_maximized(&self, maximized: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetMaximized {
window: self.inner.clone(),
maximized,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn is_maximized(&self) -> bool {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Maximized {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetFullscreen {
window: self.inner.clone(),
fullscreen,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn fullscreen(&self) -> Option<Fullscreen> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Fullscreen {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_decorations(&self, decorations: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetDecorated {
window: self.inner.clone(),
decorated: decorations,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn is_decorated(&self) -> bool {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Decorated {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_window_level(&self, level: WindowLevel) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetWindowLevel {
window: self.inner.clone(),
level,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_window_icon(&self, icon: Option<Icon>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetWindowIcon {
window: self.inner.clone(),
icon,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_ime_position(&self, posn: impl Into<Position>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetImePosition {
window: self.inner.clone(),
position: posn.into(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_ime_allowed(&self, allowed: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetImeAllowed {
window: self.inner.clone(),
allowed,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_ime_purpose(&self, purpose: ImePurpose) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetImePurpose {
window: self.inner.clone(),
purpose,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn focus_window(&self) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::FocusWindow {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn is_focused(&self) -> bool {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Focused {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::RequestUserAttention {
window: self.inner.clone(),
request_type,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_theme(&self, theme: Option<Theme>) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetTheme {
window: self.inner.clone(),
theme,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn theme(&self) -> Option<Theme> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Theme {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_content_protected(&self, protected: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetProtectedContent {
window: self.inner.clone(),
protected,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn title(&self) -> String {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::Title {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_cursor_icon(&self, icon: CursorIcon) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetCursorIcon {
window: self.inner.clone(),
icon,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_cursor_position(
&self,
posn: impl Into<Position>,
) -> Result<(), ExternalError> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetCursorPosition {
window: self.inner.clone(),
position: posn.into(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetCursorGrab {
window: self.inner.clone(),
mode,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_cursor_visible(&self, visible: bool) {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetCursorVisible {
window: self.inner.clone(),
visible,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn drag_window(&self) -> Result<(), ExternalError> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::DragWindow {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
pub async fn drag_resize_window(
&self,
direction: ResizeDirection,
) -> Result<(), ExternalError> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::DragResizeWindow {
window: self.inner.clone(),
direction,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn set_cursor_hittest(&self, hit_test: bool) -> Result<(), ExternalError> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::SetCursorHitTest {
window: self.inner.clone(),
hit_test,
waker: tx,
})
.await;
rx.recv().await
}
pub async fn current_monitor(&self) -> Option<MonitorHandle> {
let (tx, rx) = oneoff();
self.reactor
.push_event_loop_op(EventLoopOp::CurrentMonitor {
window: self.inner.clone(),
waker: tx,
})
.await;
rx.recv().await
}
}
impl<TS: ThreadSafety> Window<TS> {
pub fn redraw_requested(&self) -> &Handler<(), TS> {
&self.registration.redraw_requested
}
pub fn close_requested(&self) -> &Handler<(), TS> {
&self.registration.close_requested
}
pub fn resized(&self) -> &Handler<PhysicalSize<u32>, TS> {
&self.registration.resized
}
pub fn moved(&self) -> &Handler<PhysicalPosition<i32>, TS> {
&self.registration.moved
}
pub fn destroyed(&self) -> &Handler<(), TS> {
&self.registration.destroyed
}
pub fn focused(&self) -> &Handler<bool, TS> {
&self.registration.focused
}
pub fn keyboard_input(&self) -> &Handler<crate::event::KeyboardInput, TS> {
&self.registration.keyboard_input
}
pub fn modifiers_changed(&self) -> &Handler<crate::event::ModifiersState, TS> {
&self.registration.modifiers_changed
}
pub fn received_character(&self) -> &Handler<char, TS> {
&self.registration.received_character
}
pub fn ime(&self) -> &Handler<crate::event::Ime, TS> {
&self.registration.ime
}
pub fn cursor_moved(&self) -> &Handler<crate::event::CursorMoved, TS> {
&self.registration.cursor_moved
}
pub fn cursor_entered(&self) -> &Handler<DeviceId, TS> {
&self.registration.cursor_entered
}
pub fn cursor_left(&self) -> &Handler<DeviceId, TS> {
&self.registration.cursor_left
}
pub fn mouse_wheel(&self) -> &Handler<crate::event::MouseWheel, TS> {
&self.registration.mouse_wheel
}
pub fn mouse_input(&self) -> &Handler<crate::event::MouseInput, TS> {
&self.registration.mouse_input
}
pub fn touchpad_magnify(&self) -> &Handler<crate::event::TouchpadMagnify, TS> {
&self.registration.touchpad_magnify
}
pub fn touchpad_pressure(&self) -> &Handler<crate::event::TouchpadPressure, TS> {
&self.registration.touchpad_pressure
}
pub fn touch(&self) -> &Handler<crate::event::Touch, TS> {
&self.registration.touch
}
pub fn scale_factor_changed(&self) -> &Handler<crate::event::ScaleFactor, TS> {
&self.registration.scale_factor_changed
}
pub fn touchpad_rotate(&self) -> &Handler<crate::event::TouchpadRotate, TS> {
&self.registration.touchpad_rotate
}
pub fn smart_magnify(&self) -> &Handler<DeviceId, TS> {
&self.registration.smart_magnify
}
pub fn axis_motion(&self) -> &Handler<crate::event::AxisMotion, TS> {
&self.registration.axis_motion
}
pub fn theme_changed(&self) -> &Handler<Theme, TS> {
&self.registration.theme_changed
}
pub fn occluded(&self) -> &Handler<bool, TS> {
&self.registration.occluded
}
}