Compare commits

..

1 Commits

Author SHA1 Message Date
Mads Marquart
ac0f918500 Add more specific error RequestIgnored 2024-02-10 10:26:28 +01:00
18 changed files with 1607 additions and 1899 deletions

View File

@@ -89,7 +89,7 @@ jobs:
- name: Generate lockfile - name: Generate lockfile
# Also updates the crates.io index # Also updates the crates.io index
run: cargo generate-lockfile && cargo update -p ahash --precise 0.8.7 run: cargo generate-lockfile
- name: Install GCC Multilib - name: Install GCC Multilib
if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686') if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')

View File

@@ -11,7 +11,7 @@ Unreleased` header.
# Unreleased # Unreleased
- On X11, don't require XIM to run. - **Breaking:** Use `RequestIgnored` as the error type in `InnerSizeWriter::request_inner_size`.
- Fix compatibility with 32-bit platforms without 64-bit atomics. - Fix compatibility with 32-bit platforms without 64-bit atomics.
- On X11, fix swapped instance and general class names. - On X11, fix swapped instance and general class names.
- **Breaking:** Removed unnecessary generic parameter `T` from `EventLoopWindowTarget`. - **Breaking:** Removed unnecessary generic parameter `T` from `EventLoopWindowTarget`.
@@ -54,22 +54,6 @@ Unreleased` header.
- On Orbital, fix `logical_key` and `text` not reported in `KeyEvent`. - On Orbital, fix `logical_key` and `text` not reported in `KeyEvent`.
- On Orbital, implement `KeyEventExtModifierSupplement`. - On Orbital, implement `KeyEventExtModifierSupplement`.
- On Orbital, map keys to `NamedKey` when possible. - On Orbital, map keys to `NamedKey` when possible.
- On Orbital, implement `set_cursor_grab`.
- On Orbital, implement `set_cursor_visible`.
- On Orbital, implement `drag_window`.
- On Orbital, implement `drag_resize_window`.
- On Orbital, implement `set_transparent`.
- On Orbital, implement `set_visible`.
- On Orbital, implement `is_visible`.
- On Orbital, implement `set_resizable`.
- On Orbital, implement `is_resizable`.
- On Orbital, implement `set_maximized`.
- On Orbital, implement `is_maximized`.
- On Orbital, implement `set_decorations`.
- On Orbital, implement `is_decorated`.
- On Orbital, implement `set_window_level`.
- On Orbital, emit `DeviceEvent::MouseMotion`.
- On Wayland, fix title in CSD not updated from `AboutToWait`.
# 0.29.10 # 0.29.10

View File

@@ -32,6 +32,8 @@
//! //!
//! [`EventLoop::run(...)`]: crate::event_loop::EventLoop::run //! [`EventLoop::run(...)`]: crate::event_loop::EventLoop::run
//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil //! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
use std::error::Error;
use std::fmt;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Mutex, Weak}; use std::sync::{Mutex, Weak};
#[cfg(not(web_platform))] #[cfg(not(web_platform))]
@@ -43,7 +45,6 @@ use smol_str::SmolStr;
#[cfg(web_platform)] #[cfg(web_platform)]
use web_time::Instant; use web_time::Instant;
use crate::error::ExternalError;
#[cfg(doc)] #[cfg(doc)]
use crate::window::Window; use crate::window::Window;
use crate::{ use crate::{
@@ -536,8 +537,9 @@ pub enum WindowEvent {
/// * Changing the display's scale factor (e.g. in Control Panel on Windows). /// * Changing the display's scale factor (e.g. in Control Panel on Windows).
/// * Moving the window to a display with a different scale factor. /// * Moving the window to a display with a different scale factor.
/// ///
/// To update the window size, use the provided [`InnerSizeWriter`] handle. By default, the window is /// After this event callback has been processed, the window will be resized to whatever value
/// resized to the value suggested by the OS, but it can be changed to any value. /// is pointed to by the `new_inner_size` reference. By default, this will contain the size suggested
/// by the OS, but it can be changed to any value.
/// ///
/// For more information about DPI in general, see the [`dpi`](crate::dpi) module. /// For more information about DPI in general, see the [`dpi`](crate::dpi) module.
ScaleFactorChanged { ScaleFactorChanged {
@@ -1125,16 +1127,23 @@ impl InnerSizeWriter {
Self { new_inner_size } Self { new_inner_size }
} }
/// Try to request inner size which will be set synchroniously on the window. /// Try to request a new inner size which will be set synchronously on the
/// window.
///
///
/// # Errors
///
/// This method returns an error when the request was ignored because it
/// was done asynchronously, outside the event loop callback.
pub fn request_inner_size( pub fn request_inner_size(
&mut self, &mut self,
new_inner_size: PhysicalSize<u32>, new_inner_size: PhysicalSize<u32>,
) -> Result<(), ExternalError> { ) -> Result<(), RequestIgnored> {
if let Some(inner) = self.new_inner_size.upgrade() { if let Some(inner) = self.new_inner_size.upgrade() {
*inner.lock().unwrap() = new_inner_size; *inner.lock().unwrap() = new_inner_size;
Ok(()) Ok(())
} else { } else {
Err(ExternalError::Ignored) Err(RequestIgnored { _priv: () })
} }
} }
} }
@@ -1145,6 +1154,22 @@ impl PartialEq for InnerSizeWriter {
} }
} }
/// The request to change the inner size synchronously was ignored.
///
/// See [`InnerSizeWriter::request_inner_size`] for details.
#[derive(Debug, Clone)] // Explicitly not other traits, in case we want to extend it in the future
pub struct RequestIgnored {
_priv: (),
}
impl fmt::Display for RequestIgnored {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("the request to change the inner size was ignored")
}
}
impl Error for RequestIgnored {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::event; use crate::event;

View File

@@ -498,7 +498,7 @@ impl<'a> KeyEventResults<'a> {
} }
} }
fn physical_key(&self) -> PhysicalKey { fn physical_key(&mut self) -> PhysicalKey {
keymap::raw_keycode_to_physicalkey(self.keycode) keymap::raw_keycode_to_physicalkey(self.keycode)
} }
@@ -553,7 +553,6 @@ impl<'a> KeyEventResults<'a> {
} else { } else {
0 0
}; };
self.keysym_to_key(keysym) self.keysym_to_key(keysym)
.unwrap_or_else(|(key, location)| { .unwrap_or_else(|(key, location)| {
( (
@@ -566,7 +565,7 @@ impl<'a> KeyEventResults<'a> {
}) })
} }
fn keysym_to_key(&self, keysym: u32) -> Result<(Key, KeyLocation), (Key, KeyLocation)> { fn keysym_to_key(&mut self, keysym: u32) -> Result<(Key, KeyLocation), (Key, KeyLocation)> {
let location = super::keymap::keysym_location(keysym); let location = super::keymap::keysym_location(keysym);
let key = super::keymap::keysym_to_key(keysym); let key = super::keymap::keysym_to_key(keysym);
if matches!(key, Key::Unidentified(_)) { if matches!(key, Key::Unidentified(_)) {

View File

@@ -940,12 +940,10 @@ impl EventLoopWindowTarget {
} }
} }
#[allow(dead_code)]
fn set_exit_code(&self, code: i32) { fn set_exit_code(&self, code: i32) {
x11_or_wayland!(match self; Self(evlp) => evlp.set_exit_code(code)) x11_or_wayland!(match self; Self(evlp) => evlp.set_exit_code(code))
} }
#[allow(dead_code)]
fn exit_code(&self) -> Option<i32> { fn exit_code(&self) -> Option<i32> {
x11_or_wayland!(match self; Self(evlp) => evlp.exit_code()) x11_or_wayland!(match self; Self(evlp) => evlp.exit_code())
} }

View File

@@ -461,19 +461,19 @@ impl<T: 'static> EventLoop<T> {
window_ids.extend(state.window_requests.get_mut().keys()); window_ids.extend(state.window_requests.get_mut().keys());
}); });
for window_id in window_ids.iter() { for window_id in window_ids.drain(..) {
let event = self.with_state(|state| { let event = self.with_state(|state| {
let window_requests = state.window_requests.get_mut(); let window_requests = state.window_requests.get_mut();
if window_requests.get(window_id).unwrap().take_closed() { if window_requests.get(&window_id).unwrap().take_closed() {
mem::drop(window_requests.remove(window_id)); mem::drop(window_requests.remove(&window_id));
mem::drop(state.windows.get_mut().remove(window_id)); mem::drop(state.windows.get_mut().remove(&window_id));
return Some(WindowEvent::Destroyed); return Some(WindowEvent::Destroyed);
} }
let mut window = state let mut window = state
.windows .windows
.get_mut() .get_mut()
.get_mut(window_id) .get_mut(&window_id)
.unwrap() .unwrap()
.lock() .lock()
.unwrap(); .unwrap();
@@ -485,7 +485,7 @@ impl<T: 'static> EventLoop<T> {
// Reset the frame callbacks state. // Reset the frame callbacks state.
window.frame_callback_reset(); window.frame_callback_reset();
let mut redraw_requested = window_requests let mut redraw_requested = window_requests
.get(window_id) .get(&window_id)
.unwrap() .unwrap()
.take_redraw_requested(); .take_redraw_requested();
@@ -498,7 +498,7 @@ impl<T: 'static> EventLoop<T> {
if let Some(event) = event { if let Some(event) = event {
callback( callback(
Event::WindowEvent { Event::WindowEvent {
window_id: crate::window::WindowId(*window_id), window_id: crate::window::WindowId(window_id),
event, event,
}, },
&self.window_target, &self.window_target,
@@ -514,42 +514,6 @@ impl<T: 'static> EventLoop<T> {
// This is always the last event we dispatch before poll again // This is always the last event we dispatch before poll again
callback(Event::AboutToWait, &self.window_target); callback(Event::AboutToWait, &self.window_target);
// Update the window frames and schedule redraws.
let mut wake_up = false;
for window_id in window_ids.drain(..) {
wake_up |= self.with_state(|state| match state.windows.get_mut().get_mut(&window_id) {
Some(window) => {
let refresh = window.lock().unwrap().refresh_frame();
if refresh {
state
.window_requests
.get_mut()
.get_mut(&window_id)
.unwrap()
.redraw_requested
.store(true, Ordering::Relaxed);
}
refresh
}
None => false,
});
}
// Wakeup event loop if needed.
//
// If the user draws from the `AboutToWait` this is likely not required, however
// we can't do much about it.
if wake_up {
match &self.window_target.p {
PlatformEventLoopWindowTarget::Wayland(window_target) => {
window_target.event_loop_awakener.ping();
}
#[cfg(x11_platform)]
PlatformEventLoopWindowTarget::X(_) => unreachable!(),
}
}
std::mem::swap(&mut self.compositor_updates, &mut compositor_updates); std::mem::swap(&mut self.compositor_updates, &mut compositor_updates);
std::mem::swap(&mut self.buffer_sink, &mut buffer_sink); std::mem::swap(&mut self.buffer_sink, &mut buffer_sink);
std::mem::swap(&mut self.window_ids, &mut window_ids); std::mem::swap(&mut self.window_ids, &mut window_ids);

View File

@@ -6,7 +6,7 @@ macro_rules! atom_manager {
($($name:ident $(:$lit:literal)?),*) => { ($($name:ident $(:$lit:literal)?),*) => {
x11rb::atom_manager! { x11rb::atom_manager! {
/// The atoms used by `winit` /// The atoms used by `winit`
pub Atoms: AtomsCookie { pub(crate) Atoms: AtomsCookie {
$($name $(:$lit)?,)* $($name $(:$lit)?,)*
} }
} }
@@ -14,7 +14,7 @@ macro_rules! atom_manager {
/// Indices into the `Atoms` struct. /// Indices into the `Atoms` struct.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub enum AtomName { pub(crate) enum AtomName {
$($name,)* $($name,)*
} }

View File

@@ -41,7 +41,7 @@ impl From<io::Error> for DndDataParseError {
} }
} }
pub struct Dnd { pub(crate) struct Dnd {
xconn: Arc<XConnection>, xconn: Arc<XConnection>,
// Populated by XdndEnter event handler // Populated by XdndEnter event handler
pub version: Option<c_long>, pub version: Option<c_long>,

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +1,72 @@
#![cfg(x11_platform)] #![cfg(x11_platform)]
use std::cell::{Cell, RefCell}; mod activation;
use std::collections::{HashMap, HashSet}; mod atoms;
use std::ffi::CStr; mod dnd;
use std::fmt; mod event_processor;
use std::marker::PhantomData; pub mod ffi;
use std::mem::MaybeUninit; mod ime;
use std::ops::Deref; mod monitor;
use std::os::raw::*; pub mod util;
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; mod window;
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError}; mod xdisplay;
use std::sync::{Arc, Weak}; mod xsettings;
use std::time::{Duration, Instant};
use std::{ptr, slice, str}; pub(crate) use self::{
monitor::{MonitorHandle, VideoModeHandle},
window::UnownedWindow,
xdisplay::{XConnection, XError, XNotSupported},
};
use calloop::generic::Generic; use calloop::generic::Generic;
use calloop::EventLoop as Loop; use calloop::EventLoop as Loop;
use calloop::{ping::Ping, Readiness}; use calloop::{ping::Ping, Readiness};
use libc::{self, setlocale, LC_CTYPE};
use log::warn; use log::warn;
use x11rb::connection::RequestConnection; use std::{
use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError}; cell::{Cell, RefCell},
use x11rb::protocol::xinput::{self, ConnectionExt as _}; collections::{HashMap, HashSet},
use x11rb::protocol::xkb; ffi::CStr,
use x11rb::protocol::xproto::{self, ConnectionExt as _}; fmt,
use x11rb::x11_utils::X11Error as LogicalError; marker::PhantomData,
use x11rb::xcb_ffi::ReplyOrIdError; mem::MaybeUninit,
ops::Deref,
os::{
raw::*,
unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd},
},
ptr,
rc::Rc,
slice, str,
sync::mpsc::{Receiver, Sender, TryRecvError},
sync::{mpsc, Arc, Weak},
time::{Duration, Instant},
};
use libc::{self, setlocale, LC_CTYPE};
use atoms::*;
use x11rb::x11_utils::X11Error as LogicalError;
use x11rb::{
connection::RequestConnection,
protocol::{
xinput::{self, ConnectionExt as _},
xkb,
xproto::{self, ConnectionExt as _},
},
};
use x11rb::{
errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError},
xcb_ffi::ReplyOrIdError,
};
pub(super) use self::util::CustomCursor;
use self::{
dnd::{Dnd, DndState},
event_processor::EventProcessor,
ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender},
};
use super::{common::xkb_state::KbdState, ControlFlow, OsError}; use super::{common::xkb_state::KbdState, ControlFlow, OsError};
use crate::{ use crate::{
error::{EventLoopError, OsError as RootOsError}, error::{EventLoopError, OsError as RootOsError},
@@ -38,28 +77,6 @@ use crate::{
window::WindowAttributes, window::WindowAttributes,
}; };
mod activation;
mod atoms;
mod dnd;
mod event_processor;
pub mod ffi;
mod ime;
mod monitor;
mod util;
mod window;
mod xdisplay;
mod xsettings;
use atoms::*;
use dnd::{Dnd, DndState};
use event_processor::EventProcessor;
use ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender};
pub(crate) use monitor::{MonitorHandle, VideoModeHandle};
use window::UnownedWindow;
pub(crate) use xdisplay::{XConnection, XError, XNotSupported};
pub use util::CustomCursor;
// Xinput constants not defined in x11rb // Xinput constants not defined in x11rb
const ALL_DEVICES: u16 = 0; const ALL_DEVICES: u16 = 0;
const ALL_MASTER_DEVICES: u16 = 1; const ALL_MASTER_DEVICES: u16 = 1;
@@ -133,7 +150,7 @@ pub struct EventLoopWindowTarget {
control_flow: Cell<ControlFlow>, control_flow: Cell<ControlFlow>,
exit: Cell<Option<i32>>, exit: Cell<Option<i32>>,
root: xproto::Window, root: xproto::Window,
ime: Option<RefCell<Ime>>, ime: RefCell<Ime>,
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>, windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
redraw_sender: WakeSender<WindowId>, redraw_sender: WakeSender<WindowId>,
activation_sender: WakeSender<ActivationToken>, activation_sender: WakeSender<ActivationToken>,
@@ -149,6 +166,7 @@ pub struct EventLoop<T: 'static> {
user_receiver: PeekableReceiver<T>, user_receiver: PeekableReceiver<T>,
activation_receiver: PeekableReceiver<ActivationToken>, activation_receiver: PeekableReceiver<ActivationToken>,
user_sender: Sender<T>, user_sender: Sender<T>,
target: Rc<RootELW>,
/// The current state of the event loop. /// The current state of the event loop.
state: EventLoopState, state: EventLoopState,
@@ -209,15 +227,13 @@ impl<T: 'static> EventLoop<T> {
setlocale(LC_CTYPE, default_locale); setlocale(LC_CTYPE, default_locale);
} }
} }
let ime = RefCell::new({
let ime = Ime::new(Arc::clone(&xconn), ime_event_sender); let result = Ime::new(Arc::clone(&xconn), ime_event_sender);
if let Err(ImeCreationError::OpenFailure(state)) = ime.as_ref() { if let Err(ImeCreationError::OpenFailure(ref state)) = result {
warn!("Failed to open input method: {state:#?}"); panic!("Failed to open input method: {state:#?}");
} else if let Err(err) = ime.as_ref() { }
warn!("Failed to set input method destruction callback: {err:?}"); result.expect("Failed to set input method destruction callback")
} });
let ime = ime.ok().map(RefCell::new);
let randr_event_offset = xconn let randr_event_offset = xconn
.select_xrandr_input(root) .select_xrandr_input(root)
@@ -308,13 +324,13 @@ impl<T: 'static> EventLoop<T> {
// Set initial device event filter. // Set initial device event filter.
window_target.update_listen_device_events(true); window_target.update_listen_device_events(true);
let root_window_target = RootELW { let target = Rc::new(RootELW {
p: super::EventLoopWindowTarget::X(window_target), p: super::EventLoopWindowTarget::X(window_target),
_marker: PhantomData, _marker: PhantomData,
}; });
let event_processor = EventProcessor { let event_processor = EventProcessor {
target: root_window_target, target: target.clone(),
dnd, dnd,
devices: Default::default(), devices: Default::default(),
randr_event_offset, randr_event_offset,
@@ -333,9 +349,8 @@ impl<T: 'static> EventLoop<T> {
// Register for device hotplug events // Register for device hotplug events
// (The request buffer is flushed during `init_device`) // (The request buffer is flushed during `init_device`)
let xconn = &EventProcessor::window_target(&event_processor.target).xconn; get_xtarget(&target)
.xconn
xconn
.select_xinput_events( .select_xinput_events(
root, root,
ALL_DEVICES, ALL_DEVICES,
@@ -343,7 +358,8 @@ impl<T: 'static> EventLoop<T> {
) )
.expect_then_ignore_error("Failed to register for XInput2 device hotplug events"); .expect_then_ignore_error("Failed to register for XInput2 device hotplug events");
xconn get_xtarget(&target)
.xconn
.select_xkb_events( .select_xkb_events(
0x100, // Use the "core keyboard device" 0x100, // Use the "core keyboard device"
xkb::EventType::NEW_KEYBOARD_NOTIFY xkb::EventType::NEW_KEYBOARD_NOTIFY
@@ -363,6 +379,7 @@ impl<T: 'static> EventLoop<T> {
activation_receiver: PeekableReceiver::from_recv(activation_token_channel), activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
user_receiver: PeekableReceiver::from_recv(user_channel), user_receiver: PeekableReceiver::from_recv(user_channel),
user_sender, user_sender,
target,
state: EventLoopState { state: EventLoopState {
x11_readiness: Readiness::EMPTY, x11_readiness: Readiness::EMPTY,
}, },
@@ -379,7 +396,7 @@ impl<T: 'static> EventLoop<T> {
} }
pub(crate) fn window_target(&self) -> &RootELW { pub(crate) fn window_target(&self) -> &RootELW {
&self.event_processor.target &self.target
} }
pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError> pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
@@ -404,7 +421,7 @@ impl<T: 'static> EventLoop<T> {
// `run_on_demand` calls but if they have only just dropped their // `run_on_demand` calls but if they have only just dropped their
// windows we need to make sure those last requests are sent to the // windows we need to make sure those last requests are sent to the
// X Server. // X Server.
let wt = EventProcessor::window_target(&self.event_processor.target); let wt = get_xtarget(&self.target);
wt.x_connection().sync_with_server().map_err(|x_err| { wt.x_connection().sync_with_server().map_err(|x_err| {
EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err))))) EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err)))))
})?; })?;
@@ -527,12 +544,12 @@ impl<T: 'static> EventLoop<T> {
where where
F: FnMut(Event<T>, &RootELW), F: FnMut(Event<T>, &RootELW),
{ {
callback(Event::NewEvents(cause), &self.event_processor.target); callback(crate::event::Event::NewEvents(cause), &self.target);
// NB: For consistency all platforms must emit a 'resumed' event even though X11 // NB: For consistency all platforms must emit a 'resumed' event even though X11
// applications don't themselves have a formal suspend/resume lifecycle. // applications don't themselves have a formal suspend/resume lifecycle.
if cause == StartCause::Init { if cause == StartCause::Init {
callback(Event::Resumed, &self.event_processor.target); callback(crate::event::Event::Resumed, &self.target);
} }
// Process all pending events // Process all pending events
@@ -547,16 +564,16 @@ impl<T: 'static> EventLoop<T> {
}); });
match token { match token {
Some(Ok(token)) => { Some(Ok(token)) => callback(
let event = Event::WindowEvent { crate::event::Event::WindowEvent {
window_id: crate::window::WindowId(window_id), window_id: crate::window::WindowId(window_id),
event: WindowEvent::ActivationTokenDone { event: crate::event::WindowEvent::ActivationTokenDone {
serial, serial,
token: crate::window::ActivationToken::_new(token), token: crate::window::ActivationToken::_new(token),
}, },
}; },
callback(event, &self.event_processor.target) &self.target,
} ),
Some(Err(e)) => { Some(Err(e)) => {
log::error!("Failed to get activation token: {}", e); log::error!("Failed to get activation token: {}", e);
} }
@@ -567,7 +584,7 @@ impl<T: 'static> EventLoop<T> {
// Empty the user event buffer // Empty the user event buffer
{ {
while let Ok(event) = self.user_receiver.try_recv() { while let Ok(event) = self.user_receiver.try_recv() {
callback(Event::UserEvent(event), &self.event_processor.target); callback(crate::event::Event::UserEvent(event), &self.target);
} }
} }
@@ -586,14 +603,14 @@ impl<T: 'static> EventLoop<T> {
window_id, window_id,
event: WindowEvent::RedrawRequested, event: WindowEvent::RedrawRequested,
}, },
&self.event_processor.target, &self.target,
); );
} }
} }
// This is always the last event we dispatch before poll again // This is always the last event we dispatch before poll again
{ {
callback(Event::AboutToWait, &self.event_processor.target); callback(crate::event::Event::AboutToWait, &self.target);
} }
} }
@@ -601,44 +618,40 @@ impl<T: 'static> EventLoop<T> {
where where
F: FnMut(Event<T>, &RootELW), F: FnMut(Event<T>, &RootELW),
{ {
let target = &self.target;
let mut xev = MaybeUninit::uninit(); let mut xev = MaybeUninit::uninit();
let wt = get_xtarget(&self.target);
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } { while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
let mut xev = unsafe { xev.assume_init() }; let mut xev = unsafe { xev.assume_init() };
self.event_processor self.event_processor.process_event(&mut xev, |event| {
.process_event(&mut xev, |window_target, event| { if let Event::WindowEvent {
if let Event::WindowEvent { window_id: crate::window::WindowId(wid),
window_id: crate::window::WindowId(wid), event: WindowEvent::RedrawRequested,
event: WindowEvent::RedrawRequested, } = event
} = event {
{ wt.redraw_sender.send(wid).unwrap();
let window_target = EventProcessor::window_target(window_target); } else {
window_target.redraw_sender.send(wid).unwrap(); callback(event, target);
} else { }
callback(event, window_target); });
}
});
} }
} }
fn control_flow(&self) -> ControlFlow { fn control_flow(&self) -> ControlFlow {
let window_target = EventProcessor::window_target(&self.event_processor.target); self.target.p.control_flow()
window_target.control_flow()
} }
fn exiting(&self) -> bool { fn exiting(&self) -> bool {
let window_target = EventProcessor::window_target(&self.event_processor.target); self.target.p.exiting()
window_target.exiting()
} }
fn set_exit_code(&self, code: i32) { fn set_exit_code(&self, code: i32) {
let window_target = EventProcessor::window_target(&self.event_processor.target); self.target.p.set_exit_code(code)
window_target.set_exit_code(code);
} }
fn exit_code(&self) -> Option<i32> { fn exit_code(&self) -> Option<i32> {
let window_target = EventProcessor::window_target(&self.event_processor.target); self.target.p.exit_code()
window_target.exit_code()
} }
} }
@@ -654,6 +667,14 @@ impl<T> AsRawFd for EventLoop<T> {
} }
} }
pub(crate) fn get_xtarget(target: &RootELW) -> &EventLoopWindowTarget {
match target.p {
super::EventLoopWindowTarget::X(ref target) => target,
#[cfg(wayland_platform)]
_ => unreachable!(),
}
}
impl EventLoopWindowTarget { impl EventLoopWindowTarget {
/// Returns the `XConnection` of this events loop. /// Returns the `XConnection` of this events loop.
#[inline] #[inline]
@@ -1027,7 +1048,7 @@ fn mkdid(w: xinput::DeviceId) -> crate::event::DeviceId {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Device { struct Device {
_name: String, _name: String,
scroll_axes: Vec<(i32, ScrollAxis)>, scroll_axes: Vec<(i32, ScrollAxis)>,
// For master devices, this is the paired device (pointer <-> keyboard). // For master devices, this is the paired device (pointer <-> keyboard).

View File

@@ -324,7 +324,7 @@ impl XConnection {
} }
} }
pub struct ScreenResources { pub(crate) struct ScreenResources {
/// List of attached modes. /// List of attached modes.
modes: Vec<randr::ModeInfo>, modes: Vec<randr::ModeInfo>,

View File

@@ -39,13 +39,11 @@ impl XConnection {
// Retrieve DPI from Xft.dpi property // Retrieve DPI from Xft.dpi property
pub fn get_xft_dpi(&self) -> Option<f64> { pub fn get_xft_dpi(&self) -> Option<f64> {
// Try to get it from XSETTINGS first. // Try to get it from XSETTINGS first.
if let Some(xsettings_screen) = self.xsettings_screen() { match self.xsettings_dpi() {
match self.xsettings_dpi(xsettings_screen) { Ok(Some(dpi)) => return Some(dpi),
Ok(Some(dpi)) => return Some(dpi), Ok(None) => {}
Ok(None) => {} Err(err) => {
Err(err) => { log::warn!("failed to fetch XSettings: {err}");
log::warn!("failed to fetch XSettings: {err}");
}
} }
} }

View File

@@ -123,7 +123,7 @@ impl SharedState {
unsafe impl Send for UnownedWindow {} unsafe impl Send for UnownedWindow {}
unsafe impl Sync for UnownedWindow {} unsafe impl Sync for UnownedWindow {}
pub struct UnownedWindow { pub(crate) struct UnownedWindow {
pub(crate) xconn: Arc<XConnection>, // never changes pub(crate) xconn: Arc<XConnection>, // never changes
xwindow: xproto::Window, // never changes xwindow: xproto::Window, // never changes
#[allow(dead_code)] #[allow(dead_code)]
@@ -555,9 +555,9 @@ impl UnownedWindow {
leap!(xconn.select_xinput_events(window.xwindow, super::ALL_MASTER_DEVICES, mask)) leap!(xconn.select_xinput_events(window.xwindow, super::ALL_MASTER_DEVICES, mask))
.ignore_error(); .ignore_error();
// Try to create input context for the window. {
if let Some(ime) = event_loop.ime.as_ref() { let result = event_loop
let result = ime .ime
.borrow_mut() .borrow_mut()
.create_context(window.xwindow as ffi::Window, false); .create_context(window.xwindow as ffi::Window, false);
leap!(result); leap!(result);

View File

@@ -22,7 +22,7 @@ use x11rb::{
}; };
/// A connection to an X server. /// A connection to an X server.
pub struct XConnection { pub(crate) struct XConnection {
pub xlib: ffi::Xlib, pub xlib: ffi::Xlib,
pub xcursor: ffi::Xcursor, pub xcursor: ffi::Xcursor,
@@ -59,7 +59,7 @@ pub struct XConnection {
randr_version: (u32, u32), randr_version: (u32, u32),
/// Atom for the XSettings screen. /// Atom for the XSettings screen.
xsettings_screen: Option<xproto::Atom>, xsettings_screen: xproto::Atom,
pub latest_error: Mutex<Option<XError>>, pub latest_error: Mutex<Option<XError>>,
pub cursor_cache: Mutex<HashMap<Option<CursorIcon>, ffi::Cursor>>, pub cursor_cache: Mutex<HashMap<Option<CursorIcon>, ffi::Cursor>>,
@@ -108,6 +108,21 @@ impl XConnection {
// Get the default screen. // Get the default screen.
let default_screen = unsafe { (xlib.XDefaultScreen)(display) } as usize; let default_screen = unsafe { (xlib.XDefaultScreen)(display) } as usize;
// Fetch the _XSETTINGS_S[screen number] atom.
let xsettings_screen = xcb
.intern_atom(false, format!("_XSETTINGS_S{}", default_screen).as_bytes())
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?;
// Fetch the other atoms.
let atoms = Atoms::new(&xcb)
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?
.reply()
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?;
let xsettings_screen = xsettings_screen
.reply()
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?
.atom;
// Load the database. // Load the database.
let database = resource_manager::new_from_default(&xcb) let database = resource_manager::new_from_default(&xcb)
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?; .map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?;
@@ -119,16 +134,23 @@ impl XConnection {
.reply() .reply()
.expect("failed to query XRandR version"); .expect("failed to query XRandR version");
let xsettings_screen = Self::new_xsettings_screen(&xcb, default_screen); // Get PropertyNotify events from the XSETTINGS window.
if xsettings_screen.is_none() { // TODO: The XSETTINGS window here can change. In the future, listen for DestroyNotify on this window
log::warn!("error setting XSETTINGS; Xft options won't reload automatically") // in order to accomodate for a changed window here.
} let selector_window = xcb
.get_selection_owner(xsettings_screen)
// Fetch atoms.
let atoms = Atoms::new(&xcb)
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))? .map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?
.reply() .reply()
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?; .map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?
.owner;
xcb.change_window_attributes(
selector_window,
&xproto::ChangeWindowAttributesAux::new()
.event_mask(xproto::EventMask::PROPERTY_CHANGE),
)
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?
.check()
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?;
Ok(XConnection { Ok(XConnection {
xlib, xlib,
@@ -148,37 +170,6 @@ impl XConnection {
}) })
} }
fn new_xsettings_screen(xcb: &XCBConnection, default_screen: usize) -> Option<xproto::Atom> {
// Fetch the _XSETTINGS_S[screen number] atom.
let xsettings_screen = xcb
.intern_atom(false, format!("_XSETTINGS_S{}", default_screen).as_bytes())
.ok()?
.reply()
.ok()?
.atom;
// Get PropertyNotify events from the XSETTINGS window.
// TODO: The XSETTINGS window here can change. In the future, listen for DestroyNotify on this window
// in order to accomodate for a changed window here.
let selector_window = xcb
.get_selection_owner(xsettings_screen)
.ok()?
.reply()
.ok()?
.owner;
xcb.change_window_attributes(
selector_window,
&xproto::ChangeWindowAttributesAux::new()
.event_mask(xproto::EventMask::PROPERTY_CHANGE),
)
.ok()?
.check()
.ok()?;
Some(xsettings_screen)
}
/// Checks whether an error has been triggered by the previous function calls. /// Checks whether an error has been triggered by the previous function calls.
#[inline] #[inline]
pub fn check_errors(&self) -> Result<(), XError> { pub fn check_errors(&self) -> Result<(), XError> {
@@ -267,7 +258,7 @@ impl XConnection {
/// Get the atom for Xsettings. /// Get the atom for Xsettings.
#[inline] #[inline]
pub fn xsettings_screen(&self) -> Option<xproto::Atom> { pub fn xsettings_screen(&self) -> u32 {
self.xsettings_screen self.xsettings_screen
} }
} }
@@ -309,7 +300,7 @@ impl fmt::Display for XError {
/// Error returned if this system doesn't have XLib or can't create an X connection. /// Error returned if this system doesn't have XLib or can't create an X connection.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum XNotSupported { pub(crate) enum XNotSupported {
/// Failed to load one or several shared libraries. /// Failed to load one or several shared libraries.
LibraryOpenError(ffi::OpenError), LibraryOpenError(ffi::OpenError),

View File

@@ -4,13 +4,13 @@
//! //!
//! [here]: https://github.com/derat/xsettingsd //! [here]: https://github.com/derat/xsettingsd
use super::{atoms::*, XConnection};
use x11rb::protocol::xproto::ConnectionExt;
use std::iter; use std::iter;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use x11rb::protocol::xproto::{self, ConnectionExt};
use super::{atoms::*, XConnection};
type Result<T> = core::result::Result<T, ParserError>; type Result<T> = core::result::Result<T, ParserError>;
const DPI_NAME: &[u8] = b"Xft/DPI"; const DPI_NAME: &[u8] = b"Xft/DPI";
@@ -20,16 +20,13 @@ const BIG_ENDIAN: u8 = b'B';
impl XConnection { impl XConnection {
/// Get the DPI from XSettings. /// Get the DPI from XSettings.
pub(crate) fn xsettings_dpi( pub(crate) fn xsettings_dpi(&self) -> core::result::Result<Option<f64>, super::X11Error> {
&self,
xsettings_screen: xproto::Atom,
) -> core::result::Result<Option<f64>, super::X11Error> {
let atoms = self.atoms(); let atoms = self.atoms();
// Get the current owner of the screen's settings. // Get the current owner of the screen's settings.
let owner = self let owner = self
.xcb_connection() .xcb_connection()
.get_selection_owner(xsettings_screen)? .get_selection_owner(self.xsettings_screen())?
.reply()?; .reply()?;
// Read the _XSETTINGS_SETTINGS property. // Read the _XSETTINGS_SETTINGS property.

View File

@@ -9,8 +9,8 @@ use std::{
use bitflags::bitflags; use bitflags::bitflags;
use orbclient::{ use orbclient::{
ButtonEvent, EventOption, FocusEvent, HoverEvent, KeyEvent, MouseEvent, MouseRelativeEvent, ButtonEvent, EventOption, FocusEvent, HoverEvent, KeyEvent, MouseEvent, MoveEvent, QuitEvent,
MoveEvent, QuitEvent, ResizeEvent, ScrollEvent, TextInputEvent, ResizeEvent, ScrollEvent, TextInputEvent,
}; };
use smol_str::SmolStr; use smol_str::SmolStr;
@@ -457,14 +457,6 @@ impl<T: 'static> EventLoop<T> {
}, },
}); });
} }
EventOption::MouseRelative(MouseRelativeEvent { dx, dy }) => {
event_handler(event::Event::DeviceEvent {
device_id: event::DeviceId(DeviceId),
event: event::DeviceEvent::MouseMotion {
delta: (dx as f64, dy as f64),
},
});
}
EventOption::Button(ButtonEvent { EventOption::Button(ButtonEvent {
left, left,
middle, middle,
@@ -518,7 +510,7 @@ impl<T: 'static> EventLoop<T> {
// Acknowledge resize after event loop. // Acknowledge resize after event loop.
event_state.resize_opt = Some((width, height)); event_state.resize_opt = Some((width, height));
} }
//TODO: Screen, Clipboard, Drop //TODO: Clipboard
EventOption::Hover(HoverEvent { entered }) => { EventOption::Hover(HoverEvent { entered }) => {
if entered { if entered {
event_handler(event::Event::WindowEvent { event_handler(event::Event::WindowEvent {

View File

@@ -13,8 +13,7 @@ use crate::{
}; };
use super::{ use super::{
EventLoopWindowTarget, MonitorHandle, OsError, RedoxSocket, TimeSocket, WindowId, EventLoopWindowTarget, MonitorHandle, RedoxSocket, TimeSocket, WindowId, WindowProperties,
WindowProperties,
}; };
// These values match the values uses in the `window_new` function in orbital: // These values match the values uses in the `window_new` function in orbital:
@@ -22,9 +21,7 @@ use super::{
const ORBITAL_FLAG_ASYNC: char = 'a'; const ORBITAL_FLAG_ASYNC: char = 'a';
const ORBITAL_FLAG_BACK: char = 'b'; const ORBITAL_FLAG_BACK: char = 'b';
const ORBITAL_FLAG_FRONT: char = 'f'; const ORBITAL_FLAG_FRONT: char = 'f';
const ORBITAL_FLAG_HIDDEN: char = 'h';
const ORBITAL_FLAG_BORDERLESS: char = 'l'; const ORBITAL_FLAG_BORDERLESS: char = 'l';
const ORBITAL_FLAG_MAXIMIZED: char = 'm';
const ORBITAL_FLAG_RESIZABLE: char = 'r'; const ORBITAL_FLAG_RESIZABLE: char = 'r';
const ORBITAL_FLAG_TRANSPARENT: char = 't'; const ORBITAL_FLAG_TRANSPARENT: char = 't';
@@ -60,15 +57,11 @@ impl Window {
// Async by default. // Async by default.
let mut flag_str = ORBITAL_FLAG_ASYNC.to_string(); let mut flag_str = ORBITAL_FLAG_ASYNC.to_string();
if attrs.maximized {
flag_str.push(ORBITAL_FLAG_MAXIMIZED);
}
if attrs.resizable { if attrs.resizable {
flag_str.push(ORBITAL_FLAG_RESIZABLE); flag_str.push(ORBITAL_FLAG_RESIZABLE);
} }
//TODO: fullscreen //TODO: maximized, fullscreen, visible
if attrs.transparent { if attrs.transparent {
flag_str.push(ORBITAL_FLAG_TRANSPARENT); flag_str.push(ORBITAL_FLAG_TRANSPARENT);
@@ -78,10 +71,6 @@ impl Window {
flag_str.push(ORBITAL_FLAG_BORDERLESS); flag_str.push(ORBITAL_FLAG_BORDERLESS);
} }
if !attrs.visible {
flag_str.push(ORBITAL_FLAG_HIDDEN);
}
match attrs.window_level { match attrs.window_level {
window::WindowLevel::AlwaysOnBottom => { window::WindowLevel::AlwaysOnBottom => {
flag_str.push(ORBITAL_FLAG_BACK); flag_str.push(ORBITAL_FLAG_BACK);
@@ -140,23 +129,6 @@ impl Window {
f(self) f(self)
} }
fn get_flag(&self, flag: char) -> Result<bool, error::ExternalError> {
let mut buf: [u8; 4096] = [0; 4096];
let path = self
.window_socket
.fpath(&mut buf)
.map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?;
let properties = WindowProperties::new(path);
Ok(properties.flags.contains(flag))
}
fn set_flag(&self, flag: char, value: bool) -> Result<(), error::ExternalError> {
self.window_socket
.write(format!("F,{flag},{}", if value { 1 } else { 0 }).as_bytes())
.map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?;
Ok(())
}
#[inline] #[inline]
pub fn id(&self) -> WindowId { pub fn id(&self) -> WindowId {
WindowId { WindowId {
@@ -282,21 +254,17 @@ impl Window {
} }
#[inline] #[inline]
pub fn set_transparent(&self, transparent: bool) { pub fn set_transparent(&self, _transparent: bool) {}
let _ = self.set_flag(ORBITAL_FLAG_TRANSPARENT, transparent);
}
#[inline] #[inline]
pub fn set_blur(&self, _blur: bool) {} pub fn set_blur(&self, _blur: bool) {}
#[inline] #[inline]
pub fn set_visible(&self, visible: bool) { pub fn set_visible(&self, _visibility: bool) {}
let _ = self.set_flag(ORBITAL_FLAG_HIDDEN, !visible);
}
#[inline] #[inline]
pub fn is_visible(&self) -> Option<bool> { pub fn is_visible(&self) -> Option<bool> {
Some(!self.get_flag(ORBITAL_FLAG_HIDDEN).unwrap_or(false)) None
} }
#[inline] #[inline]
@@ -308,13 +276,17 @@ impl Window {
pub fn set_resize_increments(&self, _increments: Option<Size>) {} pub fn set_resize_increments(&self, _increments: Option<Size>) {}
#[inline] #[inline]
pub fn set_resizable(&self, resizeable: bool) { pub fn set_resizable(&self, _resizeable: bool) {}
let _ = self.set_flag(ORBITAL_FLAG_RESIZABLE, resizeable);
}
#[inline] #[inline]
pub fn is_resizable(&self) -> bool { pub fn is_resizable(&self) -> bool {
self.get_flag(ORBITAL_FLAG_RESIZABLE).unwrap_or(false) let mut buf: [u8; 4096] = [0; 4096];
let path = self
.window_socket
.fpath(&mut buf)
.expect("failed to read properties");
let properties = WindowProperties::new(path);
properties.flags.contains(ORBITAL_FLAG_RESIZABLE)
} }
#[inline] #[inline]
@@ -326,13 +298,11 @@ impl Window {
} }
#[inline] #[inline]
pub fn set_maximized(&self, maximized: bool) { pub fn set_maximized(&self, _maximized: bool) {}
let _ = self.set_flag(ORBITAL_FLAG_MAXIMIZED, maximized);
}
#[inline] #[inline]
pub fn is_maximized(&self) -> bool { pub fn is_maximized(&self) -> bool {
self.get_flag(ORBITAL_FLAG_MAXIMIZED).unwrap_or(false) false
} }
#[inline] #[inline]
@@ -344,30 +314,21 @@ impl Window {
} }
#[inline] #[inline]
pub fn set_decorations(&self, decorations: bool) { pub fn set_decorations(&self, _decorations: bool) {}
let _ = self.set_flag(ORBITAL_FLAG_BORDERLESS, !decorations);
}
#[inline] #[inline]
pub fn is_decorated(&self) -> bool { pub fn is_decorated(&self) -> bool {
!self.get_flag(ORBITAL_FLAG_BORDERLESS).unwrap_or(false) let mut buf: [u8; 4096] = [0; 4096];
let path = self
.window_socket
.fpath(&mut buf)
.expect("failed to read properties");
let properties = WindowProperties::new(path);
!properties.flags.contains(ORBITAL_FLAG_BORDERLESS)
} }
#[inline] #[inline]
pub fn set_window_level(&self, level: window::WindowLevel) { pub fn set_window_level(&self, _level: window::WindowLevel) {}
match level {
window::WindowLevel::AlwaysOnBottom => {
let _ = self.set_flag(ORBITAL_FLAG_BACK, true);
}
window::WindowLevel::Normal => {
let _ = self.set_flag(ORBITAL_FLAG_BACK, false);
let _ = self.set_flag(ORBITAL_FLAG_FRONT, false);
}
window::WindowLevel::AlwaysOnTop => {
let _ = self.set_flag(ORBITAL_FLAG_FRONT, true);
}
}
}
#[inline] #[inline]
pub fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {} pub fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {}
@@ -398,58 +359,30 @@ impl Window {
} }
#[inline] #[inline]
pub fn set_cursor_grab( pub fn set_cursor_grab(&self, _: window::CursorGrabMode) -> Result<(), error::ExternalError> {
&self, Err(error::ExternalError::NotSupported(
mode: window::CursorGrabMode, error::NotSupportedError::new(),
) -> Result<(), error::ExternalError> { ))
let (grab, relative) = match mode {
window::CursorGrabMode::None => (false, false),
window::CursorGrabMode::Confined => (true, false),
window::CursorGrabMode::Locked => (true, true),
};
self.window_socket
.write(format!("M,G,{}", if grab { 1 } else { 0 }).as_bytes())
.map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?;
self.window_socket
.write(format!("M,R,{}", if relative { 1 } else { 0 }).as_bytes())
.map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?;
Ok(())
} }
#[inline] #[inline]
pub fn set_cursor_visible(&self, visible: bool) { pub fn set_cursor_visible(&self, _: bool) {}
let _ = self
.window_socket
.write(format!("M,C,{}", if visible { 1 } else { 0 }).as_bytes());
}
#[inline] #[inline]
pub fn drag_window(&self) -> Result<(), error::ExternalError> { pub fn drag_window(&self) -> Result<(), error::ExternalError> {
self.window_socket Err(error::ExternalError::NotSupported(
.write(b"D") error::NotSupportedError::new(),
.map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; ))
Ok(())
} }
#[inline] #[inline]
pub fn drag_resize_window( pub fn drag_resize_window(
&self, &self,
direction: window::ResizeDirection, _direction: window::ResizeDirection,
) -> Result<(), error::ExternalError> { ) -> Result<(), error::ExternalError> {
let arg = match direction { Err(error::ExternalError::NotSupported(
window::ResizeDirection::East => "R", error::NotSupportedError::new(),
window::ResizeDirection::North => "T", ))
window::ResizeDirection::NorthEast => "T,R",
window::ResizeDirection::NorthWest => "T,L",
window::ResizeDirection::South => "B",
window::ResizeDirection::SouthEast => "B,R",
window::ResizeDirection::SouthWest => "B,L",
window::ResizeDirection::West => "L",
};
self.window_socket
.write(format!("D,{}", arg).as_bytes())
.map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?;
Ok(())
} }
#[inline] #[inline]

View File

@@ -57,11 +57,8 @@ use serde::{Deserialize, Serialize};
/// ///
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **Web:** The window is represented by a `HTMLElementCanvas`, and cannot /// **Web:** The [`Window`], which is represented by a `HTMLElementCanvas`, can
/// currently be closed by dropping the [`Window`]. /// not be closed by dropping the [`Window`].
/// - **Android:** Each window is spawned inside its own process, and as such
/// Winit does not support multiple windows on Android. Create a new
/// activity instead.
pub struct Window { pub struct Window {
pub(crate) window: platform_impl::Window, pub(crate) window: platform_impl::Window,
} }
@@ -949,7 +946,7 @@ impl Window {
/// ///
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **Web / iOS / Android:** Unsupported. /// - **Web / iOS / Android / Orbital:** Unsupported.
/// - **X11:** Can only be set while building the window, with [`WindowBuilder::with_transparent`]. /// - **X11:** Can only be set while building the window, with [`WindowBuilder::with_transparent`].
#[inline] #[inline]
pub fn set_transparent(&self, transparent: bool) { pub fn set_transparent(&self, transparent: bool) {
@@ -1082,7 +1079,7 @@ impl Window {
/// ///
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **iOS / Android / Web:** Unsupported. /// - **iOS / Android / Web / Orbital:** Unsupported.
#[inline] #[inline]
pub fn set_maximized(&self, maximized: bool) { pub fn set_maximized(&self, maximized: bool) {
self.window self.window
@@ -1093,7 +1090,7 @@ impl Window {
/// ///
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **iOS / Android / Web:** Unsupported. /// - **iOS / Android / Web / Orbital:** Unsupported.
#[inline] #[inline]
pub fn is_maximized(&self) -> bool { pub fn is_maximized(&self) -> bool {
self.window.maybe_wait_on_main(|w| w.is_maximized()) self.window.maybe_wait_on_main(|w| w.is_maximized())
@@ -1453,7 +1450,7 @@ impl Window {
/// - **Wayland:** The cursor is only hidden within the confines of the window. /// - **Wayland:** The cursor is only hidden within the confines of the window.
/// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
/// outside of the window. /// outside of the window.
/// - **iOS / Android:** Unsupported. /// - **iOS / Android / Orbital:** Unsupported.
#[inline] #[inline]
pub fn set_cursor_visible(&self, visible: bool) { pub fn set_cursor_visible(&self, visible: bool) {
self.window self.window
@@ -1470,7 +1467,7 @@ impl Window {
/// - **X11:** Un-grabs the cursor. /// - **X11:** Un-grabs the cursor.
/// - **Wayland:** Requires the cursor to be inside the window to be dragged. /// - **Wayland:** Requires the cursor to be inside the window to be dragged.
/// - **macOS:** May prevent the button release event to be triggered. /// - **macOS:** May prevent the button release event to be triggered.
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
#[inline] #[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> { pub fn drag_window(&self) -> Result<(), ExternalError> {
self.window.maybe_wait_on_main(|w| w.drag_window()) self.window.maybe_wait_on_main(|w| w.drag_window())
@@ -1484,7 +1481,7 @@ impl Window {
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **macOS:** Always returns an [`ExternalError::NotSupported`] /// - **macOS:** Always returns an [`ExternalError::NotSupported`]
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
#[inline] #[inline]
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
self.window self.window
@@ -1645,7 +1642,7 @@ pub enum CursorGrabMode {
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **macOS:** Not implemented. Always returns [`ExternalError::NotSupported`] for now. /// - **macOS:** Not implemented. Always returns [`ExternalError::NotSupported`] for now.
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
Confined, Confined,
/// The cursor is locked inside the window area to the certain position. /// The cursor is locked inside the window area to the certain position.
@@ -1656,7 +1653,7 @@ pub enum CursorGrabMode {
/// ## Platform-specific /// ## Platform-specific
/// ///
/// - **X11 / Windows:** Not implemented. Always returns [`ExternalError::NotSupported`] for now. /// - **X11 / Windows:** Not implemented. Always returns [`ExternalError::NotSupported`] for now.
/// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`]. /// - **iOS / Android / Orbital:** Always returns an [`ExternalError::NotSupported`].
Locked, Locked,
} }