mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 22:53:15 -04:00
Compare commits
1 Commits
android-no
...
request-ig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac0f918500 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -89,7 +89,7 @@ jobs:
|
||||
|
||||
- name: Generate lockfile
|
||||
# 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
|
||||
if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')
|
||||
|
||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -11,7 +11,7 @@ Unreleased` header.
|
||||
|
||||
# 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.
|
||||
- On X11, fix swapped instance and general class names.
|
||||
- **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, implement `KeyEventExtModifierSupplement`.
|
||||
- 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
|
||||
|
||||
|
||||
37
src/event.rs
37
src/event.rs
@@ -32,6 +32,8 @@
|
||||
//!
|
||||
//! [`EventLoop::run(...)`]: crate::event_loop::EventLoop::run
|
||||
//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Mutex, Weak};
|
||||
#[cfg(not(web_platform))]
|
||||
@@ -43,7 +45,6 @@ use smol_str::SmolStr;
|
||||
#[cfg(web_platform)]
|
||||
use web_time::Instant;
|
||||
|
||||
use crate::error::ExternalError;
|
||||
#[cfg(doc)]
|
||||
use crate::window::Window;
|
||||
use crate::{
|
||||
@@ -536,8 +537,9 @@ pub enum WindowEvent {
|
||||
/// * Changing the display's scale factor (e.g. in Control Panel on Windows).
|
||||
/// * 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
|
||||
/// resized to the value suggested by the OS, but it can be changed to any value.
|
||||
/// After this event callback has been processed, the window will be resized to whatever 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.
|
||||
ScaleFactorChanged {
|
||||
@@ -1125,16 +1127,23 @@ impl InnerSizeWriter {
|
||||
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(
|
||||
&mut self,
|
||||
new_inner_size: PhysicalSize<u32>,
|
||||
) -> Result<(), ExternalError> {
|
||||
) -> Result<(), RequestIgnored> {
|
||||
if let Some(inner) = self.new_inner_size.upgrade() {
|
||||
*inner.lock().unwrap() = new_inner_size;
|
||||
Ok(())
|
||||
} 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)]
|
||||
mod tests {
|
||||
use crate::event;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -553,7 +553,6 @@ impl<'a> KeyEventResults<'a> {
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
self.keysym_to_key(keysym)
|
||||
.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 key = super::keymap::keysym_to_key(keysym);
|
||||
if matches!(key, Key::Unidentified(_)) {
|
||||
|
||||
@@ -940,12 +940,10 @@ impl EventLoopWindowTarget {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn set_exit_code(&self, code: i32) {
|
||||
x11_or_wayland!(match self; Self(evlp) => evlp.set_exit_code(code))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn exit_code(&self) -> Option<i32> {
|
||||
x11_or_wayland!(match self; Self(evlp) => evlp.exit_code())
|
||||
}
|
||||
|
||||
@@ -461,19 +461,19 @@ impl<T: 'static> EventLoop<T> {
|
||||
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 window_requests = state.window_requests.get_mut();
|
||||
if window_requests.get(window_id).unwrap().take_closed() {
|
||||
mem::drop(window_requests.remove(window_id));
|
||||
mem::drop(state.windows.get_mut().remove(window_id));
|
||||
if window_requests.get(&window_id).unwrap().take_closed() {
|
||||
mem::drop(window_requests.remove(&window_id));
|
||||
mem::drop(state.windows.get_mut().remove(&window_id));
|
||||
return Some(WindowEvent::Destroyed);
|
||||
}
|
||||
|
||||
let mut window = state
|
||||
.windows
|
||||
.get_mut()
|
||||
.get_mut(window_id)
|
||||
.get_mut(&window_id)
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap();
|
||||
@@ -485,7 +485,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
// Reset the frame callbacks state.
|
||||
window.frame_callback_reset();
|
||||
let mut redraw_requested = window_requests
|
||||
.get(window_id)
|
||||
.get(&window_id)
|
||||
.unwrap()
|
||||
.take_redraw_requested();
|
||||
|
||||
@@ -498,7 +498,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
if let Some(event) = event {
|
||||
callback(
|
||||
Event::WindowEvent {
|
||||
window_id: crate::window::WindowId(*window_id),
|
||||
window_id: crate::window::WindowId(window_id),
|
||||
event,
|
||||
},
|
||||
&self.window_target,
|
||||
@@ -514,42 +514,6 @@ impl<T: 'static> EventLoop<T> {
|
||||
// This is always the last event we dispatch before poll again
|
||||
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.buffer_sink, &mut buffer_sink);
|
||||
std::mem::swap(&mut self.window_ids, &mut window_ids);
|
||||
|
||||
@@ -6,7 +6,7 @@ macro_rules! atom_manager {
|
||||
($($name:ident $(:$lit:literal)?),*) => {
|
||||
x11rb::atom_manager! {
|
||||
/// The atoms used by `winit`
|
||||
pub Atoms: AtomsCookie {
|
||||
pub(crate) Atoms: AtomsCookie {
|
||||
$($name $(:$lit)?,)*
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ macro_rules! atom_manager {
|
||||
/// Indices into the `Atoms` struct.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum AtomName {
|
||||
pub(crate) enum AtomName {
|
||||
$($name,)*
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ impl From<io::Error> for DndDataParseError {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Dnd {
|
||||
pub(crate) struct Dnd {
|
||||
xconn: Arc<XConnection>,
|
||||
// Populated by XdndEnter event handler
|
||||
pub version: Option<c_long>,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,72 @@
|
||||
#![cfg(x11_platform)]
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ops::Deref;
|
||||
use std::os::raw::*;
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{ptr, slice, str};
|
||||
mod activation;
|
||||
mod atoms;
|
||||
mod dnd;
|
||||
mod event_processor;
|
||||
pub mod ffi;
|
||||
mod ime;
|
||||
mod monitor;
|
||||
pub mod util;
|
||||
mod window;
|
||||
mod xdisplay;
|
||||
mod xsettings;
|
||||
|
||||
pub(crate) use self::{
|
||||
monitor::{MonitorHandle, VideoModeHandle},
|
||||
window::UnownedWindow,
|
||||
xdisplay::{XConnection, XError, XNotSupported},
|
||||
};
|
||||
|
||||
use calloop::generic::Generic;
|
||||
use calloop::EventLoop as Loop;
|
||||
use calloop::{ping::Ping, Readiness};
|
||||
use libc::{self, setlocale, LC_CTYPE};
|
||||
use log::warn;
|
||||
|
||||
use x11rb::connection::RequestConnection;
|
||||
use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError};
|
||||
use x11rb::protocol::xinput::{self, ConnectionExt as _};
|
||||
use x11rb::protocol::xkb;
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt as _};
|
||||
use x11rb::x11_utils::X11Error as LogicalError;
|
||||
use x11rb::xcb_ffi::ReplyOrIdError;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
collections::{HashMap, HashSet},
|
||||
ffi::CStr,
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
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 crate::{
|
||||
error::{EventLoopError, OsError as RootOsError},
|
||||
@@ -38,28 +77,6 @@ use crate::{
|
||||
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
|
||||
const ALL_DEVICES: u16 = 0;
|
||||
const ALL_MASTER_DEVICES: u16 = 1;
|
||||
@@ -133,7 +150,7 @@ pub struct EventLoopWindowTarget {
|
||||
control_flow: Cell<ControlFlow>,
|
||||
exit: Cell<Option<i32>>,
|
||||
root: xproto::Window,
|
||||
ime: Option<RefCell<Ime>>,
|
||||
ime: RefCell<Ime>,
|
||||
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
|
||||
redraw_sender: WakeSender<WindowId>,
|
||||
activation_sender: WakeSender<ActivationToken>,
|
||||
@@ -149,6 +166,7 @@ pub struct EventLoop<T: 'static> {
|
||||
user_receiver: PeekableReceiver<T>,
|
||||
activation_receiver: PeekableReceiver<ActivationToken>,
|
||||
user_sender: Sender<T>,
|
||||
target: Rc<RootELW>,
|
||||
|
||||
/// The current state of the event loop.
|
||||
state: EventLoopState,
|
||||
@@ -209,15 +227,13 @@ impl<T: 'static> EventLoop<T> {
|
||||
setlocale(LC_CTYPE, default_locale);
|
||||
}
|
||||
}
|
||||
|
||||
let ime = Ime::new(Arc::clone(&xconn), ime_event_sender);
|
||||
if let Err(ImeCreationError::OpenFailure(state)) = ime.as_ref() {
|
||||
warn!("Failed to open input method: {state:#?}");
|
||||
} else if let Err(err) = ime.as_ref() {
|
||||
warn!("Failed to set input method destruction callback: {err:?}");
|
||||
}
|
||||
|
||||
let ime = ime.ok().map(RefCell::new);
|
||||
let ime = RefCell::new({
|
||||
let result = Ime::new(Arc::clone(&xconn), ime_event_sender);
|
||||
if let Err(ImeCreationError::OpenFailure(ref state)) = result {
|
||||
panic!("Failed to open input method: {state:#?}");
|
||||
}
|
||||
result.expect("Failed to set input method destruction callback")
|
||||
});
|
||||
|
||||
let randr_event_offset = xconn
|
||||
.select_xrandr_input(root)
|
||||
@@ -308,13 +324,13 @@ impl<T: 'static> EventLoop<T> {
|
||||
// Set initial device event filter.
|
||||
window_target.update_listen_device_events(true);
|
||||
|
||||
let root_window_target = RootELW {
|
||||
let target = Rc::new(RootELW {
|
||||
p: super::EventLoopWindowTarget::X(window_target),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
});
|
||||
|
||||
let event_processor = EventProcessor {
|
||||
target: root_window_target,
|
||||
target: target.clone(),
|
||||
dnd,
|
||||
devices: Default::default(),
|
||||
randr_event_offset,
|
||||
@@ -333,9 +349,8 @@ impl<T: 'static> EventLoop<T> {
|
||||
|
||||
// Register for device hotplug events
|
||||
// (The request buffer is flushed during `init_device`)
|
||||
let xconn = &EventProcessor::window_target(&event_processor.target).xconn;
|
||||
|
||||
xconn
|
||||
get_xtarget(&target)
|
||||
.xconn
|
||||
.select_xinput_events(
|
||||
root,
|
||||
ALL_DEVICES,
|
||||
@@ -343,7 +358,8 @@ impl<T: 'static> EventLoop<T> {
|
||||
)
|
||||
.expect_then_ignore_error("Failed to register for XInput2 device hotplug events");
|
||||
|
||||
xconn
|
||||
get_xtarget(&target)
|
||||
.xconn
|
||||
.select_xkb_events(
|
||||
0x100, // Use the "core keyboard device"
|
||||
xkb::EventType::NEW_KEYBOARD_NOTIFY
|
||||
@@ -363,6 +379,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
|
||||
user_receiver: PeekableReceiver::from_recv(user_channel),
|
||||
user_sender,
|
||||
target,
|
||||
state: EventLoopState {
|
||||
x11_readiness: Readiness::EMPTY,
|
||||
},
|
||||
@@ -379,7 +396,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
}
|
||||
|
||||
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>
|
||||
@@ -404,7 +421,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
// `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
|
||||
// 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| {
|
||||
EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err)))))
|
||||
})?;
|
||||
@@ -527,12 +544,12 @@ impl<T: 'static> EventLoop<T> {
|
||||
where
|
||||
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
|
||||
// applications don't themselves have a formal suspend/resume lifecycle.
|
||||
if cause == StartCause::Init {
|
||||
callback(Event::Resumed, &self.event_processor.target);
|
||||
callback(crate::event::Event::Resumed, &self.target);
|
||||
}
|
||||
|
||||
// Process all pending events
|
||||
@@ -547,16 +564,16 @@ impl<T: 'static> EventLoop<T> {
|
||||
});
|
||||
|
||||
match token {
|
||||
Some(Ok(token)) => {
|
||||
let event = Event::WindowEvent {
|
||||
Some(Ok(token)) => callback(
|
||||
crate::event::Event::WindowEvent {
|
||||
window_id: crate::window::WindowId(window_id),
|
||||
event: WindowEvent::ActivationTokenDone {
|
||||
event: crate::event::WindowEvent::ActivationTokenDone {
|
||||
serial,
|
||||
token: crate::window::ActivationToken::_new(token),
|
||||
},
|
||||
};
|
||||
callback(event, &self.event_processor.target)
|
||||
}
|
||||
},
|
||||
&self.target,
|
||||
),
|
||||
Some(Err(e)) => {
|
||||
log::error!("Failed to get activation token: {}", e);
|
||||
}
|
||||
@@ -567,7 +584,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
// Empty the user event buffer
|
||||
{
|
||||
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,
|
||||
event: WindowEvent::RedrawRequested,
|
||||
},
|
||||
&self.event_processor.target,
|
||||
&self.target,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
F: FnMut(Event<T>, &RootELW),
|
||||
{
|
||||
let target = &self.target;
|
||||
let mut xev = MaybeUninit::uninit();
|
||||
let wt = get_xtarget(&self.target);
|
||||
|
||||
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
|
||||
let mut xev = unsafe { xev.assume_init() };
|
||||
self.event_processor
|
||||
.process_event(&mut xev, |window_target, event| {
|
||||
if let Event::WindowEvent {
|
||||
window_id: crate::window::WindowId(wid),
|
||||
event: WindowEvent::RedrawRequested,
|
||||
} = event
|
||||
{
|
||||
let window_target = EventProcessor::window_target(window_target);
|
||||
window_target.redraw_sender.send(wid).unwrap();
|
||||
} else {
|
||||
callback(event, window_target);
|
||||
}
|
||||
});
|
||||
self.event_processor.process_event(&mut xev, |event| {
|
||||
if let Event::WindowEvent {
|
||||
window_id: crate::window::WindowId(wid),
|
||||
event: WindowEvent::RedrawRequested,
|
||||
} = event
|
||||
{
|
||||
wt.redraw_sender.send(wid).unwrap();
|
||||
} else {
|
||||
callback(event, target);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn control_flow(&self) -> ControlFlow {
|
||||
let window_target = EventProcessor::window_target(&self.event_processor.target);
|
||||
window_target.control_flow()
|
||||
self.target.p.control_flow()
|
||||
}
|
||||
|
||||
fn exiting(&self) -> bool {
|
||||
let window_target = EventProcessor::window_target(&self.event_processor.target);
|
||||
window_target.exiting()
|
||||
self.target.p.exiting()
|
||||
}
|
||||
|
||||
fn set_exit_code(&self, code: i32) {
|
||||
let window_target = EventProcessor::window_target(&self.event_processor.target);
|
||||
window_target.set_exit_code(code);
|
||||
self.target.p.set_exit_code(code)
|
||||
}
|
||||
|
||||
fn exit_code(&self) -> Option<i32> {
|
||||
let window_target = EventProcessor::window_target(&self.event_processor.target);
|
||||
window_target.exit_code()
|
||||
self.target.p.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 {
|
||||
/// Returns the `XConnection` of this events loop.
|
||||
#[inline]
|
||||
@@ -1027,7 +1048,7 @@ fn mkdid(w: xinput::DeviceId) -> crate::event::DeviceId {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Device {
|
||||
struct Device {
|
||||
_name: String,
|
||||
scroll_axes: Vec<(i32, ScrollAxis)>,
|
||||
// For master devices, this is the paired device (pointer <-> keyboard).
|
||||
|
||||
@@ -324,7 +324,7 @@ impl XConnection {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ScreenResources {
|
||||
pub(crate) struct ScreenResources {
|
||||
/// List of attached modes.
|
||||
modes: Vec<randr::ModeInfo>,
|
||||
|
||||
|
||||
@@ -39,13 +39,11 @@ impl XConnection {
|
||||
// Retrieve DPI from Xft.dpi property
|
||||
pub fn get_xft_dpi(&self) -> Option<f64> {
|
||||
// Try to get it from XSETTINGS first.
|
||||
if let Some(xsettings_screen) = self.xsettings_screen() {
|
||||
match self.xsettings_dpi(xsettings_screen) {
|
||||
Ok(Some(dpi)) => return Some(dpi),
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
log::warn!("failed to fetch XSettings: {err}");
|
||||
}
|
||||
match self.xsettings_dpi() {
|
||||
Ok(Some(dpi)) => return Some(dpi),
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
log::warn!("failed to fetch XSettings: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ impl SharedState {
|
||||
unsafe impl Send for UnownedWindow {}
|
||||
unsafe impl Sync for UnownedWindow {}
|
||||
|
||||
pub struct UnownedWindow {
|
||||
pub(crate) struct UnownedWindow {
|
||||
pub(crate) xconn: Arc<XConnection>, // never changes
|
||||
xwindow: xproto::Window, // never changes
|
||||
#[allow(dead_code)]
|
||||
@@ -555,9 +555,9 @@ impl UnownedWindow {
|
||||
leap!(xconn.select_xinput_events(window.xwindow, super::ALL_MASTER_DEVICES, mask))
|
||||
.ignore_error();
|
||||
|
||||
// Try to create input context for the window.
|
||||
if let Some(ime) = event_loop.ime.as_ref() {
|
||||
let result = ime
|
||||
{
|
||||
let result = event_loop
|
||||
.ime
|
||||
.borrow_mut()
|
||||
.create_context(window.xwindow as ffi::Window, false);
|
||||
leap!(result);
|
||||
|
||||
@@ -22,7 +22,7 @@ use x11rb::{
|
||||
};
|
||||
|
||||
/// A connection to an X server.
|
||||
pub struct XConnection {
|
||||
pub(crate) struct XConnection {
|
||||
pub xlib: ffi::Xlib,
|
||||
pub xcursor: ffi::Xcursor,
|
||||
|
||||
@@ -59,7 +59,7 @@ pub struct XConnection {
|
||||
randr_version: (u32, u32),
|
||||
|
||||
/// Atom for the XSettings screen.
|
||||
xsettings_screen: Option<xproto::Atom>,
|
||||
xsettings_screen: xproto::Atom,
|
||||
|
||||
pub latest_error: Mutex<Option<XError>>,
|
||||
pub cursor_cache: Mutex<HashMap<Option<CursorIcon>, ffi::Cursor>>,
|
||||
@@ -108,6 +108,21 @@ impl XConnection {
|
||||
// Get the default screen.
|
||||
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.
|
||||
let database = resource_manager::new_from_default(&xcb)
|
||||
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?;
|
||||
@@ -119,16 +134,23 @@ impl XConnection {
|
||||
.reply()
|
||||
.expect("failed to query XRandR version");
|
||||
|
||||
let xsettings_screen = Self::new_xsettings_screen(&xcb, default_screen);
|
||||
if xsettings_screen.is_none() {
|
||||
log::warn!("error setting XSETTINGS; Xft options won't reload automatically")
|
||||
}
|
||||
|
||||
// Fetch atoms.
|
||||
let atoms = Atoms::new(&xcb)
|
||||
// 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)
|
||||
.map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?
|
||||
.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 {
|
||||
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.
|
||||
#[inline]
|
||||
pub fn check_errors(&self) -> Result<(), XError> {
|
||||
@@ -267,7 +258,7 @@ impl XConnection {
|
||||
|
||||
/// Get the atom for Xsettings.
|
||||
#[inline]
|
||||
pub fn xsettings_screen(&self) -> Option<xproto::Atom> {
|
||||
pub fn xsettings_screen(&self) -> u32 {
|
||||
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.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum XNotSupported {
|
||||
pub(crate) enum XNotSupported {
|
||||
/// Failed to load one or several shared libraries.
|
||||
LibraryOpenError(ffi::OpenError),
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
//!
|
||||
//! [here]: https://github.com/derat/xsettingsd
|
||||
|
||||
use super::{atoms::*, XConnection};
|
||||
|
||||
use x11rb::protocol::xproto::ConnectionExt;
|
||||
|
||||
use std::iter;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt};
|
||||
|
||||
use super::{atoms::*, XConnection};
|
||||
|
||||
type Result<T> = core::result::Result<T, ParserError>;
|
||||
|
||||
const DPI_NAME: &[u8] = b"Xft/DPI";
|
||||
@@ -20,16 +20,13 @@ const BIG_ENDIAN: u8 = b'B';
|
||||
|
||||
impl XConnection {
|
||||
/// Get the DPI from XSettings.
|
||||
pub(crate) fn xsettings_dpi(
|
||||
&self,
|
||||
xsettings_screen: xproto::Atom,
|
||||
) -> core::result::Result<Option<f64>, super::X11Error> {
|
||||
pub(crate) fn xsettings_dpi(&self) -> core::result::Result<Option<f64>, super::X11Error> {
|
||||
let atoms = self.atoms();
|
||||
|
||||
// Get the current owner of the screen's settings.
|
||||
let owner = self
|
||||
.xcb_connection()
|
||||
.get_selection_owner(xsettings_screen)?
|
||||
.get_selection_owner(self.xsettings_screen())?
|
||||
.reply()?;
|
||||
|
||||
// Read the _XSETTINGS_SETTINGS property.
|
||||
|
||||
@@ -9,8 +9,8 @@ use std::{
|
||||
|
||||
use bitflags::bitflags;
|
||||
use orbclient::{
|
||||
ButtonEvent, EventOption, FocusEvent, HoverEvent, KeyEvent, MouseEvent, MouseRelativeEvent,
|
||||
MoveEvent, QuitEvent, ResizeEvent, ScrollEvent, TextInputEvent,
|
||||
ButtonEvent, EventOption, FocusEvent, HoverEvent, KeyEvent, MouseEvent, MoveEvent, QuitEvent,
|
||||
ResizeEvent, ScrollEvent, TextInputEvent,
|
||||
};
|
||||
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 {
|
||||
left,
|
||||
middle,
|
||||
@@ -518,7 +510,7 @@ impl<T: 'static> EventLoop<T> {
|
||||
// Acknowledge resize after event loop.
|
||||
event_state.resize_opt = Some((width, height));
|
||||
}
|
||||
//TODO: Screen, Clipboard, Drop
|
||||
//TODO: Clipboard
|
||||
EventOption::Hover(HoverEvent { entered }) => {
|
||||
if entered {
|
||||
event_handler(event::Event::WindowEvent {
|
||||
|
||||
@@ -13,8 +13,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
EventLoopWindowTarget, MonitorHandle, OsError, RedoxSocket, TimeSocket, WindowId,
|
||||
WindowProperties,
|
||||
EventLoopWindowTarget, MonitorHandle, RedoxSocket, TimeSocket, WindowId, WindowProperties,
|
||||
};
|
||||
|
||||
// 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_BACK: char = 'b';
|
||||
const ORBITAL_FLAG_FRONT: char = 'f';
|
||||
const ORBITAL_FLAG_HIDDEN: char = 'h';
|
||||
const ORBITAL_FLAG_BORDERLESS: char = 'l';
|
||||
const ORBITAL_FLAG_MAXIMIZED: char = 'm';
|
||||
const ORBITAL_FLAG_RESIZABLE: char = 'r';
|
||||
const ORBITAL_FLAG_TRANSPARENT: char = 't';
|
||||
|
||||
@@ -60,15 +57,11 @@ impl Window {
|
||||
// Async by default.
|
||||
let mut flag_str = ORBITAL_FLAG_ASYNC.to_string();
|
||||
|
||||
if attrs.maximized {
|
||||
flag_str.push(ORBITAL_FLAG_MAXIMIZED);
|
||||
}
|
||||
|
||||
if attrs.resizable {
|
||||
flag_str.push(ORBITAL_FLAG_RESIZABLE);
|
||||
}
|
||||
|
||||
//TODO: fullscreen
|
||||
//TODO: maximized, fullscreen, visible
|
||||
|
||||
if attrs.transparent {
|
||||
flag_str.push(ORBITAL_FLAG_TRANSPARENT);
|
||||
@@ -78,10 +71,6 @@ impl Window {
|
||||
flag_str.push(ORBITAL_FLAG_BORDERLESS);
|
||||
}
|
||||
|
||||
if !attrs.visible {
|
||||
flag_str.push(ORBITAL_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
match attrs.window_level {
|
||||
window::WindowLevel::AlwaysOnBottom => {
|
||||
flag_str.push(ORBITAL_FLAG_BACK);
|
||||
@@ -140,23 +129,6 @@ impl Window {
|
||||
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]
|
||||
pub fn id(&self) -> WindowId {
|
||||
WindowId {
|
||||
@@ -282,21 +254,17 @@ impl Window {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_transparent(&self, transparent: bool) {
|
||||
let _ = self.set_flag(ORBITAL_FLAG_TRANSPARENT, transparent);
|
||||
}
|
||||
pub fn set_transparent(&self, _transparent: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_blur(&self, _blur: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_visible(&self, visible: bool) {
|
||||
let _ = self.set_flag(ORBITAL_FLAG_HIDDEN, !visible);
|
||||
}
|
||||
pub fn set_visible(&self, _visibility: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn is_visible(&self) -> Option<bool> {
|
||||
Some(!self.get_flag(ORBITAL_FLAG_HIDDEN).unwrap_or(false))
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -308,13 +276,17 @@ impl Window {
|
||||
pub fn set_resize_increments(&self, _increments: Option<Size>) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_resizable(&self, resizeable: bool) {
|
||||
let _ = self.set_flag(ORBITAL_FLAG_RESIZABLE, resizeable);
|
||||
}
|
||||
pub fn set_resizable(&self, _resizeable: bool) {}
|
||||
|
||||
#[inline]
|
||||
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]
|
||||
@@ -326,13 +298,11 @@ impl Window {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, maximized: bool) {
|
||||
let _ = self.set_flag(ORBITAL_FLAG_MAXIMIZED, maximized);
|
||||
}
|
||||
pub fn set_maximized(&self, _maximized: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn is_maximized(&self) -> bool {
|
||||
self.get_flag(ORBITAL_FLAG_MAXIMIZED).unwrap_or(false)
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -344,30 +314,21 @@ impl Window {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_decorations(&self, decorations: bool) {
|
||||
let _ = self.set_flag(ORBITAL_FLAG_BORDERLESS, !decorations);
|
||||
}
|
||||
pub fn set_decorations(&self, _decorations: bool) {}
|
||||
|
||||
#[inline]
|
||||
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]
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn set_window_level(&self, _level: window::WindowLevel) {}
|
||||
|
||||
#[inline]
|
||||
pub fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {}
|
||||
@@ -398,58 +359,30 @@ impl Window {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_grab(
|
||||
&self,
|
||||
mode: window::CursorGrabMode,
|
||||
) -> 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(())
|
||||
pub fn set_cursor_grab(&self, _: window::CursorGrabMode) -> Result<(), error::ExternalError> {
|
||||
Err(error::ExternalError::NotSupported(
|
||||
error::NotSupportedError::new(),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_visible(&self, visible: bool) {
|
||||
let _ = self
|
||||
.window_socket
|
||||
.write(format!("M,C,{}", if visible { 1 } else { 0 }).as_bytes());
|
||||
}
|
||||
pub fn set_cursor_visible(&self, _: bool) {}
|
||||
|
||||
#[inline]
|
||||
pub fn drag_window(&self) -> Result<(), error::ExternalError> {
|
||||
self.window_socket
|
||||
.write(b"D")
|
||||
.map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?;
|
||||
Ok(())
|
||||
Err(error::ExternalError::NotSupported(
|
||||
error::NotSupportedError::new(),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn drag_resize_window(
|
||||
&self,
|
||||
direction: window::ResizeDirection,
|
||||
_direction: window::ResizeDirection,
|
||||
) -> Result<(), error::ExternalError> {
|
||||
let arg = match direction {
|
||||
window::ResizeDirection::East => "R",
|
||||
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(())
|
||||
Err(error::ExternalError::NotSupported(
|
||||
error::NotSupportedError::new(),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -57,11 +57,8 @@ use serde::{Deserialize, Serialize};
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Web:** The window is represented by a `HTMLElementCanvas`, and cannot
|
||||
/// currently 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.
|
||||
/// **Web:** The [`Window`], which is represented by a `HTMLElementCanvas`, can
|
||||
/// not be closed by dropping the [`Window`].
|
||||
pub struct Window {
|
||||
pub(crate) window: platform_impl::Window,
|
||||
}
|
||||
@@ -949,7 +946,7 @@ impl Window {
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Web / iOS / Android:** Unsupported.
|
||||
/// - **Web / iOS / Android / Orbital:** Unsupported.
|
||||
/// - **X11:** Can only be set while building the window, with [`WindowBuilder::with_transparent`].
|
||||
#[inline]
|
||||
pub fn set_transparent(&self, transparent: bool) {
|
||||
@@ -1082,7 +1079,7 @@ impl Window {
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, maximized: bool) {
|
||||
self.window
|
||||
@@ -1093,7 +1090,7 @@ impl Window {
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web:** Unsupported.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn is_maximized(&self) -> bool {
|
||||
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.
|
||||
/// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
|
||||
/// outside of the window.
|
||||
/// - **iOS / Android:** Unsupported.
|
||||
/// - **iOS / Android / Orbital:** Unsupported.
|
||||
#[inline]
|
||||
pub fn set_cursor_visible(&self, visible: bool) {
|
||||
self.window
|
||||
@@ -1470,7 +1467,7 @@ impl Window {
|
||||
/// - **X11:** Un-grabs the cursor.
|
||||
/// - **Wayland:** Requires the cursor to be inside the window to be dragged.
|
||||
/// - **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]
|
||||
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
||||
self.window.maybe_wait_on_main(|w| w.drag_window())
|
||||
@@ -1484,7 +1481,7 @@ impl Window {
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **macOS:** Always returns an [`ExternalError::NotSupported`]
|
||||
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
|
||||
/// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
|
||||
#[inline]
|
||||
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
||||
self.window
|
||||
@@ -1645,7 +1642,7 @@ pub enum CursorGrabMode {
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **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,
|
||||
|
||||
/// The cursor is locked inside the window area to the certain position.
|
||||
@@ -1656,7 +1653,7 @@ pub enum CursorGrabMode {
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **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,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user