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
|
- 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')
|
||||||
|
|||||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -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
|
||||||
|
|
||||||
|
|||||||
37
src/event.rs
37
src/event.rs
@@ -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;
|
||||||
|
|||||||
@@ -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(_)) {
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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).
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
|
||||||
|
|||||||
@@ -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}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user