chore(rustfmt): use nightly (#2325)
Stable rustfmt lacks a lot of features resulting in worse formatted code, thus use nightly formatter.
This commit is contained in:
parent
7006c7ceca
commit
7b0c7b6cb2
154 changed files with 3439 additions and 5891 deletions
|
|
@ -6,8 +6,7 @@ use std::ops::Deref;
|
|||
use std::os::unix::ffi::OsStringExt;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use super::XkbContext;
|
||||
use super::XKBCH;
|
||||
use super::{XkbContext, XKBCH};
|
||||
use smol_str::SmolStr;
|
||||
use xkbcommon_dl::{
|
||||
xkb_compose_compile_flags, xkb_compose_feed_result, xkb_compose_state, xkb_compose_state_flags,
|
||||
|
|
@ -91,7 +90,7 @@ impl XkbComposeState {
|
|||
xkb_compose_feed_result::XKB_COMPOSE_FEED_IGNORED => ComposeStatus::Ignored,
|
||||
xkb_compose_feed_result::XKB_COMPOSE_FEED_ACCEPTED => {
|
||||
ComposeStatus::Accepted(self.status())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ pub fn physicalkey_to_scancode(key: PhysicalKey) -> Option<u32> {
|
|||
NativeKeyCode::Xkb(raw) => Some(raw),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
match code {
|
||||
|
|
@ -627,7 +627,6 @@ pub fn keysym_to_key(keysym: u32) -> Key {
|
|||
// keysyms::ISO_First_Group_Lock => NamedKey::GroupFirstLock,
|
||||
keysyms::ISO_Last_Group => NamedKey::GroupLast,
|
||||
// keysyms::ISO_Last_Group_Lock => NamedKey::GroupLastLock,
|
||||
//
|
||||
keysyms::ISO_Left_Tab => NamedKey::Tab,
|
||||
// keysyms::ISO_Move_Line_Up => NamedKey::IsoMoveLineUp,
|
||||
// keysyms::ISO_Move_Line_Down => NamedKey::IsoMoveLineDown,
|
||||
|
|
@ -809,18 +808,15 @@ pub fn keysym_to_key(keysym: u32) -> Key {
|
|||
keysyms::XF86_Music => NamedKey::LaunchMusicPlayer,
|
||||
|
||||
// XF86_Battery..XF86_UWB
|
||||
//
|
||||
keysyms::XF86_AudioForward => NamedKey::MediaFastForward,
|
||||
// XF86_AudioRepeat
|
||||
keysyms::XF86_AudioRandomPlay => NamedKey::RandomToggle,
|
||||
keysyms::XF86_Subtitle => NamedKey::Subtitle,
|
||||
keysyms::XF86_AudioCycleTrack => NamedKey::MediaAudioTrack,
|
||||
// XF86_CycleAngle..XF86_Blue
|
||||
//
|
||||
keysyms::XF86_Suspend => NamedKey::Standby,
|
||||
keysyms::XF86_Hibernate => NamedKey::Hibernate,
|
||||
// XF86_TouchpadToggle..XF86_TouchpadOff
|
||||
//
|
||||
keysyms::XF86_AudioMute => NamedKey::AudioVolumeMute,
|
||||
|
||||
// XF86_Switch_VT_1..XF86_Switch_VT_12
|
||||
|
|
@ -853,7 +849,6 @@ pub fn keysym_to_key(keysym: u32) -> Key {
|
|||
keysyms::SUN_VideoLowerBrightness => NamedKey::BrightnessDown,
|
||||
keysyms::SUN_VideoRaiseBrightness => NamedKey::BrightnessUp,
|
||||
// SunPowerSwitchShift
|
||||
//
|
||||
0 => return Key::Unidentified(NativeKey::Unidentified),
|
||||
_ => return Key::Unidentified(NativeKey::Xkb(keysym)),
|
||||
})
|
||||
|
|
@ -968,11 +963,7 @@ impl XkbKeymap {
|
|||
mod5: mod_index_for_name(keymap, b"Mod5\0"),
|
||||
};
|
||||
|
||||
Self {
|
||||
keymap,
|
||||
_mods_indices: mods_indices,
|
||||
_core_keyboard_id,
|
||||
}
|
||||
Self { keymap, _mods_indices: mods_indices, _core_keyboard_id }
|
||||
}
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
|
|
@ -1020,6 +1011,7 @@ impl Drop for XkbKeymap {
|
|||
|
||||
impl Deref for XkbKeymap {
|
||||
type Target = NonNull<xkb_keymap>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.keymap
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ use xkbcommon_dl::{
|
|||
#[cfg(x11_platform)]
|
||||
use {x11_dl::xlib_xcb::xcb_connection_t, xkbcommon_dl::x11::xkbcommon_x11_handle};
|
||||
|
||||
use crate::event::ElementState;
|
||||
use crate::event::KeyEvent;
|
||||
use crate::event::{ElementState, KeyEvent};
|
||||
use crate::keyboard::{Key, KeyLocation};
|
||||
use crate::platform_impl::KeyEventExtra;
|
||||
|
||||
|
|
@ -143,9 +142,7 @@ impl Context {
|
|||
#[cfg(x11_platform)]
|
||||
pub fn set_keymap_from_x11(&mut self, xcb: *mut xcb_connection_t) {
|
||||
let keymap = XkbKeymap::from_x11_keymap(&self.context, xcb, self.core_keyboard_id);
|
||||
let state = keymap
|
||||
.as_ref()
|
||||
.and_then(|keymap| XkbState::new_x11(xcb, keymap));
|
||||
let state = keymap.as_ref().and_then(|keymap| XkbState::new_x11(xcb, keymap));
|
||||
if keymap.is_none() || state.is_none() {
|
||||
warn!("failed to update xkb keymap");
|
||||
}
|
||||
|
|
@ -160,13 +157,7 @@ impl Context {
|
|||
let compose_state1 = self.compose_state1.as_mut();
|
||||
let compose_state2 = self.compose_state2.as_mut();
|
||||
let scratch_buffer = &mut self.scratch_buffer;
|
||||
Some(KeyContext {
|
||||
state,
|
||||
keymap,
|
||||
compose_state1,
|
||||
compose_state2,
|
||||
scratch_buffer,
|
||||
})
|
||||
Some(KeyContext { state, keymap, compose_state1, compose_state2, scratch_buffer })
|
||||
}
|
||||
|
||||
/// Key builder context with the user provided xkb state.
|
||||
|
|
@ -181,13 +172,7 @@ impl Context {
|
|||
let compose_state1 = self.compose_state1.as_mut();
|
||||
let compose_state2 = self.compose_state2.as_mut();
|
||||
let scratch_buffer = &mut self.scratch_buffer;
|
||||
Some(KeyContext {
|
||||
state,
|
||||
keymap,
|
||||
compose_state1,
|
||||
compose_state2,
|
||||
scratch_buffer,
|
||||
})
|
||||
Some(KeyContext { state, keymap, compose_state1, compose_state2, scratch_buffer })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -214,20 +199,9 @@ impl<'a> KeyContext<'a> {
|
|||
let (key_without_modifiers, _) = event.key_without_modifiers();
|
||||
let text_with_all_modifiers = event.text_with_all_modifiers();
|
||||
|
||||
let platform_specific = KeyEventExtra {
|
||||
text_with_all_modifiers,
|
||||
key_without_modifiers,
|
||||
};
|
||||
let platform_specific = KeyEventExtra { text_with_all_modifiers, key_without_modifiers };
|
||||
|
||||
KeyEvent {
|
||||
physical_key,
|
||||
logical_key,
|
||||
text,
|
||||
location,
|
||||
state,
|
||||
repeat,
|
||||
platform_specific,
|
||||
}
|
||||
KeyEvent { physical_key, logical_key, text, location, state, repeat, platform_specific }
|
||||
}
|
||||
|
||||
fn keysym_to_utf8_raw(&mut self, keysym: u32) -> Option<SmolStr> {
|
||||
|
|
@ -246,10 +220,7 @@ impl<'a> KeyContext<'a> {
|
|||
} else if bytes_written == -1 {
|
||||
self.scratch_buffer.reserve(8);
|
||||
} else {
|
||||
unsafe {
|
||||
self.scratch_buffer
|
||||
.set_len(bytes_written.try_into().unwrap())
|
||||
};
|
||||
unsafe { self.scratch_buffer.set_len(bytes_written.try_into().unwrap()) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -281,12 +252,7 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
|
|||
ComposeStatus::None
|
||||
};
|
||||
|
||||
KeyEventResults {
|
||||
context,
|
||||
keycode,
|
||||
keysym,
|
||||
compose,
|
||||
}
|
||||
KeyEventResults { context, keycode, keysym, compose }
|
||||
}
|
||||
|
||||
pub fn key(&mut self) -> (Key, KeyLocation) {
|
||||
|
|
@ -323,23 +289,18 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
|
|||
}
|
||||
|
||||
pub fn key_without_modifiers(&mut self) -> (Key, KeyLocation) {
|
||||
// This will become a pointer to an array which libxkbcommon owns, so we don't need to deallocate it.
|
||||
// This will become a pointer to an array which libxkbcommon owns, so we don't need to
|
||||
// deallocate it.
|
||||
let layout = self.context.state.layout(self.keycode);
|
||||
let keysym = self
|
||||
.context
|
||||
.keymap
|
||||
.first_keysym_by_level(layout, self.keycode);
|
||||
let keysym = self.context.keymap.first_keysym_by_level(layout, self.keycode);
|
||||
|
||||
match self.keysym_to_key(keysym) {
|
||||
Ok((key, location)) => (key, location),
|
||||
Err((key, location)) => {
|
||||
let key = self
|
||||
.context
|
||||
.keysym_to_utf8_raw(keysym)
|
||||
.map(Key::Character)
|
||||
.unwrap_or(key);
|
||||
let key =
|
||||
self.context.keysym_to_utf8_raw(keysym).map(Key::Character).unwrap_or(key);
|
||||
(key, location)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -354,8 +315,7 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
|
|||
}
|
||||
|
||||
pub fn text(&mut self) -> Option<SmolStr> {
|
||||
self.composed_text()
|
||||
.unwrap_or_else(|_| self.context.keysym_to_utf8_raw(self.keysym))
|
||||
self.composed_text().unwrap_or_else(|_| self.context.keysym_to_utf8_raw(self.keysym))
|
||||
}
|
||||
|
||||
// The current behaviour makes it so composing a character overrides attempts to input a
|
||||
|
|
@ -364,10 +324,7 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
|
|||
pub fn text_with_all_modifiers(&mut self) -> Option<SmolStr> {
|
||||
match self.composed_text() {
|
||||
Ok(text) => text,
|
||||
Err(_) => self
|
||||
.context
|
||||
.state
|
||||
.get_utf8_raw(self.keycode, self.context.scratch_buffer),
|
||||
Err(_) => self.context.state.get_utf8_raw(self.keycode, self.context.scratch_buffer),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,7 +334,7 @@ impl<'a, 'b> KeyEventResults<'a, 'b> {
|
|||
xkb_compose_status::XKB_COMPOSE_COMPOSED => {
|
||||
let state = self.context.compose_state1.as_mut().unwrap();
|
||||
Ok(state.get_string(self.context.scratch_buffer))
|
||||
}
|
||||
},
|
||||
xkb_compose_status::XKB_COMPOSE_COMPOSING
|
||||
| xkb_compose_status::XKB_COMPOSE_CANCELLED => Ok(None),
|
||||
xkb_compose_status::XKB_COMPOSE_NOTHING => Err(()),
|
||||
|
|
@ -436,10 +393,7 @@ where
|
|||
// The allocated buffer must include space for the null-terminator.
|
||||
scratch_buffer.reserve(size + 1);
|
||||
unsafe {
|
||||
let written = f(
|
||||
scratch_buffer.as_mut_ptr().cast(),
|
||||
scratch_buffer.capacity(),
|
||||
);
|
||||
let written = f(scratch_buffer.as_mut_ptr().cast(), scratch_buffer.capacity());
|
||||
if usize::try_from(written).unwrap() != size {
|
||||
// This will likely never happen.
|
||||
return None;
|
||||
|
|
@ -456,10 +410,7 @@ fn byte_slice_to_smol_str(bytes: &[u8]) -> Option<SmolStr> {
|
|||
std::str::from_utf8(bytes)
|
||||
.map(SmolStr::new)
|
||||
.map_err(|e| {
|
||||
tracing::warn!(
|
||||
"UTF-8 received from libxkbcommon ({:?}) was invalid: {e}",
|
||||
bytes
|
||||
)
|
||||
tracing::warn!("UTF-8 received from libxkbcommon ({:?}) was invalid: {e}", bytes)
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
#[cfg(all(not(x11_platform), not(wayland_platform)))]
|
||||
compile_error!("Please select a feature to build for unix: `x11`, `wayland`");
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{collections::VecDeque, env, fmt};
|
||||
use std::{env, fmt};
|
||||
#[cfg(x11_platform)]
|
||||
use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex};
|
||||
|
||||
|
|
@ -16,22 +17,19 @@ use smol_str::SmolStr;
|
|||
|
||||
#[cfg(x11_platform)]
|
||||
use self::x11::{X11Error, XConnection, XError, XNotSupported};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootELW, AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
|
||||
};
|
||||
use crate::icon::Icon;
|
||||
use crate::keyboard::Key;
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
#[cfg(x11_platform)]
|
||||
use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook};
|
||||
use crate::window::{CustomCursor, CustomCursorSource};
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
event_loop::{
|
||||
ActiveEventLoop as RootELW, AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
|
||||
},
|
||||
icon::Icon,
|
||||
keyboard::Key,
|
||||
platform::pump_events::PumpStatus,
|
||||
window::{
|
||||
ActivationToken, Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme,
|
||||
UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
|
||||
},
|
||||
use crate::window::{
|
||||
ActivationToken, Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose,
|
||||
ResizeDirection, Theme, UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
|
||||
};
|
||||
|
||||
pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||
|
|
@ -294,11 +292,11 @@ impl Window {
|
|||
#[cfg(wayland_platform)]
|
||||
ActiveEventLoop::Wayland(ref window_target) => {
|
||||
wayland::Window::new(window_target, attribs).map(Window::Wayland)
|
||||
}
|
||||
},
|
||||
#[cfg(x11_platform)]
|
||||
ActiveEventLoop::X(ref window_target) => {
|
||||
x11::Window::new(window_target, attribs).map(Window::X)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -534,6 +532,7 @@ impl Window {
|
|||
pub fn focus_window(&self) {
|
||||
x11_or_wayland!(match self; Window(w) => w.focus_window())
|
||||
}
|
||||
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
x11_or_wayland!(match self; Window(w) => w.request_user_attention(request_type))
|
||||
}
|
||||
|
|
@ -557,17 +556,13 @@ impl Window {
|
|||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
match self {
|
||||
#[cfg(x11_platform)]
|
||||
Window::X(ref window) => window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect(),
|
||||
Window::X(ref window) => {
|
||||
window.available_monitors().into_iter().map(MonitorHandle::X).collect()
|
||||
},
|
||||
#[cfg(wayland_platform)]
|
||||
Window::Wayland(ref window) => window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect(),
|
||||
Window::Wayland(ref window) => {
|
||||
window.available_monitors().into_iter().map(MonitorHandle::Wayland).collect()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -741,12 +736,10 @@ impl<T: 'static> EventLoop<T> {
|
|||
.or_else(|| env::var("WAYLAND_SOCKET").ok())
|
||||
.filter(|var| !var.is_empty())
|
||||
.is_some(),
|
||||
env::var("DISPLAY")
|
||||
.map(|var| !var.is_empty())
|
||||
.unwrap_or(false),
|
||||
env::var("DISPLAY").map(|var| !var.is_empty()).unwrap_or(false),
|
||||
) {
|
||||
// User is forcing a backend.
|
||||
(Some(backend), _, _) => backend,
|
||||
(Some(backend), ..) => backend,
|
||||
// Wayland is present.
|
||||
#[cfg(wayland_platform)]
|
||||
(None, true, _) => Backend::Wayland,
|
||||
|
|
@ -756,14 +749,16 @@ impl<T: 'static> EventLoop<T> {
|
|||
// No backend is present.
|
||||
(_, wayland_display, x11_display) => {
|
||||
let msg = if wayland_display && !cfg!(wayland_platform) {
|
||||
"DISPLAY is not set; note: enable the `winit/wayland` feature to support Wayland"
|
||||
"DISPLAY is not set; note: enable the `winit/wayland` feature to support \
|
||||
Wayland"
|
||||
} else if x11_display && !cfg!(x11_platform) {
|
||||
"neither WAYLAND_DISPLAY nor WAYLAND_SOCKET is set; note: enable the `winit/x11` feature to support X11"
|
||||
"neither WAYLAND_DISPLAY nor WAYLAND_SOCKET is set; note: enable the \
|
||||
`winit/x11` feature to support X11"
|
||||
} else {
|
||||
"neither WAYLAND_DISPLAY nor WAYLAND_SOCKET nor DISPLAY is set."
|
||||
};
|
||||
return Err(EventLoopError::Os(os_error!(OsError::Misc(msg))));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Create the display based on the backend.
|
||||
|
|
@ -864,14 +859,13 @@ impl ActiveEventLoop {
|
|||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
match *self {
|
||||
#[cfg(wayland_platform)]
|
||||
ActiveEventLoop::Wayland(ref evlp) => evlp
|
||||
.available_monitors()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect(),
|
||||
ActiveEventLoop::Wayland(ref evlp) => {
|
||||
evlp.available_monitors().map(MonitorHandle::Wayland).collect()
|
||||
},
|
||||
#[cfg(x11_platform)]
|
||||
ActiveEventLoop::X(ref evlp) => {
|
||||
evlp.available_monitors().map(MonitorHandle::X).collect()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -961,7 +955,7 @@ impl OwnedDisplayHandle {
|
|||
xlib_handle.display = xconn.display.cast();
|
||||
xlib_handle.screen = xconn.default_screen_index() as _;
|
||||
xlib_handle.into()
|
||||
}
|
||||
},
|
||||
|
||||
#[cfg(wayland_platform)]
|
||||
Self::Wayland(conn) => {
|
||||
|
|
@ -970,7 +964,7 @@ impl OwnedDisplayHandle {
|
|||
let mut wayland_handle = rwh_05::WaylandDisplayHandle::empty();
|
||||
wayland_handle.display = conn.display().id().as_ptr() as *mut _;
|
||||
wayland_handle.into()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -997,7 +991,7 @@ impl OwnedDisplayHandle {
|
|||
NonNull::new(conn.display().id().as_ptr().cast()).unwrap(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1006,9 +1000,7 @@ impl OwnedDisplayHandle {
|
|||
/// equates to an infinite timeout, not a zero timeout (so can't just use
|
||||
/// `Option::min`)
|
||||
fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
|
||||
a.map_or(b, |a_timeout| {
|
||||
b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))
|
||||
})
|
||||
a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ use std::time::{Duration, Instant};
|
|||
|
||||
use sctk::reexports::calloop::Error as CalloopError;
|
||||
use sctk::reexports::calloop_wayland_source::WaylandSource;
|
||||
use sctk::reexports::client::globals;
|
||||
use sctk::reexports::client::{Connection, QueueHandle};
|
||||
use sctk::reexports::client::{globals, Connection, QueueHandle};
|
||||
|
||||
use crate::cursor::OnlyCursorImage;
|
||||
use crate::dpi::LogicalSize;
|
||||
|
|
@ -81,26 +80,19 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
let connection = map_err!(Connection::connect_to_env(), WaylandError::Connection)?;
|
||||
|
||||
let (globals, mut event_queue) = map_err!(
|
||||
globals::registry_queue_init(&connection),
|
||||
WaylandError::Global
|
||||
)?;
|
||||
let (globals, mut event_queue) =
|
||||
map_err!(globals::registry_queue_init(&connection), WaylandError::Global)?;
|
||||
let queue_handle = event_queue.handle();
|
||||
|
||||
let event_loop = map_err!(
|
||||
calloop::EventLoop::<WinitState>::try_new(),
|
||||
WaylandError::Calloop
|
||||
)?;
|
||||
let event_loop =
|
||||
map_err!(calloop::EventLoop::<WinitState>::try_new(), WaylandError::Calloop)?;
|
||||
|
||||
let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle())
|
||||
.map_err(|error| os_error!(error))?;
|
||||
|
||||
// NOTE: do a roundtrip after binding the globals to prevent potential
|
||||
// races with the server.
|
||||
map_err!(
|
||||
event_queue.roundtrip(&mut winit_state),
|
||||
WaylandError::Dispatch
|
||||
)?;
|
||||
map_err!(event_queue.roundtrip(&mut winit_state), WaylandError::Dispatch)?;
|
||||
|
||||
// Register Wayland source.
|
||||
let wayland_source = WaylandSource::new(connection.clone(), event_queue);
|
||||
|
|
@ -117,9 +109,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
});
|
||||
|
||||
map_err!(
|
||||
event_loop
|
||||
.handle()
|
||||
.register_dispatcher(wayland_dispatcher.clone()),
|
||||
event_loop.handle().register_dispatcher(wayland_dispatcher.clone()),
|
||||
WaylandError::Calloop
|
||||
)?;
|
||||
|
||||
|
|
@ -129,15 +119,12 @@ impl<T: 'static> EventLoop<T> {
|
|||
let (user_events_sender, user_events_channel) = calloop::channel::channel();
|
||||
let result = event_loop
|
||||
.handle()
|
||||
.insert_source(
|
||||
user_events_channel,
|
||||
move |event, _, winit_state: &mut WinitState| {
|
||||
if let calloop::channel::Event::Msg(msg) = event {
|
||||
winit_state.dispatched_events = true;
|
||||
pending_user_events_clone.borrow_mut().push(msg);
|
||||
}
|
||||
},
|
||||
)
|
||||
.insert_source(user_events_channel, move |event, _, winit_state: &mut WinitState| {
|
||||
if let calloop::channel::Event::Msg(msg) = event {
|
||||
winit_state.dispatched_events = true;
|
||||
pending_user_events_clone.borrow_mut().push(msg);
|
||||
}
|
||||
})
|
||||
.map_err(|error| error.error);
|
||||
map_err!(result, WaylandError::Calloop)?;
|
||||
|
||||
|
|
@ -150,13 +137,10 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
let result = event_loop
|
||||
.handle()
|
||||
.insert_source(
|
||||
event_loop_awakener_source,
|
||||
move |_, _, winit_state: &mut WinitState| {
|
||||
// Mark that we have something to dispatch.
|
||||
winit_state.dispatched_events = true;
|
||||
},
|
||||
)
|
||||
.insert_source(event_loop_awakener_source, move |_, _, winit_state: &mut WinitState| {
|
||||
// Mark that we have something to dispatch.
|
||||
winit_state.dispatched_events = true;
|
||||
})
|
||||
.map_err(|error| error.error);
|
||||
map_err!(result, WaylandError::Calloop)?;
|
||||
|
||||
|
|
@ -197,13 +181,13 @@ impl<T: 'static> EventLoop<T> {
|
|||
match self.pump_events(None, &mut event_handler) {
|
||||
PumpStatus::Exit(0) => {
|
||||
break Ok(());
|
||||
}
|
||||
},
|
||||
PumpStatus::Exit(code) => {
|
||||
break Err(EventLoopError::ExitFailure(code));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -256,7 +240,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
ControlFlow::Poll => Some(Duration::ZERO),
|
||||
ControlFlow::WaitUntil(wait_deadline) => {
|
||||
Some(wait_deadline.saturating_duration_since(start))
|
||||
}
|
||||
},
|
||||
};
|
||||
min_timeout(control_flow_timeout, timeout)
|
||||
};
|
||||
|
|
@ -274,11 +258,12 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
if let Err(error) = self.loop_dispatch(timeout) {
|
||||
// NOTE We exit on errors from dispatches, since if we've got protocol error
|
||||
// libwayland-client/wayland-rs will inform us anyway, but crashing downstream is not
|
||||
// really an option. Instead we inform that the event loop got destroyed. We may
|
||||
// communicate an error that something was terminated, but winit doesn't provide us
|
||||
// with an API to do that via some event.
|
||||
// Still, we set the exit code to the error's OS error code, or to 1 if not possible.
|
||||
// libwayland-client/wayland-rs will inform us anyway, but crashing downstream is
|
||||
// not really an option. Instead we inform that the event loop got
|
||||
// destroyed. We may communicate an error that something was
|
||||
// terminated, but winit doesn't provide us with an API to do that
|
||||
// via some event. Still, we set the exit code to the error's OS
|
||||
// error code, or to 1 if not possible.
|
||||
let exit_code = error.raw_os_error().unwrap_or(1);
|
||||
self.set_exit_code(exit_code);
|
||||
return;
|
||||
|
|
@ -288,23 +273,14 @@ impl<T: 'static> EventLoop<T> {
|
|||
// to be considered here
|
||||
let cause = match self.control_flow() {
|
||||
ControlFlow::Poll => StartCause::Poll,
|
||||
ControlFlow::Wait => StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: None,
|
||||
},
|
||||
ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
|
||||
ControlFlow::WaitUntil(deadline) => {
|
||||
if Instant::now() < deadline {
|
||||
StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: Some(deadline),
|
||||
}
|
||||
StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
|
||||
} else {
|
||||
StartCause::ResumeTimeReached {
|
||||
start,
|
||||
requested_resume: deadline,
|
||||
}
|
||||
StartCause::ResumeTimeReached { start, requested_resume: deadline }
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Reduce spurious wake-ups.
|
||||
|
|
@ -471,13 +447,8 @@ impl<T: 'static> EventLoop<T> {
|
|||
return Some(WindowEvent::Destroyed);
|
||||
}
|
||||
|
||||
let mut window = state
|
||||
.windows
|
||||
.get_mut()
|
||||
.get_mut(window_id)
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap();
|
||||
let mut window =
|
||||
state.windows.get_mut().get_mut(window_id).unwrap().lock().unwrap();
|
||||
|
||||
if window.frame_callback_state() == FrameCallbackState::Requested {
|
||||
return None;
|
||||
|
|
@ -485,10 +456,8 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
// Reset the frame callbacks state.
|
||||
window.frame_callback_reset();
|
||||
let mut redraw_requested = window_requests
|
||||
.get(window_id)
|
||||
.unwrap()
|
||||
.take_redraw_requested();
|
||||
let mut redraw_requested =
|
||||
window_requests.get(window_id).unwrap().take_redraw_requested();
|
||||
|
||||
// Redraw the frame while at it.
|
||||
redraw_requested |= window.refresh_frame();
|
||||
|
|
@ -498,10 +467,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
if let Some(event) = event {
|
||||
callback(
|
||||
Event::WindowEvent {
|
||||
window_id: crate::window::WindowId(*window_id),
|
||||
event,
|
||||
},
|
||||
Event::WindowEvent { window_id: crate::window::WindowId(*window_id), event },
|
||||
&self.window_target,
|
||||
);
|
||||
}
|
||||
|
|
@ -532,7 +498,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
}
|
||||
|
||||
refresh
|
||||
}
|
||||
},
|
||||
None => false,
|
||||
});
|
||||
}
|
||||
|
|
@ -545,7 +511,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
match &self.window_target.p {
|
||||
PlatformActiveEventLoop::Wayland(window_target) => {
|
||||
window_target.event_loop_awakener.ping();
|
||||
}
|
||||
},
|
||||
#[cfg(x11_platform)]
|
||||
PlatformActiveEventLoop::X(_) => unreachable!(),
|
||||
}
|
||||
|
|
@ -599,9 +565,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
let mut wayland_source = self.wayland_dispatcher.as_source_mut();
|
||||
let event_queue = wayland_source.queue();
|
||||
event_queue.roundtrip(state).map_err(|error| {
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(
|
||||
error
|
||||
))))
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ pub struct EventLoopProxy<T: 'static> {
|
|||
|
||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
||||
fn clone(&self) -> Self {
|
||||
EventLoopProxy {
|
||||
user_events_sender: self.user_events_sender.clone(),
|
||||
}
|
||||
EventLoopProxy { user_events_sender: self.user_events_sender.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -25,8 +23,6 @@ impl<T: 'static> EventLoopProxy<T> {
|
|||
}
|
||||
|
||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
||||
self.user_events_sender
|
||||
.send(event)
|
||||
.map_err(|SendError(error)| EventLoopClosed(error))
|
||||
self.user_events_sender.send(event).map_err(|SendError(error)| EventLoopClosed(error))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,7 @@ impl EventSink {
|
|||
/// Add new window event to a queue.
|
||||
#[inline]
|
||||
pub fn push_window_event(&mut self, event: WindowEvent, window_id: WindowId) {
|
||||
self.window_events.push(Event::WindowEvent {
|
||||
event,
|
||||
window_id: RootWindowId(window_id),
|
||||
});
|
||||
self.window_events.push(Event::WindowEvent { event, window_id: RootWindowId(window_id) });
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -11,11 +11,7 @@ use super::event_loop::ActiveEventLoop;
|
|||
impl ActiveEventLoop {
|
||||
#[inline]
|
||||
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
||||
self.state
|
||||
.borrow()
|
||||
.output_state
|
||||
.outputs()
|
||||
.map(MonitorHandle::new)
|
||||
self.state.borrow().output_state.outputs().map(MonitorHandle::new)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -52,9 +48,7 @@ impl MonitorHandle {
|
|||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
let output_data = self.proxy.data::<OutputData>().unwrap();
|
||||
let dimensions = output_data.with_output_info(|info| {
|
||||
info.modes
|
||||
.iter()
|
||||
.find_map(|mode| mode.current.then_some(mode.dimensions))
|
||||
info.modes.iter().find_map(|mode| mode.current.then_some(mode.dimensions))
|
||||
});
|
||||
|
||||
match dimensions {
|
||||
|
|
@ -85,9 +79,7 @@ impl MonitorHandle {
|
|||
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
||||
let output_data = self.proxy.data::<OutputData>().unwrap();
|
||||
output_data.with_output_info(|info| {
|
||||
info.modes
|
||||
.iter()
|
||||
.find_map(|mode| mode.current.then_some(mode.refresh_rate as u32))
|
||||
info.modes.iter().find_map(|mode| mode.current.then_some(mode.refresh_rate as u32))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ use calloop::timer::{TimeoutAction, Timer};
|
|||
use calloop::{LoopHandle, RegistrationToken};
|
||||
use tracing::warn;
|
||||
|
||||
use sctk::reexports::client::protocol::wl_keyboard::WlKeyboard;
|
||||
use sctk::reexports::client::protocol::wl_keyboard::{
|
||||
Event as WlKeyboardEvent, KeyState as WlKeyState, KeymapFormat as WlKeymapFormat,
|
||||
Event as WlKeyboardEvent, KeyState as WlKeyState, KeymapFormat as WlKeymapFormat, WlKeyboard,
|
||||
};
|
||||
use sctk::reexports::client::protocol::wl_seat::WlSeat;
|
||||
use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, WEnum};
|
||||
|
|
@ -42,16 +41,16 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
WEnum::Value(format) => match format {
|
||||
WlKeymapFormat::NoKeymap => {
|
||||
warn!("non-xkb compatible keymap")
|
||||
}
|
||||
},
|
||||
WlKeymapFormat::XkbV1 => {
|
||||
let context = &mut seat_state.keyboard_state.as_mut().unwrap().xkb_context;
|
||||
context.set_keymap_from_fd(fd, size as usize);
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
WEnum::Unknown(value) => {
|
||||
warn!("unknown keymap format 0x{:x}", value)
|
||||
}
|
||||
},
|
||||
},
|
||||
WlKeyboardEvent::Enter { surface, .. } => {
|
||||
let window_id = wayland::make_wid(&surface);
|
||||
|
|
@ -63,7 +62,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
let was_unfocused = !window.has_focus();
|
||||
window.add_seat_focus(data.seat.id());
|
||||
was_unfocused
|
||||
}
|
||||
},
|
||||
None => return,
|
||||
};
|
||||
|
||||
|
|
@ -78,9 +77,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
|
||||
// The keyboard focus is considered as general focus.
|
||||
if was_unfocused {
|
||||
state
|
||||
.events_sink
|
||||
.push_window_event(WindowEvent::Focused(true), window_id);
|
||||
state.events_sink.push_window_event(WindowEvent::Focused(true), window_id);
|
||||
}
|
||||
|
||||
// HACK: this is just for GNOME not fixing their ordering issue of modifiers.
|
||||
|
|
@ -90,7 +87,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
window_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
WlKeyboardEvent::Leave { surface, .. } => {
|
||||
let window_id = wayland::make_wid(&surface);
|
||||
|
||||
|
|
@ -109,7 +106,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
let mut window = window.lock().unwrap();
|
||||
window.remove_seat_focus(&data.seat.id());
|
||||
window.has_focus()
|
||||
}
|
||||
},
|
||||
None => return,
|
||||
};
|
||||
|
||||
|
|
@ -124,16 +121,10 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
window_id,
|
||||
);
|
||||
|
||||
state
|
||||
.events_sink
|
||||
.push_window_event(WindowEvent::Focused(false), window_id);
|
||||
state.events_sink.push_window_event(WindowEvent::Focused(false), window_id);
|
||||
}
|
||||
}
|
||||
WlKeyboardEvent::Key {
|
||||
key,
|
||||
state: WEnum::Value(WlKeyState::Pressed),
|
||||
..
|
||||
} => {
|
||||
},
|
||||
WlKeyboardEvent::Key { key, state: WEnum::Value(WlKeyState::Pressed), .. } => {
|
||||
let key = key + 8;
|
||||
|
||||
key_input(
|
||||
|
|
@ -151,12 +142,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
RepeatInfo::Disable => return,
|
||||
};
|
||||
|
||||
if !keyboard_state
|
||||
.xkb_context
|
||||
.keymap_mut()
|
||||
.unwrap()
|
||||
.key_repeats(key)
|
||||
{
|
||||
if !keyboard_state.xkb_context.keymap_mut().unwrap().key_repeats(key) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -203,12 +189,8 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
WlKeyboardEvent::Key {
|
||||
key,
|
||||
state: WEnum::Value(WlKeyState::Released),
|
||||
..
|
||||
} => {
|
||||
},
|
||||
WlKeyboardEvent::Key { key, state: WEnum::Value(WlKeyState::Released), .. } => {
|
||||
let key = key + 8;
|
||||
|
||||
key_input(
|
||||
|
|
@ -222,11 +204,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
|
||||
let keyboard_state = seat_state.keyboard_state.as_mut().unwrap();
|
||||
if keyboard_state.repeat_info != RepeatInfo::Disable
|
||||
&& keyboard_state
|
||||
.xkb_context
|
||||
.keymap_mut()
|
||||
.unwrap()
|
||||
.key_repeats(key)
|
||||
&& keyboard_state.xkb_context.keymap_mut().unwrap().key_repeats(key)
|
||||
&& Some(key) == keyboard_state.current_repeat
|
||||
{
|
||||
keyboard_state.current_repeat = None;
|
||||
|
|
@ -234,13 +212,9 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
keyboard_state.loop_handle.remove(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
WlKeyboardEvent::Modifiers {
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
..
|
||||
mods_depressed, mods_latched, mods_locked, group, ..
|
||||
} => {
|
||||
let xkb_context = &mut seat_state.keyboard_state.as_mut().unwrap().xkb_context;
|
||||
let xkb_state = match xkb_context.state_mut() {
|
||||
|
|
@ -257,14 +231,14 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
None => {
|
||||
seat_state.modifiers_pending = true;
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
state.events_sink.push_window_event(
|
||||
WindowEvent::ModifiersChanged(seat_state.modifiers.into()),
|
||||
window_id,
|
||||
);
|
||||
}
|
||||
},
|
||||
WlKeyboardEvent::RepeatInfo { rate, delay } => {
|
||||
let keyboard_state = seat_state.keyboard_state.as_mut().unwrap();
|
||||
keyboard_state.repeat_info = if rate == 0 {
|
||||
|
|
@ -279,7 +253,7 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
|||
let delay = Duration::from_millis(delay as u64);
|
||||
RepeatInfo::Repeat { gap, delay }
|
||||
};
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
@ -353,10 +327,7 @@ impl Default for RepeatInfo {
|
|||
///
|
||||
/// The values are picked based on the default in various compositors and Xorg.
|
||||
fn default() -> Self {
|
||||
Self::Repeat {
|
||||
gap: Duration::from_millis(40),
|
||||
delay: Duration::from_millis(200),
|
||||
}
|
||||
Self::Repeat { gap: Duration::from_millis(40), delay: Duration::from_millis(200) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -372,10 +343,7 @@ pub struct KeyboardData {
|
|||
|
||||
impl KeyboardData {
|
||||
pub fn new(seat: WlSeat) -> Self {
|
||||
Self {
|
||||
window_id: Default::default(),
|
||||
seat,
|
||||
}
|
||||
Self { window_id: Default::default(), seat }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -397,11 +365,7 @@ fn key_input(
|
|||
let device_id = crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId));
|
||||
if let Some(mut key_context) = keyboard_state.xkb_context.key_context() {
|
||||
let event = key_context.process_key_event(keycode, state, repeat);
|
||||
let event = WindowEvent::KeyboardInput {
|
||||
device_id,
|
||||
event,
|
||||
is_synthetic: false,
|
||||
};
|
||||
let event = WindowEvent::KeyboardInput { device_id, event, is_synthetic: false };
|
||||
event_sink.push_window_event(event, window_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,12 +81,12 @@ impl SeatHandler for WinitState {
|
|||
match capability {
|
||||
SeatCapability::Touch if seat_state.touch.is_none() => {
|
||||
seat_state.touch = self.seat_state.get_touch(queue_handle, &seat).ok();
|
||||
}
|
||||
},
|
||||
SeatCapability::Keyboard if seat_state.keyboard_state.is_none() => {
|
||||
let keyboard = seat.get_keyboard(queue_handle, KeyboardData::new(seat.clone()));
|
||||
seat_state.keyboard_state =
|
||||
Some(KeyboardState::new(keyboard, self.loop_handle.clone()));
|
||||
}
|
||||
},
|
||||
SeatCapability::Pointer if seat_state.pointer.is_none() => {
|
||||
let surface = self.compositor_state.create_surface(queue_handle);
|
||||
let surface_id = surface.id();
|
||||
|
|
@ -114,19 +114,15 @@ impl SeatHandler for WinitState {
|
|||
let themed_pointer = Arc::new(themed_pointer);
|
||||
|
||||
// Register cursor surface.
|
||||
self.pointer_surfaces
|
||||
.insert(surface_id, themed_pointer.clone());
|
||||
self.pointer_surfaces.insert(surface_id, themed_pointer.clone());
|
||||
|
||||
seat_state.pointer = Some(themed_pointer);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if let Some(text_input_state) = seat_state
|
||||
.text_input
|
||||
.is_none()
|
||||
.then_some(self.text_input_state.as_ref())
|
||||
.flatten()
|
||||
if let Some(text_input_state) =
|
||||
seat_state.text_input.is_none().then_some(self.text_input_state.as_ref()).flatten()
|
||||
{
|
||||
seat_state.text_input = Some(Arc::new(text_input_state.get_text_input(
|
||||
&seat,
|
||||
|
|
@ -156,7 +152,7 @@ impl SeatHandler for WinitState {
|
|||
touch.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
SeatCapability::Pointer => {
|
||||
if let Some(relative_pointer) = seat_state.relative_pointer.take() {
|
||||
relative_pointer.destroy();
|
||||
|
|
@ -177,11 +173,11 @@ impl SeatHandler for WinitState {
|
|||
pointer.pointer().release();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
SeatCapability::Keyboard => {
|
||||
seat_state.keyboard_state = None;
|
||||
self.on_keyboard_destroy(&seat.id());
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
@ -213,8 +209,7 @@ impl WinitState {
|
|||
let had_focus = window.has_focus();
|
||||
window.remove_seat_focus(seat);
|
||||
if had_focus != window.has_focus() {
|
||||
self.events_sink
|
||||
.push_window_event(WindowEvent::Focused(false), *window_id);
|
||||
self.events_sink.push_window_event(WindowEvent::Focused(false), *window_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@ use sctk::reexports::csd_frame::FrameClick;
|
|||
|
||||
use sctk::compositor::SurfaceData;
|
||||
use sctk::globals::GlobalData;
|
||||
use sctk::seat::pointer::{PointerData, PointerDataExt};
|
||||
use sctk::seat::pointer::{PointerEvent, PointerEventKind, PointerHandler};
|
||||
use sctk::seat::pointer::{
|
||||
PointerData, PointerDataExt, PointerEvent, PointerEventKind, PointerHandler,
|
||||
};
|
||||
use sctk::seat::SeatState;
|
||||
|
||||
use crate::dpi::{LogicalPosition, PhysicalPosition};
|
||||
|
|
@ -81,20 +82,14 @@ impl PointerHandler for WinitState {
|
|||
let _ = pointer.set_cursor(connection, icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
PointerEventKind::Leave { .. } if parent_surface != surface => {
|
||||
window.frame_point_left();
|
||||
}
|
||||
ref kind @ PointerEventKind::Press {
|
||||
button,
|
||||
serial,
|
||||
time,
|
||||
}
|
||||
| ref kind @ PointerEventKind::Release {
|
||||
button,
|
||||
serial,
|
||||
time,
|
||||
} if parent_surface != surface => {
|
||||
},
|
||||
ref kind @ PointerEventKind::Press { button, serial, time }
|
||||
| ref kind @ PointerEventKind::Release { button, serial, time }
|
||||
if parent_surface != surface =>
|
||||
{
|
||||
let click = match wayland_button_to_winit(button) {
|
||||
MouseButton::Left => FrameClick::Normal,
|
||||
MouseButton::Right => FrameClick::Alternate,
|
||||
|
|
@ -112,7 +107,7 @@ impl PointerHandler for WinitState {
|
|||
window_id,
|
||||
&mut self.window_compositor_updates,
|
||||
);
|
||||
}
|
||||
},
|
||||
// Regular events on the main surface.
|
||||
PointerEventKind::Enter { .. } => {
|
||||
self.events_sink
|
||||
|
|
@ -126,13 +121,10 @@ impl PointerHandler for WinitState {
|
|||
pointer.winit_data().inner.lock().unwrap().surface = Some(window_id);
|
||||
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::CursorMoved {
|
||||
device_id,
|
||||
position,
|
||||
},
|
||||
WindowEvent::CursorMoved { device_id, position },
|
||||
window_id,
|
||||
);
|
||||
}
|
||||
},
|
||||
PointerEventKind::Leave { .. } => {
|
||||
if let Some(pointer) = seat_state.pointer.as_ref().map(Arc::downgrade) {
|
||||
window.pointer_left(pointer);
|
||||
|
|
@ -143,25 +135,17 @@ impl PointerHandler for WinitState {
|
|||
|
||||
self.events_sink
|
||||
.push_window_event(WindowEvent::CursorLeft { device_id }, window_id);
|
||||
}
|
||||
},
|
||||
PointerEventKind::Motion { .. } => {
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::CursorMoved {
|
||||
device_id,
|
||||
position,
|
||||
},
|
||||
WindowEvent::CursorMoved { device_id, position },
|
||||
window_id,
|
||||
);
|
||||
}
|
||||
},
|
||||
ref kind @ PointerEventKind::Press { button, serial, .. }
|
||||
| ref kind @ PointerEventKind::Release { button, serial, .. } => {
|
||||
// Update the last button serial.
|
||||
pointer
|
||||
.winit_data()
|
||||
.inner
|
||||
.lock()
|
||||
.unwrap()
|
||||
.latest_button_serial = serial;
|
||||
pointer.winit_data().inner.lock().unwrap().latest_button_serial = serial;
|
||||
|
||||
let button = wayland_button_to_winit(button);
|
||||
let state = if matches!(kind, PointerEventKind::Press { .. }) {
|
||||
|
|
@ -170,19 +154,11 @@ impl PointerHandler for WinitState {
|
|||
ElementState::Released
|
||||
};
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button,
|
||||
},
|
||||
WindowEvent::MouseInput { device_id, state, button },
|
||||
window_id,
|
||||
);
|
||||
}
|
||||
PointerEventKind::Axis {
|
||||
horizontal,
|
||||
vertical,
|
||||
..
|
||||
} => {
|
||||
},
|
||||
PointerEventKind::Axis { horizontal, vertical, .. } => {
|
||||
// Get the current phase.
|
||||
let mut pointer_data = pointer.winit_data().inner.lock().unwrap();
|
||||
|
||||
|
|
@ -223,14 +199,10 @@ impl PointerHandler for WinitState {
|
|||
};
|
||||
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id,
|
||||
delta,
|
||||
phase,
|
||||
},
|
||||
WindowEvent::MouseWheel { device_id, delta, phase },
|
||||
window_id,
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -407,8 +379,7 @@ pub trait WinitPointerDataExt {
|
|||
|
||||
impl WinitPointerDataExt for WlPointer {
|
||||
fn winit_data(&self) -> &WinitPointerData {
|
||||
self.data::<WinitPointerData>()
|
||||
.expect("failed to get pointer data.")
|
||||
self.data::<WinitPointerData>().expect("failed to get pointer data.")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -422,14 +393,13 @@ impl PointerConstraintsState {
|
|||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> Result<Self, BindError> {
|
||||
let pointer_constraints = globals.bind(queue_handle, 1..=1, GlobalData)?;
|
||||
Ok(Self {
|
||||
pointer_constraints,
|
||||
})
|
||||
Ok(Self { pointer_constraints })
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for PointerConstraintsState {
|
||||
type Target = ZwpPointerConstraintsV1;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pointer_constraints
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,31 +61,19 @@ impl Dispatch<ZwpRelativePointerV1, GlobalData, WinitState> for RelativePointerS
|
|||
_qhandle: &QueueHandle<WinitState>,
|
||||
) {
|
||||
let (dx_unaccel, dy_unaccel) = match event {
|
||||
zwp_relative_pointer_v1::Event::RelativeMotion {
|
||||
dx_unaccel,
|
||||
dy_unaccel,
|
||||
..
|
||||
} => (dx_unaccel, dy_unaccel),
|
||||
zwp_relative_pointer_v1::Event::RelativeMotion { dx_unaccel, dy_unaccel, .. } => {
|
||||
(dx_unaccel, dy_unaccel)
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
state
|
||||
.events_sink
|
||||
.push_device_event(DeviceEvent::Motion { axis: 0, value: dx_unaccel }, super::DeviceId);
|
||||
state
|
||||
.events_sink
|
||||
.push_device_event(DeviceEvent::Motion { axis: 1, value: dy_unaccel }, super::DeviceId);
|
||||
state.events_sink.push_device_event(
|
||||
DeviceEvent::Motion {
|
||||
axis: 0,
|
||||
value: dx_unaccel,
|
||||
},
|
||||
super::DeviceId,
|
||||
);
|
||||
state.events_sink.push_device_event(
|
||||
DeviceEvent::Motion {
|
||||
axis: 1,
|
||||
value: dy_unaccel,
|
||||
},
|
||||
super::DeviceId,
|
||||
);
|
||||
state.events_sink.push_device_event(
|
||||
DeviceEvent::MouseMotion {
|
||||
delta: (dx_unaccel, dy_unaccel),
|
||||
},
|
||||
DeviceEvent::MouseMotion { delta: (dx_unaccel, dy_unaccel) },
|
||||
super::DeviceId,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,12 @@ use std::ops::Deref;
|
|||
use sctk::globals::GlobalData;
|
||||
use sctk::reexports::client::{Connection, Proxy, QueueHandle};
|
||||
|
||||
use sctk::reexports::client::delegate_dispatch;
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Dispatch;
|
||||
use sctk::reexports::client::{delegate_dispatch, Dispatch};
|
||||
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_manager_v3::ZwpTextInputManagerV3;
|
||||
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::Event as TextInputEvent;
|
||||
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::{
|
||||
ContentHint, ContentPurpose, ZwpTextInputV3,
|
||||
ContentHint, ContentPurpose, Event as TextInputEvent, ZwpTextInputV3,
|
||||
};
|
||||
|
||||
use crate::event::{Ime, WindowEvent};
|
||||
|
|
@ -77,13 +75,11 @@ impl Dispatch<ZwpTextInputV3, TextInputData, WinitState> for TextInputState {
|
|||
text_input.enable();
|
||||
text_input.set_content_type_by_purpose(window.ime_purpose());
|
||||
text_input.commit();
|
||||
state
|
||||
.events_sink
|
||||
.push_window_event(WindowEvent::Ime(Ime::Enabled), window_id);
|
||||
state.events_sink.push_window_event(WindowEvent::Ime(Ime::Enabled), window_id);
|
||||
}
|
||||
|
||||
window.text_input_entered(text_input);
|
||||
}
|
||||
},
|
||||
TextInputEvent::Leave { surface } => {
|
||||
text_input_data.surface = None;
|
||||
|
||||
|
|
@ -102,15 +98,9 @@ impl Dispatch<ZwpTextInputV3, TextInputData, WinitState> for TextInputState {
|
|||
|
||||
window.text_input_left(text_input);
|
||||
|
||||
state
|
||||
.events_sink
|
||||
.push_window_event(WindowEvent::Ime(Ime::Disabled), window_id);
|
||||
}
|
||||
TextInputEvent::PreeditString {
|
||||
text,
|
||||
cursor_begin,
|
||||
cursor_end,
|
||||
} => {
|
||||
state.events_sink.push_window_event(WindowEvent::Ime(Ime::Disabled), window_id);
|
||||
},
|
||||
TextInputEvent::PreeditString { text, cursor_begin, cursor_end } => {
|
||||
let text = text.unwrap_or_default();
|
||||
let cursor_begin = usize::try_from(cursor_begin)
|
||||
.ok()
|
||||
|
|
@ -119,16 +109,12 @@ impl Dispatch<ZwpTextInputV3, TextInputData, WinitState> for TextInputState {
|
|||
.ok()
|
||||
.and_then(|idx| text.is_char_boundary(idx).then_some(idx));
|
||||
|
||||
text_input_data.pending_preedit = Some(Preedit {
|
||||
text,
|
||||
cursor_begin,
|
||||
cursor_end,
|
||||
})
|
||||
}
|
||||
text_input_data.pending_preedit = Some(Preedit { text, cursor_begin, cursor_end })
|
||||
},
|
||||
TextInputEvent::CommitString { text } => {
|
||||
text_input_data.pending_preedit = None;
|
||||
text_input_data.pending_commit = text;
|
||||
}
|
||||
},
|
||||
TextInputEvent::Done { .. } => {
|
||||
let window_id = match text_input_data.surface.as_ref() {
|
||||
Some(surface) => wayland::make_wid(surface),
|
||||
|
|
@ -150,20 +136,19 @@ impl Dispatch<ZwpTextInputV3, TextInputData, WinitState> for TextInputState {
|
|||
|
||||
// Send preedit.
|
||||
if let Some(preedit) = text_input_data.pending_preedit.take() {
|
||||
let cursor_range = preedit
|
||||
.cursor_begin
|
||||
.map(|b| (b, preedit.cursor_end.unwrap_or(b)));
|
||||
let cursor_range =
|
||||
preedit.cursor_begin.map(|b| (b, preedit.cursor_end.unwrap_or(b)));
|
||||
|
||||
state.events_sink.push_window_event(
|
||||
WindowEvent::Ime(Ime::Preedit(preedit.text, cursor_range)),
|
||||
window_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
TextInputEvent::DeleteSurroundingText { .. } => {
|
||||
// Not handled.
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ impl TouchHandler for WinitState {
|
|||
let seat_state = self.seats.get_mut(&touch.seat().id()).unwrap();
|
||||
|
||||
// Update the state of the point.
|
||||
seat_state
|
||||
.touch_map
|
||||
.insert(id, TouchPoint { surface, location });
|
||||
seat_state.touch_map.insert(id, TouchPoint { surface, location });
|
||||
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::Touch(Touch {
|
||||
|
|
@ -190,9 +188,7 @@ pub trait TouchDataExt {
|
|||
|
||||
impl TouchDataExt for WlTouch {
|
||||
fn seat(&self) -> &WlSeat {
|
||||
self.data::<TouchData>()
|
||||
.expect("failed to get touch data.")
|
||||
.seat()
|
||||
self.data::<TouchData>().expect("failed to get touch data.").seat()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ impl WinitState {
|
|||
Err(e) => {
|
||||
tracing::warn!("Subcompositor protocol not available, ignoring CSD: {e:?}");
|
||||
None
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let output_state = OutputState::new(globals, queue_handle);
|
||||
|
|
@ -218,8 +218,7 @@ impl WinitState {
|
|||
{
|
||||
pos
|
||||
} else {
|
||||
self.window_compositor_updates
|
||||
.push(WindowCompositorUpdate::new(window_id));
|
||||
self.window_compositor_updates.push(WindowCompositorUpdate::new(window_id));
|
||||
self.window_compositor_updates.len() - 1
|
||||
};
|
||||
|
||||
|
|
@ -240,9 +239,7 @@ impl WinitState {
|
|||
}
|
||||
|
||||
pub fn queue_close(updates: &mut Vec<WindowCompositorUpdate>, window_id: WindowId) {
|
||||
let pos = if let Some(pos) = updates
|
||||
.iter()
|
||||
.position(|update| update.window_id == window_id)
|
||||
let pos = if let Some(pos) = updates.iter().position(|update| update.window_id == window_id)
|
||||
{
|
||||
pos
|
||||
} else {
|
||||
|
|
@ -276,15 +273,12 @@ impl WindowHandler for WinitState {
|
|||
) {
|
||||
let window_id = super::make_wid(window.wl_surface());
|
||||
|
||||
let pos = if let Some(pos) = self
|
||||
.window_compositor_updates
|
||||
.iter()
|
||||
.position(|update| update.window_id == window_id)
|
||||
let pos = if let Some(pos) =
|
||||
self.window_compositor_updates.iter().position(|update| update.window_id == window_id)
|
||||
{
|
||||
pos
|
||||
} else {
|
||||
self.window_compositor_updates
|
||||
.push(WindowCompositorUpdate::new(window_id));
|
||||
self.window_compositor_updates.push(WindowCompositorUpdate::new(window_id));
|
||||
self.window_compositor_updates.len() - 1
|
||||
};
|
||||
|
||||
|
|
@ -318,10 +312,7 @@ impl OutputHandler for WinitState {
|
|||
}
|
||||
|
||||
fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, output: WlOutput) {
|
||||
self.monitors
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(MonitorHandle::new(output));
|
||||
self.monitors.lock().unwrap().push(MonitorHandle::new(output));
|
||||
}
|
||||
|
||||
fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, updated: WlOutput) {
|
||||
|
|
@ -388,11 +379,11 @@ impl CompositorHandler for WinitState {
|
|||
}
|
||||
|
||||
impl ProvidesRegistryState for WinitState {
|
||||
sctk::registry_handlers![OutputState, SeatState];
|
||||
|
||||
fn registry(&mut self) -> &mut RegistryState {
|
||||
&mut self.registry_state
|
||||
}
|
||||
|
||||
sctk::registry_handlers![OutputState, SeatState];
|
||||
}
|
||||
|
||||
// The window update coming from the compositor.
|
||||
|
|
@ -413,12 +404,7 @@ pub struct WindowCompositorUpdate {
|
|||
|
||||
impl WindowCompositorUpdate {
|
||||
fn new(window_id: WindowId) -> Self {
|
||||
Self {
|
||||
window_id,
|
||||
resized: false,
|
||||
scale_changed: false,
|
||||
close_window: false,
|
||||
}
|
||||
Self { window_id, resized: false, scale_changed: false, close_window: false }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Dispatch;
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Proxy, QueueHandle};
|
||||
use wayland_protocols_plasma::blur::client::{
|
||||
org_kde_kwin_blur::OrgKdeKwinBlur, org_kde_kwin_blur_manager::OrgKdeKwinBlurManager,
|
||||
};
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
|
||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur_manager::OrgKdeKwinBlurManager;
|
||||
|
||||
use sctk::globals::GlobalData;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Dispatch;
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Proxy, QueueHandle};
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
|
||||
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1;
|
||||
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::Event as FractionalScalingEvent;
|
||||
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1;
|
||||
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::{
|
||||
Event as FractionalScalingEvent, WpFractionalScaleV1,
|
||||
};
|
||||
|
||||
use sctk::globals::GlobalData;
|
||||
|
||||
|
|
@ -41,11 +41,8 @@ impl FractionalScalingManager {
|
|||
surface: &WlSurface,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> WpFractionalScaleV1 {
|
||||
let data = FractionalScaling {
|
||||
surface: surface.clone(),
|
||||
};
|
||||
self.manager
|
||||
.get_fractional_scale(surface, queue_handle, data)
|
||||
let data = FractionalScaling { surface: surface.clone() };
|
||||
self.manager.get_fractional_scale(surface, queue_handle, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Dispatch;
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Proxy, QueueHandle};
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
|
||||
use sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport;
|
||||
use sctk::reexports::protocols::wp::viewporter::client::wp_viewporter::WpViewporter;
|
||||
|
||||
|
|
@ -33,8 +32,7 @@ impl ViewporterState {
|
|||
surface: &WlSurface,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> WpViewport {
|
||||
self.viewporter
|
||||
.get_viewport(surface, queue_handle, GlobalData)
|
||||
self.viewporter.get_viewport(surface, queue_handle, GlobalData)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,9 @@
|
|||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Weak;
|
||||
|
||||
use sctk::reexports::client::delegate_dispatch;
|
||||
use sctk::reexports::client::globals::BindError;
|
||||
use sctk::reexports::client::globals::GlobalList;
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Dispatch;
|
||||
use sctk::reexports::client::{Connection, Proxy, QueueHandle};
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
|
||||
use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_token_v1::{
|
||||
Event as ActivationTokenEvent, XdgActivationTokenV1,
|
||||
};
|
||||
|
|
@ -78,7 +75,7 @@ impl Dispatch<XdgActivationTokenV1, XdgActivationTokenData, WinitState> for XdgA
|
|||
if let Some(attention_requested) = fence.upgrade() {
|
||||
attention_requested.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
},
|
||||
XdgActivationTokenData::Obtain((window_id, serial)) => {
|
||||
state.events_sink.push_window_event(
|
||||
crate::event::WindowEvent::ActivationTokenDone {
|
||||
|
|
@ -87,7 +84,7 @@ impl Dispatch<XdgActivationTokenV1, XdgActivationTokenData, WinitState> for XdgA
|
|||
},
|
||||
*window_id,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
proxy.destroy();
|
||||
|
|
|
|||
|
|
@ -5,13 +5,11 @@ use std::sync::{Arc, Mutex};
|
|||
|
||||
use sctk::reexports::client::protocol::wl_display::WlDisplay;
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Proxy;
|
||||
use sctk::reexports::client::QueueHandle;
|
||||
use sctk::reexports::client::{Proxy, QueueHandle};
|
||||
|
||||
use sctk::compositor::{CompositorState, Region, SurfaceData};
|
||||
use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_v1::XdgActivationV1;
|
||||
use sctk::shell::xdg::window::Window as SctkWindow;
|
||||
use sctk::shell::xdg::window::WindowDecorations;
|
||||
use sctk::shell::xdg::window::{Window as SctkWindow, WindowDecorations};
|
||||
use sctk::shell::WaylandSurface;
|
||||
|
||||
use tracing::warn;
|
||||
|
|
@ -90,15 +88,11 @@ impl Window {
|
|||
|
||||
let surface = state.compositor_state.create_surface(&queue_handle);
|
||||
let compositor = state.compositor_state.clone();
|
||||
let xdg_activation = state
|
||||
.xdg_activation
|
||||
.as_ref()
|
||||
.map(|activation_state| activation_state.global().clone());
|
||||
let xdg_activation =
|
||||
state.xdg_activation.as_ref().map(|activation_state| activation_state.global().clone());
|
||||
let display = event_loop_window_target.connection.display();
|
||||
|
||||
let size: Size = attributes
|
||||
.inner_size
|
||||
.unwrap_or(LogicalSize::new(800., 600.).into());
|
||||
let size: Size = attributes.inner_size.unwrap_or(LogicalSize::new(800., 600.).into());
|
||||
|
||||
// We prefer server side decorations, however to not have decorations we ask for client
|
||||
// side decorations instead.
|
||||
|
|
@ -109,9 +103,7 @@ impl Window {
|
|||
};
|
||||
|
||||
let window =
|
||||
state
|
||||
.xdg_shell
|
||||
.create_window(surface.clone(), default_decorations, &queue_handle);
|
||||
state.xdg_shell.create_window(surface.clone(), default_decorations, &queue_handle);
|
||||
|
||||
let mut window_state = WindowState::new(
|
||||
event_loop_window_target.connection.clone(),
|
||||
|
|
@ -152,7 +144,7 @@ impl Window {
|
|||
match attributes.fullscreen.map(Into::into) {
|
||||
Some(Fullscreen::Exclusive(_)) => {
|
||||
warn!("`Fullscreen::Exclusive` is ignored on Wayland");
|
||||
}
|
||||
},
|
||||
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
|
||||
Some(Fullscreen::Borderless(monitor)) => {
|
||||
let output = monitor.and_then(|monitor| match monitor {
|
||||
|
|
@ -162,7 +154,7 @@ impl Window {
|
|||
});
|
||||
|
||||
window.set_fullscreen(output.as_ref())
|
||||
}
|
||||
},
|
||||
_ if attributes.maximized => window.set_maximized(),
|
||||
_ => (),
|
||||
};
|
||||
|
|
@ -173,10 +165,9 @@ impl Window {
|
|||
}
|
||||
|
||||
// Activate the window when the token is passed.
|
||||
if let (Some(xdg_activation), Some(token)) = (
|
||||
xdg_activation.as_ref(),
|
||||
attributes.platform_specific.activation_token,
|
||||
) {
|
||||
if let (Some(xdg_activation), Some(token)) =
|
||||
(xdg_activation.as_ref(), attributes.platform_specific.activation_token)
|
||||
{
|
||||
xdg_activation.activate(token._token, &surface);
|
||||
}
|
||||
|
||||
|
|
@ -186,20 +177,14 @@ impl Window {
|
|||
// Add the window and window requests into the state.
|
||||
let window_state = Arc::new(Mutex::new(window_state));
|
||||
let window_id = super::make_wid(&surface);
|
||||
state
|
||||
.windows
|
||||
.get_mut()
|
||||
.insert(window_id, window_state.clone());
|
||||
state.windows.get_mut().insert(window_id, window_state.clone());
|
||||
|
||||
let window_requests = WindowRequests {
|
||||
redraw_requested: AtomicBool::new(true),
|
||||
closed: AtomicBool::new(false),
|
||||
};
|
||||
let window_requests = Arc::new(window_requests);
|
||||
state
|
||||
.window_requests
|
||||
.get_mut()
|
||||
.insert(window_id, window_requests.clone());
|
||||
state.window_requests.get_mut().insert(window_id, window_requests.clone());
|
||||
|
||||
// Setup the event sync to insert `WindowEvents` right from the window.
|
||||
let window_events_sink = state.window_events_sink.clone();
|
||||
|
|
@ -209,17 +194,13 @@ impl Window {
|
|||
|
||||
// Do a roundtrip.
|
||||
event_queue.roundtrip(&mut state).map_err(|error| {
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(
|
||||
error
|
||||
))))
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
|
||||
})?;
|
||||
|
||||
// XXX Wait for the initial configure to arrive.
|
||||
while !window_state.lock().unwrap().is_configured() {
|
||||
event_queue.blocking_dispatch(&mut state).map_err(|error| {
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(
|
||||
error
|
||||
))))
|
||||
os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error))))
|
||||
})?;
|
||||
}
|
||||
|
||||
|
|
@ -329,10 +310,7 @@ impl Window {
|
|||
pub fn set_min_inner_size(&self, min_size: Option<Size>) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let min_size = min_size.map(|size| size.to_logical(scale_factor));
|
||||
self.window_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_min_inner_size(min_size);
|
||||
self.window_state.lock().unwrap().set_min_inner_size(min_size);
|
||||
// NOTE: Requires commit to be applied.
|
||||
self.request_redraw();
|
||||
}
|
||||
|
|
@ -342,10 +320,7 @@ impl Window {
|
|||
pub fn set_max_inner_size(&self, max_size: Option<Size>) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let max_size = max_size.map(|size| size.to_logical(scale_factor));
|
||||
self.window_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_max_inner_size(max_size);
|
||||
self.window_state.lock().unwrap().set_max_inner_size(max_size);
|
||||
// NOTE: Requires commit to be applied.
|
||||
self.request_redraw();
|
||||
}
|
||||
|
|
@ -362,10 +337,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn set_transparent(&self, transparent: bool) {
|
||||
self.window_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_transparent(transparent);
|
||||
self.window_state.lock().unwrap().set_transparent(transparent);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -388,10 +360,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
||||
self.window_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.drag_resize_window(direction)
|
||||
self.window_state.lock().unwrap().drag_resize_window(direction)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -499,7 +468,7 @@ impl Window {
|
|||
match fullscreen {
|
||||
Some(Fullscreen::Exclusive(_)) => {
|
||||
warn!("`Fullscreen::Exclusive` is ignored on Wayland");
|
||||
}
|
||||
},
|
||||
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
|
||||
Some(Fullscreen::Borderless(monitor)) => {
|
||||
let output = monitor.and_then(|monitor| match monitor {
|
||||
|
|
@ -509,7 +478,7 @@ impl Window {
|
|||
});
|
||||
|
||||
self.window.set_fullscreen(output.as_ref())
|
||||
}
|
||||
},
|
||||
None => self.window.unset_fullscreen(),
|
||||
}
|
||||
}
|
||||
|
|
@ -526,10 +495,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn set_cursor_visible(&self, visible: bool) {
|
||||
self.window_state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_cursor_visible(visible);
|
||||
self.window_state.lock().unwrap().set_cursor_visible(visible);
|
||||
}
|
||||
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
|
|
@ -538,7 +504,7 @@ impl Window {
|
|||
None => {
|
||||
warn!("`request_user_attention` isn't supported");
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Urgency is only removed by the compositor and there's no need to raise urgency when it
|
||||
|
|
@ -630,10 +596,7 @@ impl Window {
|
|||
|
||||
if window_state.ime_allowed() != allowed && window_state.set_ime_allowed(allowed) {
|
||||
let event = WindowEvent::Ime(if allowed { Ime::Enabled } else { Ime::Disabled });
|
||||
self.window_events_sink
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push_window_event(event, self.window_id);
|
||||
self.window_events_sink.lock().unwrap().push_window_event(event, self.window_id);
|
||||
self.event_loop_awakener.ping();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,13 +226,10 @@ impl WindowState {
|
|||
&self,
|
||||
callback: F,
|
||||
) {
|
||||
self.pointers
|
||||
.iter()
|
||||
.filter_map(Weak::upgrade)
|
||||
.for_each(|pointer| {
|
||||
let data = pointer.pointer().winit_data();
|
||||
callback(pointer.as_ref(), data);
|
||||
})
|
||||
self.pointers.iter().filter_map(Weak::upgrade).for_each(|pointer| {
|
||||
let data = pointer.pointer().winit_data();
|
||||
callback(pointer.as_ref(), data);
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the current state of the frame callback.
|
||||
|
|
@ -257,7 +254,7 @@ impl WindowState {
|
|||
FrameCallbackState::None | FrameCallbackState::Received => {
|
||||
self.frame_callback_state = FrameCallbackState::Requested;
|
||||
surface.frame(&self.queue_handle, surface.clone());
|
||||
}
|
||||
},
|
||||
FrameCallbackState::Requested => (),
|
||||
}
|
||||
}
|
||||
|
|
@ -297,11 +294,11 @@ impl WindowState {
|
|||
// Hide the frame if we were asked to not decorate.
|
||||
frame.set_hidden(!self.decorate);
|
||||
self.frame = Some(frame);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
warn!("Failed to create client side decorations frame: {err}");
|
||||
self.csd_fails = true;
|
||||
}
|
||||
},
|
||||
}
|
||||
} else if configure.decoration_mode == DecorationMode::Server {
|
||||
// Drop the frame for server side decorations to save resources.
|
||||
|
|
@ -320,8 +317,8 @@ impl WindowState {
|
|||
let width = width.map(|w| w.get()).unwrap_or(1);
|
||||
let height = height.map(|h| h.get()).unwrap_or(1);
|
||||
((width, height).into(), false)
|
||||
}
|
||||
(_, _) if stateless => (self.stateless_size, true),
|
||||
},
|
||||
(..) if stateless => (self.stateless_size, true),
|
||||
_ => (self.size, true),
|
||||
}
|
||||
} else {
|
||||
|
|
@ -335,10 +332,8 @@ impl WindowState {
|
|||
// Apply configure bounds only when compositor let the user decide what size to pick.
|
||||
if constrain {
|
||||
let bounds = self.inner_size_bounds(&configure);
|
||||
new_size.width = bounds
|
||||
.0
|
||||
.map(|bound_w| new_size.width.min(bound_w.get()))
|
||||
.unwrap_or(new_size.width);
|
||||
new_size.width =
|
||||
bounds.0.map(|bound_w| new_size.width.min(bound_w.get())).unwrap_or(new_size.width);
|
||||
new_size.height = bounds
|
||||
.1
|
||||
.map(|bound_h| new_size.height.min(bound_h.get()))
|
||||
|
|
@ -346,10 +341,7 @@ impl WindowState {
|
|||
}
|
||||
|
||||
let new_state = configure.state;
|
||||
let old_state = self
|
||||
.last_configure
|
||||
.as_ref()
|
||||
.map(|configure| configure.state);
|
||||
let old_state = self.last_configure.as_ref().map(|configure| configure.state);
|
||||
|
||||
let state_change_requires_resize = old_state
|
||||
.map(|old_state| {
|
||||
|
|
@ -387,10 +379,7 @@ impl WindowState {
|
|||
configure_bounds.0.unwrap_or(NonZeroU32::new(1).unwrap()),
|
||||
configure_bounds.1.unwrap_or(NonZeroU32::new(1).unwrap()),
|
||||
);
|
||||
(
|
||||
configure_bounds.0.and(width),
|
||||
configure_bounds.1.and(height),
|
||||
)
|
||||
(configure_bounds.0.and(width), configure_bounds.1.and(height))
|
||||
} else {
|
||||
configure_bounds
|
||||
}
|
||||
|
|
@ -460,7 +449,7 @@ impl WindowState {
|
|||
_ => return None,
|
||||
};
|
||||
self.window.resize(seat, serial, edge);
|
||||
}
|
||||
},
|
||||
FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)),
|
||||
_ => (),
|
||||
};
|
||||
|
|
@ -643,12 +632,7 @@ impl WindowState {
|
|||
|
||||
/// Try to resize the window when the user can do so.
|
||||
pub fn request_inner_size(&mut self, inner_size: Size) -> PhysicalSize<u32> {
|
||||
if self
|
||||
.last_configure
|
||||
.as_ref()
|
||||
.map(Self::is_stateless)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
if self.last_configure.as_ref().map(Self::is_stateless).unwrap_or(true) {
|
||||
self.resize(inner_size.to_logical(self.scale_factor()))
|
||||
}
|
||||
|
||||
|
|
@ -674,10 +658,7 @@ impl WindowState {
|
|||
);
|
||||
}
|
||||
|
||||
(
|
||||
frame.location(),
|
||||
frame.add_borders(self.size.width, self.size.height).into(),
|
||||
)
|
||||
(frame.location(), frame.add_borders(self.size.width, self.size.height).into())
|
||||
} else {
|
||||
((0, 0), self.size)
|
||||
};
|
||||
|
|
@ -724,16 +705,12 @@ impl WindowState {
|
|||
/// Set the custom cursor icon.
|
||||
pub(crate) fn set_custom_cursor(&mut self, cursor: RootCustomCursor) {
|
||||
let cursor = match cursor {
|
||||
RootCustomCursor {
|
||||
inner: PlatformCustomCursor::Wayland(cursor),
|
||||
} => cursor.0,
|
||||
RootCustomCursor { inner: PlatformCustomCursor::Wayland(cursor) } => cursor.0,
|
||||
#[cfg(x11_platform)]
|
||||
RootCustomCursor {
|
||||
inner: PlatformCustomCursor::X(_),
|
||||
} => {
|
||||
RootCustomCursor { inner: PlatformCustomCursor::X(_) } => {
|
||||
tracing::error!("passed a X11 cursor to Wayland backend");
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let cursor = {
|
||||
|
|
@ -752,11 +729,7 @@ impl WindowState {
|
|||
self.apply_on_pointer(|pointer, _| {
|
||||
let surface = pointer.surface();
|
||||
|
||||
let scale = surface
|
||||
.data::<SurfaceData>()
|
||||
.unwrap()
|
||||
.surface_data()
|
||||
.scale_factor();
|
||||
let scale = surface.data::<SurfaceData>().unwrap().surface_data().scale_factor();
|
||||
|
||||
surface.set_buffer_scale(scale);
|
||||
surface.attach(Some(cursor.buffer.wl_buffer()), 0, 0);
|
||||
|
|
@ -864,7 +837,7 @@ impl WindowState {
|
|||
}),
|
||||
CursorGrabMode::Locked => {
|
||||
self.apply_on_pointer(|_, data| data.unlock_pointer());
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let surface = self.window.wl_surface();
|
||||
|
|
@ -879,7 +852,7 @@ impl WindowState {
|
|||
}),
|
||||
CursorGrabMode::None => {
|
||||
// Current lock/confine was already removed.
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -902,11 +875,9 @@ impl WindowState {
|
|||
|
||||
// Position can be set only for locked cursor.
|
||||
if self.cursor_grab_mode.current_grab_mode != CursorGrabMode::Locked {
|
||||
return Err(ExternalError::Os(os_error!(
|
||||
crate::platform_impl::OsError::Misc(
|
||||
"cursor position can be set only for locked cursor."
|
||||
)
|
||||
)));
|
||||
return Err(ExternalError::Os(os_error!(crate::platform_impl::OsError::Misc(
|
||||
"cursor position can be set only for locked cursor."
|
||||
))));
|
||||
}
|
||||
|
||||
self.apply_on_pointer(|_, data| {
|
||||
|
|
@ -929,9 +900,7 @@ impl WindowState {
|
|||
for pointer in self.pointers.iter().filter_map(|pointer| pointer.upgrade()) {
|
||||
let latest_enter_serial = pointer.pointer().winit_data().latest_enter_serial();
|
||||
|
||||
pointer
|
||||
.pointer()
|
||||
.set_cursor(latest_enter_serial, None, 0, 0);
|
||||
pointer.pointer().set_cursor(latest_enter_serial, None, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -945,19 +914,12 @@ impl WindowState {
|
|||
|
||||
self.decorate = decorate;
|
||||
|
||||
match self
|
||||
.last_configure
|
||||
.as_ref()
|
||||
.map(|configure| configure.decoration_mode)
|
||||
{
|
||||
match self.last_configure.as_ref().map(|configure| configure.decoration_mode) {
|
||||
Some(DecorationMode::Server) if !self.decorate => {
|
||||
// To disable decorations we should request client and hide the frame.
|
||||
self.window
|
||||
.request_decoration_mode(Some(DecorationMode::Client))
|
||||
}
|
||||
_ if self.decorate => self
|
||||
.window
|
||||
.request_decoration_mode(Some(DecorationMode::Server)),
|
||||
self.window.request_decoration_mode(Some(DecorationMode::Client))
|
||||
},
|
||||
_ if self.decorate => self.window.request_decoration_mode(Some(DecorationMode::Server)),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
|
@ -1054,10 +1016,7 @@ impl WindowState {
|
|||
info!("Blur manager unavailable, unable to change blur")
|
||||
}
|
||||
} else if !blurred && self.blur.is_some() {
|
||||
self.blur_manager
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.unset(self.window.wl_surface());
|
||||
self.blur_manager.as_ref().unwrap().unset(self.window.wl_surface());
|
||||
self.blur.take().unwrap().release();
|
||||
}
|
||||
}
|
||||
|
|
@ -1146,10 +1105,7 @@ struct GrabState {
|
|||
|
||||
impl GrabState {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
user_grab_mode: CursorGrabMode::None,
|
||||
current_grab_mode: CursorGrabMode::None,
|
||||
}
|
||||
Self { user_grab_mode: CursorGrabMode::None, current_grab_mode: CursorGrabMode::None }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
//! X11 has a "startup notification" specification similar to Wayland's, see this URL:
|
||||
//! <https://specifications.freedesktop.org/startup-notification-spec/startup-notification-latest.txt>
|
||||
|
||||
use super::{atoms::*, VoidCookie, X11Error, XConnection};
|
||||
use super::atoms::*;
|
||||
use super::{VoidCookie, X11Error, XConnection};
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::fmt::Write;
|
||||
|
|
@ -105,11 +106,9 @@ impl XConnection {
|
|||
0,
|
||||
xproto::WindowClass::INPUT_OUTPUT,
|
||||
screen.root_visual,
|
||||
&xproto::CreateWindowAux::new()
|
||||
.override_redirect(1)
|
||||
.event_mask(
|
||||
xproto::EventMask::STRUCTURE_NOTIFY | xproto::EventMask::PROPERTY_CHANGE,
|
||||
),
|
||||
&xproto::CreateWindowAux::new().override_redirect(1).event_mask(
|
||||
xproto::EventMask::STRUCTURE_NOTIFY | xproto::EventMask::PROPERTY_CHANGE,
|
||||
),
|
||||
)?;
|
||||
|
||||
// Serialize the messages in 20-byte chunks.
|
||||
|
|
@ -130,12 +129,7 @@ impl XConnection {
|
|||
.try_for_each(|event| {
|
||||
// Send each event in order.
|
||||
self.xcb_connection()
|
||||
.send_event(
|
||||
false,
|
||||
screen.root,
|
||||
xproto::EventMask::PROPERTY_CHANGE,
|
||||
event,
|
||||
)
|
||||
.send_event(false, screen.root, xproto::EventMask::PROPERTY_CHANGE, event)
|
||||
.map(VoidCookie::ignore_error)
|
||||
})?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
use std::{
|
||||
io,
|
||||
os::raw::*,
|
||||
path::{Path, PathBuf},
|
||||
str::Utf8Error,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::io;
|
||||
use std::os::raw::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::Utf8Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use percent_encoding::percent_decode;
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt};
|
||||
|
||||
use super::{
|
||||
atoms::{AtomName::None as DndNone, *},
|
||||
util, CookieResultExt, X11Error, XConnection,
|
||||
};
|
||||
use super::atoms::AtomName::None as DndNone;
|
||||
use super::atoms::*;
|
||||
use super::{util, CookieResultExt, X11Error, XConnection};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum DndState {
|
||||
|
|
@ -54,13 +51,7 @@ pub struct Dnd {
|
|||
|
||||
impl Dnd {
|
||||
pub fn new(xconn: Arc<XConnection>) -> Result<Self, X11Error> {
|
||||
Ok(Dnd {
|
||||
xconn,
|
||||
version: None,
|
||||
type_list: None,
|
||||
source_window: None,
|
||||
result: None,
|
||||
})
|
||||
Ok(Dnd { xconn, version: None, type_list: None, source_window: None, result: None })
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
|
|
@ -82,13 +73,13 @@ impl Dnd {
|
|||
DndState::Rejected => (0, atoms[DndNone]),
|
||||
};
|
||||
self.xconn
|
||||
.send_client_msg(
|
||||
target_window,
|
||||
target_window,
|
||||
atoms[XdndStatus] as _,
|
||||
None,
|
||||
[this_window, accepted, 0, 0, action as _],
|
||||
)?
|
||||
.send_client_msg(target_window, target_window, atoms[XdndStatus] as _, None, [
|
||||
this_window,
|
||||
accepted,
|
||||
0,
|
||||
0,
|
||||
action as _,
|
||||
])?
|
||||
.ignore_error();
|
||||
|
||||
Ok(())
|
||||
|
|
@ -106,13 +97,13 @@ impl Dnd {
|
|||
DndState::Rejected => (0, atoms[DndNone]),
|
||||
};
|
||||
self.xconn
|
||||
.send_client_msg(
|
||||
target_window,
|
||||
target_window,
|
||||
atoms[XdndFinished] as _,
|
||||
None,
|
||||
[this_window, accepted, action as _, 0, 0],
|
||||
)?
|
||||
.send_client_msg(target_window, target_window, atoms[XdndFinished] as _, None, [
|
||||
this_window,
|
||||
accepted,
|
||||
action as _,
|
||||
0,
|
||||
0,
|
||||
])?
|
||||
.ignore_error();
|
||||
|
||||
Ok(())
|
||||
|
|
@ -149,8 +140,7 @@ impl Dnd {
|
|||
window: xproto::Window,
|
||||
) -> Result<Vec<c_uchar>, util::GetPropertyError> {
|
||||
let atoms = self.xconn.atoms();
|
||||
self.xconn
|
||||
.get_property(window, atoms[XdndSelection], atoms[TextUriList])
|
||||
self.xconn.get_property(window, atoms[XdndSelection], atoms[TextUriList])
|
||||
}
|
||||
|
||||
pub fn parse_data(&self, data: &mut [c_uchar]) -> Result<Vec<PathBuf>, DndDataParseError> {
|
||||
|
|
|
|||
|
|
@ -16,16 +16,14 @@ use x11_dl::xlib::{
|
|||
use x11rb::protocol::xinput;
|
||||
use x11rb::protocol::xkb::ID as XkbId;
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt as _, ModMask};
|
||||
use x11rb::x11_utils::ExtensionInformation;
|
||||
use x11rb::x11_utils::Serialize;
|
||||
use x11rb::x11_utils::{ExtensionInformation, Serialize};
|
||||
use xkbcommon_dl::xkb_mod_mask_t;
|
||||
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::event::{
|
||||
DeviceEvent, ElementState, Event, Ime, MouseScrollDelta, RawKeyEvent, Touch, TouchPhase,
|
||||
WindowEvent,
|
||||
DeviceEvent, ElementState, Event, Ime, InnerSizeWriter, MouseButton, MouseScrollDelta,
|
||||
RawKeyEvent, Touch, TouchPhase, WindowEvent,
|
||||
};
|
||||
use crate::event::{InnerSizeWriter, MouseButton};
|
||||
use crate::event_loop::ActiveEventLoop as RootAEL;
|
||||
use crate::keyboard::ModifiersState;
|
||||
use crate::platform_impl::common::xkb::{self, XkbState};
|
||||
|
|
@ -33,10 +31,11 @@ use crate::platform_impl::platform::common::xkb::Context;
|
|||
use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver, ImeRequest};
|
||||
use crate::platform_impl::platform::x11::ActiveEventLoop;
|
||||
use crate::platform_impl::platform::ActiveEventLoop as PlatformActiveEventLoop;
|
||||
use crate::platform_impl::x11::atoms::*;
|
||||
use crate::platform_impl::x11::util::cookie::GenericEventCookie;
|
||||
use crate::platform_impl::x11::{
|
||||
atoms::*, mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState,
|
||||
ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
|
||||
mkdid, mkwid, util, CookieResultExt, Device, DeviceId, DeviceInfo, Dnd, DndState, ImeReceiver,
|
||||
ScrollOrientation, UnownedWindow, WindowId,
|
||||
};
|
||||
|
||||
/// The maximum amount of X modifiers to replay.
|
||||
|
|
@ -91,10 +90,10 @@ impl EventProcessor {
|
|||
match request {
|
||||
ImeRequest::Position(window_id, x, y) => {
|
||||
ime.send_xim_spot(window_id, x, y);
|
||||
}
|
||||
},
|
||||
ImeRequest::Allow(window_id, allowed) => {
|
||||
ime.set_ime_allowed(window_id, allowed);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,19 +105,19 @@ impl EventProcessor {
|
|||
ImeEvent::Start => {
|
||||
self.is_composing = true;
|
||||
WindowEvent::Ime(Ime::Preedit("".to_owned(), None))
|
||||
}
|
||||
},
|
||||
ImeEvent::Update(text, position) if self.is_composing => {
|
||||
WindowEvent::Ime(Ime::Preedit(text, Some((position, position))))
|
||||
}
|
||||
},
|
||||
ImeEvent::End => {
|
||||
self.is_composing = false;
|
||||
// Issue empty preedit on `Done`.
|
||||
WindowEvent::Ime(Ime::Preedit(String::new(), None))
|
||||
}
|
||||
},
|
||||
ImeEvent::Disabled => {
|
||||
self.is_composing = false;
|
||||
WindowEvent::Ime(Ime::Disabled)
|
||||
}
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
|
|
@ -182,7 +181,7 @@ impl EventProcessor {
|
|||
};
|
||||
|
||||
self.xinput_key_input(xev.as_mut(), state, &mut callback);
|
||||
}
|
||||
},
|
||||
xlib::GenericEvent => {
|
||||
let wt = Self::window_target(&self.target);
|
||||
let xev: GenericEventCookie =
|
||||
|
|
@ -209,7 +208,7 @@ impl EventProcessor {
|
|||
&mut callback,
|
||||
);
|
||||
self.xinput2_button_input(xev, state, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_Motion => {
|
||||
let xev: &XIDeviceEvent = unsafe { xev.as_event() };
|
||||
self.update_mods_from_xinput2_event(
|
||||
|
|
@ -219,11 +218,11 @@ impl EventProcessor {
|
|||
&mut callback,
|
||||
);
|
||||
self.xinput2_mouse_motion(xev, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_Enter => {
|
||||
let xev: &XIEnterEvent = unsafe { xev.as_event() };
|
||||
self.xinput2_mouse_enter(xev, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_Leave => {
|
||||
let xev: &XILeaveEvent = unsafe { xev.as_event() };
|
||||
self.update_mods_from_xinput2_event(
|
||||
|
|
@ -233,15 +232,15 @@ impl EventProcessor {
|
|||
&mut callback,
|
||||
);
|
||||
self.xinput2_mouse_left(xev, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_FocusIn => {
|
||||
let xev: &XIFocusInEvent = unsafe { xev.as_event() };
|
||||
self.xinput2_focused(xev, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_FocusOut => {
|
||||
let xev: &XIFocusOutEvent = unsafe { xev.as_event() };
|
||||
self.xinput2_unfocused(xev, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_TouchBegin | xinput2::XI_TouchUpdate | xinput2::XI_TouchEnd => {
|
||||
let phase = match evtype {
|
||||
xinput2::XI_TouchBegin => TouchPhase::Started,
|
||||
|
|
@ -252,7 +251,7 @@ impl EventProcessor {
|
|||
|
||||
let xev: &XIDeviceEvent = unsafe { xev.as_event() };
|
||||
self.xinput2_touch(xev, phase, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_RawButtonPress | xinput2::XI_RawButtonRelease => {
|
||||
let state = match evtype {
|
||||
xinput2::XI_RawButtonPress => ElementState::Pressed,
|
||||
|
|
@ -262,11 +261,11 @@ impl EventProcessor {
|
|||
|
||||
let xev: &XIRawEvent = unsafe { xev.as_event() };
|
||||
self.xinput2_raw_button_input(xev, state, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_RawMotion => {
|
||||
let xev: &XIRawEvent = unsafe { xev.as_event() };
|
||||
self.xinput2_raw_mouse_motion(xev, &mut callback);
|
||||
}
|
||||
},
|
||||
xinput2::XI_RawKeyPress | xinput2::XI_RawKeyRelease => {
|
||||
let state = match evtype {
|
||||
xinput2::XI_RawKeyPress => ElementState::Pressed,
|
||||
|
|
@ -276,15 +275,15 @@ impl EventProcessor {
|
|||
|
||||
let xev: &xinput2::XIRawEvent = unsafe { xev.as_event() };
|
||||
self.xinput2_raw_key_input(xev, state, &mut callback);
|
||||
}
|
||||
},
|
||||
|
||||
xinput2::XI_HierarchyChanged => {
|
||||
let xev: &XIHierarchyEvent = unsafe { xev.as_event() };
|
||||
self.xinput2_hierarchy_changed(xev, &mut callback);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
if event_type == self.xkbext.first_event as _ {
|
||||
let xev: &XkbAnyEvent = unsafe { &*(xev as *const _ as *const XkbAnyEvent) };
|
||||
|
|
@ -293,7 +292,7 @@ impl EventProcessor {
|
|||
if event_type == self.randr_event_offset as c_int {
|
||||
self.process_dpi_change(&mut callback);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -399,10 +398,7 @@ impl EventProcessor {
|
|||
let window_id = mkwid(window);
|
||||
|
||||
if xev.data.get_long(0) as xproto::Atom == wt.wm_delete_window {
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::CloseRequested,
|
||||
};
|
||||
let event = Event::WindowEvent { window_id, event: WindowEvent::CloseRequested };
|
||||
callback(&self.target, event);
|
||||
return;
|
||||
}
|
||||
|
|
@ -467,16 +463,16 @@ impl EventProcessor {
|
|||
// where `shift = mem::size_of::<c_short>() * 8`
|
||||
// Note that coordinates are in "desktop space", not "window space"
|
||||
// (in X11 parlance, they're root window coordinates)
|
||||
//let packed_coordinates = xev.data.get_long(2);
|
||||
//let shift = mem::size_of::<libc::c_short>() * 8;
|
||||
//let x = packed_coordinates >> shift;
|
||||
//let y = packed_coordinates & !(x << shift);
|
||||
// let packed_coordinates = xev.data.get_long(2);
|
||||
// let shift = mem::size_of::<libc::c_short>() * 8;
|
||||
// let x = packed_coordinates >> shift;
|
||||
// let y = packed_coordinates & !(x << shift);
|
||||
|
||||
// By our own state flow, `version` should never be `None` at this point.
|
||||
let version = self.dnd.version.unwrap_or(5);
|
||||
|
||||
// Action is specified in versions 2 and up, though we don't need it anyway.
|
||||
//let action = xev.data.get_long(4);
|
||||
// let action = xev.data.get_long(4);
|
||||
|
||||
let accepted = if let Some(ref type_list) = self.dnd.type_list {
|
||||
type_list.contains(&atoms[TextUriList])
|
||||
|
|
@ -533,8 +529,8 @@ impl EventProcessor {
|
|||
}
|
||||
(source_window, DndState::Accepted)
|
||||
} else {
|
||||
// `source_window` won't be part of our DND state if we already rejected the drop in our
|
||||
// `XdndPosition` handler.
|
||||
// `source_window` won't be part of our DND state if we already rejected the drop in
|
||||
// our `XdndPosition` handler.
|
||||
let source_window = xev.data.get_long(0) as xproto::Window;
|
||||
(source_window, DndState::Rejected)
|
||||
};
|
||||
|
|
@ -551,10 +547,7 @@ impl EventProcessor {
|
|||
|
||||
if xev.message_type == atoms[XdndLeave] as c_ulong {
|
||||
self.dnd.reset();
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::HoveredFileCancelled,
|
||||
};
|
||||
let event = Event::WindowEvent { window_id, event: WindowEvent::HoveredFileCancelled };
|
||||
callback(&self.target, event);
|
||||
}
|
||||
}
|
||||
|
|
@ -628,8 +621,8 @@ impl EventProcessor {
|
|||
util::maybe_change(&mut shared_state_lock.inner_position, new_inner_position)
|
||||
} else {
|
||||
// Detect when frame extents change.
|
||||
// Since this isn't synthetic, as per the notes above, this position is relative to the
|
||||
// parent window.
|
||||
// Since this isn't synthetic, as per the notes above, this position is relative to
|
||||
// the parent window.
|
||||
let rel_parent = new_inner_position;
|
||||
if util::maybe_change(&mut shared_state_lock.inner_position_rel_parent, rel_parent)
|
||||
{
|
||||
|
|
@ -651,11 +644,8 @@ impl EventProcessor {
|
|||
let mut shared_state_lock = window.shared_state_lock();
|
||||
|
||||
// We need to convert client area position to window position.
|
||||
let frame_extents = shared_state_lock
|
||||
.frame_extents
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| {
|
||||
let frame_extents =
|
||||
shared_state_lock.frame_extents.as_ref().cloned().unwrap_or_else(|| {
|
||||
let frame_extents = wt.xconn.get_frame_extents_heuristic(xwindow, wt.root);
|
||||
shared_state_lock.frame_extents = Some(frame_extents.clone());
|
||||
frame_extents
|
||||
|
|
@ -668,24 +658,21 @@ impl EventProcessor {
|
|||
drop(shared_state_lock);
|
||||
|
||||
if moved {
|
||||
callback(
|
||||
&self.target,
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Moved(outer.into()),
|
||||
},
|
||||
);
|
||||
callback(&self.target, Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Moved(outer.into()),
|
||||
});
|
||||
}
|
||||
outer
|
||||
};
|
||||
|
||||
if is_synthetic {
|
||||
let mut shared_state_lock = window.shared_state_lock();
|
||||
// If we don't use the existing adjusted value when available, then the user can screw up the
|
||||
// resizing by dragging across monitors *without* dropping the window.
|
||||
let (width, height) = shared_state_lock
|
||||
.dpi_adjusted
|
||||
.unwrap_or((xev.width as u32, xev.height as u32));
|
||||
// If we don't use the existing adjusted value when available, then the user can screw
|
||||
// up the resizing by dragging across monitors *without* dropping the
|
||||
// window.
|
||||
let (width, height) =
|
||||
shared_state_lock.dpi_adjusted.unwrap_or((xev.width as u32, xev.height as u32));
|
||||
|
||||
let last_scale_factor = shared_state_lock.last_monitor.scale_factor;
|
||||
let new_scale_factor = {
|
||||
|
|
@ -719,16 +706,13 @@ impl EventProcessor {
|
|||
drop(shared_state_lock);
|
||||
|
||||
let inner_size = Arc::new(Mutex::new(new_inner_size));
|
||||
callback(
|
||||
&self.target,
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::ScaleFactorChanged {
|
||||
scale_factor: new_scale_factor,
|
||||
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&inner_size)),
|
||||
},
|
||||
callback(&self.target, Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::ScaleFactorChanged {
|
||||
scale_factor: new_scale_factor,
|
||||
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&inner_size)),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
let new_inner_size = *inner_size.lock().unwrap();
|
||||
drop(inner_size);
|
||||
|
|
@ -775,13 +759,10 @@ impl EventProcessor {
|
|||
}
|
||||
|
||||
if resized {
|
||||
callback(
|
||||
&self.target,
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Resized(new_inner_size.into()),
|
||||
},
|
||||
);
|
||||
callback(&self.target, Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Resized(new_inner_size.into()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -812,13 +793,8 @@ impl EventProcessor {
|
|||
// The purpose of it is to deliver initial focused state of the newly created
|
||||
// window, given that we can't rely on `CreateNotify`, due to it being not
|
||||
// sent.
|
||||
let focus = self
|
||||
.with_window(window, |window| window.has_focus())
|
||||
.unwrap_or_default();
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Focused(focus),
|
||||
};
|
||||
let focus = self.with_window(window, |window| window.has_focus()).unwrap_or_default();
|
||||
let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(focus) };
|
||||
|
||||
callback(&self.target, event);
|
||||
}
|
||||
|
|
@ -844,13 +820,7 @@ impl EventProcessor {
|
|||
.expect("Failed to destroy input context");
|
||||
}
|
||||
|
||||
callback(
|
||||
&self.target,
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Destroyed,
|
||||
},
|
||||
);
|
||||
callback(&self.target, Event::WindowEvent { window_id, event: WindowEvent::Destroyed });
|
||||
}
|
||||
|
||||
fn property_notify<T: 'static, F>(&mut self, xev: &XPropertyEvent, mut callback: F)
|
||||
|
|
@ -895,10 +865,7 @@ impl EventProcessor {
|
|||
let window = xev.window as xproto::Window;
|
||||
let window_id = mkwid(window);
|
||||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::RedrawRequested,
|
||||
};
|
||||
let event = Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested };
|
||||
|
||||
callback(&self.target, event);
|
||||
}
|
||||
|
|
@ -937,11 +904,8 @@ impl EventProcessor {
|
|||
// Only keys that can repeat should change the held_key_press state since a
|
||||
// continuously held repeatable key may continue repeating after the press of a
|
||||
// non-repeatable key.
|
||||
let key_repeats = self
|
||||
.xkb_context
|
||||
.keymap_mut()
|
||||
.map(|k| k.key_repeats(keycode))
|
||||
.unwrap_or(false);
|
||||
let key_repeats =
|
||||
self.xkb_context.keymap_mut().map(|k| k.key_repeats(keycode)).unwrap_or(false);
|
||||
let repeat = if key_repeats {
|
||||
let is_latest_held = self.held_key_press == Some(keycode);
|
||||
|
||||
|
|
@ -964,16 +928,12 @@ impl EventProcessor {
|
|||
// NOTE: When the modifier was captured by the XFilterEvents the modifiers for the modifier
|
||||
// itself are out of sync due to XkbState being delivered before XKeyEvent, since it's
|
||||
// being replayed by the XIM, thus we should replay ourselves.
|
||||
let replay = if let Some(position) = self
|
||||
.xfiltered_modifiers
|
||||
.iter()
|
||||
.rev()
|
||||
.position(|&s| s == xev.serial)
|
||||
let replay = if let Some(position) =
|
||||
self.xfiltered_modifiers.iter().rev().position(|&s| s == xev.serial)
|
||||
{
|
||||
// We don't have to replay modifiers pressed before the current event if some events
|
||||
// were not forwarded to us, since their state is irrelevant.
|
||||
self.xfiltered_modifiers
|
||||
.resize(self.xfiltered_modifiers.len() - 1 - position, 0);
|
||||
self.xfiltered_modifiers.resize(self.xfiltered_modifiers.len() - 1 - position, 0);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
|
@ -994,11 +954,7 @@ impl EventProcessor {
|
|||
let event = key_processor.process_key_event(keycode, state, repeat);
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id,
|
||||
event,
|
||||
is_synthetic: false,
|
||||
},
|
||||
event: WindowEvent::KeyboardInput { device_id, event, is_synthetic: false },
|
||||
};
|
||||
callback(&self.target, event);
|
||||
}
|
||||
|
|
@ -1013,10 +969,8 @@ impl EventProcessor {
|
|||
|
||||
let wt = Self::window_target(&self.target);
|
||||
|
||||
if let Some(ic) = wt
|
||||
.ime
|
||||
.as_ref()
|
||||
.and_then(|ime| ime.borrow().get_context(window as XWindow))
|
||||
if let Some(ic) =
|
||||
wt.ime.as_ref().and_then(|ime| ime.borrow().get_context(window as XWindow))
|
||||
{
|
||||
let written = wt.xconn.lookup_utf8(ic, xev);
|
||||
if !written.is_empty() {
|
||||
|
|
@ -1026,10 +980,8 @@ impl EventProcessor {
|
|||
};
|
||||
callback(&self.target, event);
|
||||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Ime(Ime::Commit(written)),
|
||||
};
|
||||
let event =
|
||||
Event::WindowEvent { window_id, event: WindowEvent::Ime(Ime::Commit(written)) };
|
||||
|
||||
self.is_composing = false;
|
||||
callback(&self.target, event);
|
||||
|
|
@ -1064,10 +1016,8 @@ impl EventProcessor {
|
|||
xkb_state.update_modifiers(mask, 0, 0, 0, 0, Self::core_keyboard_group(state));
|
||||
let mods: ModifiersState = xkb_state.modifiers().into();
|
||||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::ModifiersChanged(mods.into()),
|
||||
};
|
||||
let event =
|
||||
Event::WindowEvent { window_id, event: WindowEvent::ModifiersChanged(mods.into()) };
|
||||
|
||||
callback(&self.target, event);
|
||||
}
|
||||
|
|
@ -1093,26 +1043,21 @@ impl EventProcessor {
|
|||
}
|
||||
|
||||
let event = match event.detail as u32 {
|
||||
xlib::Button1 => WindowEvent::MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: MouseButton::Left,
|
||||
xlib::Button1 => {
|
||||
WindowEvent::MouseInput { device_id, state, button: MouseButton::Left }
|
||||
},
|
||||
xlib::Button2 => WindowEvent::MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: MouseButton::Middle,
|
||||
xlib::Button2 => {
|
||||
WindowEvent::MouseInput { device_id, state, button: MouseButton::Middle }
|
||||
},
|
||||
|
||||
xlib::Button3 => WindowEvent::MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: MouseButton::Right,
|
||||
xlib::Button3 => {
|
||||
WindowEvent::MouseInput { device_id, state, button: MouseButton::Right }
|
||||
},
|
||||
|
||||
// Suppress emulated scroll wheel clicks, since we handle the real motion events for those.
|
||||
// In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in
|
||||
// turn) as axis motion, so we don't otherwise special-case these button presses.
|
||||
// Suppress emulated scroll wheel clicks, since we handle the real motion events for
|
||||
// those. In practice, even clicky scroll wheels appear to be reported by
|
||||
// evdev (and XInput2 in turn) as axis motion, so we don't otherwise
|
||||
// special-case these button presses.
|
||||
4..=7 => WindowEvent::MouseWheel {
|
||||
device_id,
|
||||
delta: match event.detail {
|
||||
|
|
@ -1124,22 +1069,10 @@ impl EventProcessor {
|
|||
},
|
||||
phase: TouchPhase::Moved,
|
||||
},
|
||||
8 => WindowEvent::MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: MouseButton::Back,
|
||||
},
|
||||
8 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Back },
|
||||
|
||||
9 => WindowEvent::MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: MouseButton::Forward,
|
||||
},
|
||||
x => WindowEvent::MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: MouseButton::Other(x as u16),
|
||||
},
|
||||
9 => WindowEvent::MouseInput { device_id, state, button: MouseButton::Forward },
|
||||
x => WindowEvent::MouseInput { device_id, state, button: MouseButton::Other(x as u16) },
|
||||
};
|
||||
|
||||
let event = Event::WindowEvent { window_id, event };
|
||||
|
|
@ -1170,10 +1103,7 @@ impl EventProcessor {
|
|||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::CursorMoved {
|
||||
device_id,
|
||||
position,
|
||||
},
|
||||
event: WindowEvent::CursorMoved { device_id, position },
|
||||
};
|
||||
callback(&self.target, event);
|
||||
} else if cursor_moved.is_none() {
|
||||
|
|
@ -1199,10 +1129,8 @@ impl EventProcessor {
|
|||
|
||||
let x = unsafe { *value };
|
||||
|
||||
let event = if let Some(&mut (_, ref mut info)) = physical_device
|
||||
.scroll_axes
|
||||
.iter_mut()
|
||||
.find(|&&mut (axis, _)| axis == i as _)
|
||||
let event = if let Some(&mut (_, ref mut info)) =
|
||||
physical_device.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == i as _)
|
||||
{
|
||||
let delta = (x - info.position) / info.increment;
|
||||
info.position = x;
|
||||
|
|
@ -1210,21 +1138,13 @@ impl EventProcessor {
|
|||
let delta = match info.orientation {
|
||||
ScrollOrientation::Horizontal => {
|
||||
MouseScrollDelta::LineDelta(-delta as f32, 0.0)
|
||||
}
|
||||
},
|
||||
ScrollOrientation::Vertical => MouseScrollDelta::LineDelta(0.0, -delta as f32),
|
||||
};
|
||||
|
||||
WindowEvent::MouseWheel {
|
||||
device_id,
|
||||
delta,
|
||||
phase: TouchPhase::Moved,
|
||||
}
|
||||
WindowEvent::MouseWheel { device_id, delta, phase: TouchPhase::Moved }
|
||||
} else {
|
||||
WindowEvent::AxisMotion {
|
||||
device_id,
|
||||
axis: i as u32,
|
||||
value: unsafe { *value },
|
||||
}
|
||||
WindowEvent::AxisMotion { device_id, axis: i as u32, value: unsafe { *value } }
|
||||
};
|
||||
|
||||
events.push(Event::WindowEvent { window_id, event });
|
||||
|
|
@ -1253,12 +1173,11 @@ impl EventProcessor {
|
|||
if let Some(all_info) = DeviceInfo::get(&wt.xconn, super::ALL_DEVICES.into()) {
|
||||
let mut devices = self.devices.borrow_mut();
|
||||
for device_info in all_info.iter() {
|
||||
// The second expression is need for resetting to work correctly on i3, and
|
||||
// presumably some other WMs. On those, `XI_Enter` doesn't include the physical
|
||||
// device ID, so both `sourceid` and `deviceid` are the virtual device.
|
||||
if device_info.deviceid == event.sourceid
|
||||
// This is needed for resetting to work correctly on i3, and
|
||||
// presumably some other WMs. On those, `XI_Enter` doesn't include
|
||||
// the physical device ID, so both `sourceid` and `deviceid` are
|
||||
// the virtual device.
|
||||
|| device_info.attachment == event.sourceid
|
||||
|| device_info.attachment == event.sourceid
|
||||
{
|
||||
let device_id = DeviceId(device_info.deviceid as _);
|
||||
if let Some(device) = devices.get_mut(&device_id) {
|
||||
|
|
@ -1271,18 +1190,13 @@ impl EventProcessor {
|
|||
if self.window_exists(window) {
|
||||
let position = PhysicalPosition::new(event.event_x, event.event_y);
|
||||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::CursorEntered { device_id },
|
||||
};
|
||||
let event =
|
||||
Event::WindowEvent { window_id, event: WindowEvent::CursorEntered { device_id } };
|
||||
callback(&self.target, event);
|
||||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::CursorMoved {
|
||||
device_id,
|
||||
position,
|
||||
},
|
||||
event: WindowEvent::CursorMoved { device_id, position },
|
||||
};
|
||||
callback(&self.target, event);
|
||||
}
|
||||
|
|
@ -1322,9 +1236,7 @@ impl EventProcessor {
|
|||
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
|
||||
|
||||
if let Some(ime) = wt.ime.as_ref() {
|
||||
ime.borrow_mut()
|
||||
.focus(xev.event)
|
||||
.expect("Failed to focus input context");
|
||||
ime.borrow_mut().focus(xev.event).expect("Failed to focus input context");
|
||||
}
|
||||
|
||||
if self.active_window == Some(window) {
|
||||
|
|
@ -1342,10 +1254,7 @@ impl EventProcessor {
|
|||
window.shared_state_lock().has_focus = true;
|
||||
}
|
||||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Focused(true),
|
||||
};
|
||||
let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(true) };
|
||||
callback(&self.target, event);
|
||||
|
||||
// Issue key press events for all pressed keys
|
||||
|
|
@ -1370,10 +1279,7 @@ impl EventProcessor {
|
|||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::CursorMoved {
|
||||
device_id: mkdid(pointer_id as _),
|
||||
position,
|
||||
},
|
||||
event: WindowEvent::CursorMoved { device_id: mkdid(pointer_id as _), position },
|
||||
};
|
||||
callback(&self.target, event);
|
||||
}
|
||||
|
|
@ -1393,9 +1299,7 @@ impl EventProcessor {
|
|||
}
|
||||
|
||||
if let Some(ime) = wt.ime.as_ref() {
|
||||
ime.borrow_mut()
|
||||
.unfocus(xev.event)
|
||||
.expect("Failed to unfocus input context");
|
||||
ime.borrow_mut().unfocus(xev.event).expect("Failed to unfocus input context");
|
||||
}
|
||||
|
||||
if self.active_window.take() == Some(window) {
|
||||
|
|
@ -1427,10 +1331,7 @@ impl EventProcessor {
|
|||
window.shared_state_lock().has_focus = false;
|
||||
}
|
||||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Focused(false),
|
||||
};
|
||||
let event = Event::WindowEvent { window_id, event: WindowEvent::Focused(false) };
|
||||
callback(&self.target, event)
|
||||
}
|
||||
}
|
||||
|
|
@ -1497,10 +1398,7 @@ impl EventProcessor {
|
|||
if xev.flags & xinput2::XIPointerEmulated == 0 {
|
||||
let event = Event::DeviceEvent {
|
||||
device_id: mkdid(xev.deviceid as xinput::DeviceId),
|
||||
event: DeviceEvent::Button {
|
||||
state,
|
||||
button: xev.detail as u32,
|
||||
},
|
||||
event: DeviceEvent::Button { state, button: xev.detail as u32 },
|
||||
};
|
||||
callback(&self.target, event);
|
||||
}
|
||||
|
|
@ -1535,15 +1433,12 @@ impl EventProcessor {
|
|||
1 => mouse_delta.set_y(x),
|
||||
2 => scroll_delta.set_x(x as f32),
|
||||
3 => scroll_delta.set_y(x as f32),
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let event = Event::DeviceEvent {
|
||||
device_id: did,
|
||||
event: DeviceEvent::Motion {
|
||||
axis: i as u32,
|
||||
value: x,
|
||||
},
|
||||
event: DeviceEvent::Motion { axis: i as u32, value: x },
|
||||
};
|
||||
callback(&self.target, event);
|
||||
|
||||
|
|
@ -1589,16 +1484,10 @@ impl EventProcessor {
|
|||
}
|
||||
let physical_key = xkb::raw_keycode_to_physicalkey(keycode);
|
||||
|
||||
callback(
|
||||
&self.target,
|
||||
Event::DeviceEvent {
|
||||
device_id,
|
||||
event: DeviceEvent::Key(RawKeyEvent {
|
||||
physical_key,
|
||||
state,
|
||||
}),
|
||||
},
|
||||
);
|
||||
callback(&self.target, Event::DeviceEvent {
|
||||
device_id,
|
||||
event: DeviceEvent::Key(RawKeyEvent { physical_key, state }),
|
||||
});
|
||||
}
|
||||
|
||||
fn xinput2_hierarchy_changed<T: 'static, F>(&mut self, xev: &XIHierarchyEvent, mut callback: F)
|
||||
|
|
@ -1613,21 +1502,15 @@ impl EventProcessor {
|
|||
for info in infos {
|
||||
if 0 != info.flags & (xinput2::XISlaveAdded | xinput2::XIMasterAdded) {
|
||||
self.init_device(info.deviceid as xinput::DeviceId);
|
||||
callback(
|
||||
&self.target,
|
||||
Event::DeviceEvent {
|
||||
device_id: mkdid(info.deviceid as xinput::DeviceId),
|
||||
event: DeviceEvent::Added,
|
||||
},
|
||||
);
|
||||
callback(&self.target, Event::DeviceEvent {
|
||||
device_id: mkdid(info.deviceid as xinput::DeviceId),
|
||||
event: DeviceEvent::Added,
|
||||
});
|
||||
} else if 0 != info.flags & (xinput2::XISlaveRemoved | xinput2::XIMasterRemoved) {
|
||||
callback(
|
||||
&self.target,
|
||||
Event::DeviceEvent {
|
||||
device_id: mkdid(info.deviceid as xinput::DeviceId),
|
||||
event: DeviceEvent::Removed,
|
||||
},
|
||||
);
|
||||
callback(&self.target, Event::DeviceEvent {
|
||||
device_id: mkdid(info.deviceid as xinput::DeviceId),
|
||||
event: DeviceEvent::Removed,
|
||||
});
|
||||
let mut devices = self.devices.borrow_mut();
|
||||
devices.remove(&DeviceId(info.deviceid as xinput::DeviceId));
|
||||
}
|
||||
|
|
@ -1669,7 +1552,7 @@ impl EventProcessor {
|
|||
self.send_modifiers(window_id, mods, true, &mut callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
xlib::XkbMapNotify => {
|
||||
let xcb = wt.xconn.xcb_connection().get_raw_xcb_connection();
|
||||
self.xkb_context.set_keymap_from_x11(xcb);
|
||||
|
|
@ -1683,7 +1566,7 @@ impl EventProcessor {
|
|||
let mods = state.modifiers().into();
|
||||
self.send_modifiers(window_id, mods, true, &mut callback);
|
||||
}
|
||||
}
|
||||
},
|
||||
xlib::XkbStateNotify => {
|
||||
let xev = unsafe { &*(xev as *const _ as *const xlib::XkbStateNotifyEvent) };
|
||||
|
||||
|
|
@ -1708,8 +1591,8 @@ impl EventProcessor {
|
|||
let mods = state.modifiers().into();
|
||||
self.send_modifiers(window_id, mods, true, &mut callback);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1825,22 +1708,13 @@ impl EventProcessor {
|
|||
|
||||
// Build the XKB modifiers from the regular state.
|
||||
let mut depressed = 0u32;
|
||||
if let Some(shift) = mods_indices
|
||||
.shift
|
||||
.filter(|_| ModMask::SHIFT.intersects(state))
|
||||
{
|
||||
if let Some(shift) = mods_indices.shift.filter(|_| ModMask::SHIFT.intersects(state)) {
|
||||
depressed |= 1 << shift;
|
||||
}
|
||||
if let Some(caps) = mods_indices
|
||||
.caps
|
||||
.filter(|_| ModMask::LOCK.intersects(state))
|
||||
{
|
||||
if let Some(caps) = mods_indices.caps.filter(|_| ModMask::LOCK.intersects(state)) {
|
||||
depressed |= 1 << caps;
|
||||
}
|
||||
if let Some(ctrl) = mods_indices
|
||||
.ctrl
|
||||
.filter(|_| ModMask::CONTROL.intersects(state))
|
||||
{
|
||||
if let Some(ctrl) = mods_indices.ctrl.filter(|_| ModMask::CONTROL.intersects(state)) {
|
||||
depressed |= 1 << ctrl;
|
||||
}
|
||||
if let Some(alt) = mods_indices.alt.filter(|_| ModMask::M1.intersects(state)) {
|
||||
|
|
@ -1897,10 +1771,7 @@ impl EventProcessor {
|
|||
|
||||
// Update modifiers state and emit key events based on which keys are currently pressed.
|
||||
let window_target = Self::window_target(target);
|
||||
let xcb = window_target
|
||||
.xconn
|
||||
.xcb_connection()
|
||||
.get_raw_xcb_connection();
|
||||
let xcb = window_target.xconn.xcb_connection().get_raw_xcb_connection();
|
||||
|
||||
let keymap = match xkb_context.keymap_mut() {
|
||||
Some(keymap) => keymap,
|
||||
|
|
@ -1917,20 +1788,13 @@ impl EventProcessor {
|
|||
None => return,
|
||||
};
|
||||
|
||||
for keycode in window_target
|
||||
.xconn
|
||||
.query_keymap()
|
||||
.into_iter()
|
||||
.filter(|k| *k >= KEYCODE_OFFSET)
|
||||
for keycode in
|
||||
window_target.xconn.query_keymap().into_iter().filter(|k| *k >= KEYCODE_OFFSET)
|
||||
{
|
||||
let event = key_processor.process_key_event(keycode as u32, state, false);
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::KeyboardInput {
|
||||
device_id,
|
||||
event,
|
||||
is_synthetic: true,
|
||||
},
|
||||
event: WindowEvent::KeyboardInput { device_id, event, is_synthetic: true },
|
||||
};
|
||||
callback(target, event);
|
||||
}
|
||||
|
|
@ -1941,9 +1805,7 @@ impl EventProcessor {
|
|||
F: FnMut(&RootAEL, Event<T>),
|
||||
{
|
||||
let wt = Self::window_target(&self.target);
|
||||
wt.xconn
|
||||
.reload_database()
|
||||
.expect("failed to reload Xft database");
|
||||
wt.xconn.reload_database().expect("failed to reload Xft database");
|
||||
|
||||
// In the future, it would be quite easy to emit monitor hotplug events.
|
||||
let prev_list = {
|
||||
|
|
@ -1954,10 +1816,7 @@ impl EventProcessor {
|
|||
}
|
||||
};
|
||||
|
||||
let new_list = wt
|
||||
.xconn
|
||||
.available_monitors()
|
||||
.expect("Failed to get monitor list");
|
||||
let new_list = wt.xconn.available_monitors().expect("Failed to get monitor list");
|
||||
for new_monitor in new_list {
|
||||
// Previous list may be empty, in case of disconnecting and
|
||||
// reconnecting the only one monitor. We still need to emit events in
|
||||
|
|
@ -1988,13 +1847,13 @@ fn is_first_touch(first: &mut Option<u64>, num: &mut u32, id: u64, phase: TouchP
|
|||
*first = Some(id);
|
||||
}
|
||||
*num += 1;
|
||||
}
|
||||
},
|
||||
TouchPhase::Cancelled | TouchPhase::Ended => {
|
||||
if *first == Some(id) {
|
||||
*first = None;
|
||||
}
|
||||
*num = num.saturating_sub(1);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1,5 @@
|
|||
pub use x11_dl::{error::OpenError, xcursor::*, xinput2::*, xlib::*, xlib_xcb::*};
|
||||
pub use x11_dl::error::OpenError;
|
||||
pub use x11_dl::xcursor::*;
|
||||
pub use x11_dl::xinput2::*;
|
||||
pub use x11_dl::xlib::*;
|
||||
pub use x11_dl::xlib_xcb::*;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use std::{collections::HashMap, os::raw::c_char, ptr, sync::Arc};
|
||||
use std::collections::HashMap;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{ffi, XConnection, XError};
|
||||
|
||||
use super::{
|
||||
context::{ImeContext, ImeContextCreationError},
|
||||
inner::{close_im, ImeInner},
|
||||
input_method::PotentialInputMethods,
|
||||
};
|
||||
use super::context::{ImeContext, ImeContextCreationError};
|
||||
use super::inner::{close_im, ImeInner};
|
||||
use super::input_method::PotentialInputMethods;
|
||||
|
||||
pub(crate) unsafe fn xim_set_callback(
|
||||
xconn: &Arc<XConnection>,
|
||||
|
|
@ -24,8 +25,8 @@ pub(crate) unsafe fn xim_set_callback(
|
|||
// available. Note that this has nothing to do with what input methods are open or able to be
|
||||
// opened, and simply uses the modifiers that are set when the callback is set.
|
||||
// * This is called per locale modifier, not per input method opened with that locale modifier.
|
||||
// * Trying to set this for multiple locale modifiers causes problems, i.e. one of the rebuilt
|
||||
// input contexts would always silently fail to use the input method.
|
||||
// * Trying to set this for multiple locale modifiers causes problems, i.e. one of the rebuilt input
|
||||
// contexts would always silently fail to use the input method.
|
||||
pub(crate) unsafe fn set_instantiate_callback(
|
||||
xconn: &Arc<XConnection>,
|
||||
client_data: ffi::XPointer,
|
||||
|
|
@ -119,18 +120,12 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> {
|
|||
let spot = old_context.as_ref().map(|old_context| old_context.ic_spot);
|
||||
|
||||
// Check if the IME was allowed on that context.
|
||||
let is_allowed = old_context
|
||||
.as_ref()
|
||||
.map(|old_context| old_context.is_allowed())
|
||||
.unwrap_or_default();
|
||||
let is_allowed =
|
||||
old_context.as_ref().map(|old_context| old_context.is_allowed()).unwrap_or_default();
|
||||
|
||||
// We can't use the style from the old context here, since it may change on reload, so
|
||||
// pick style from the new XIM based on the old state.
|
||||
let style = if is_allowed {
|
||||
new_im.preedit_style
|
||||
} else {
|
||||
new_im.none_style
|
||||
};
|
||||
let style = if is_allowed { new_im.preedit_style } else { new_im.none_style };
|
||||
|
||||
let new_context = {
|
||||
let result = unsafe {
|
||||
|
|
@ -208,7 +203,7 @@ pub unsafe extern "C" fn xim_destroy_callback(
|
|||
Err(err) => {
|
||||
// We have no usable input methods!
|
||||
panic!("Failed to open fallback input method: {err:?}");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,7 @@ type XIMProcNonnull = unsafe extern "C" fn(ffi::XIM, ffi::XPointer, ffi::XPointe
|
|||
/// Wrapper for creating XIM callbacks.
|
||||
#[inline]
|
||||
fn create_xim_callback(client_data: ffi::XPointer, callback: XIMProcNonnull) -> ffi::XIMCallback {
|
||||
XIMCallback {
|
||||
client_data,
|
||||
callback: Some(callback),
|
||||
}
|
||||
XIMCallback { client_data, callback: Some(callback) }
|
||||
}
|
||||
|
||||
/// The server started preedit.
|
||||
|
|
@ -68,9 +65,7 @@ extern "C" fn preedit_done_callback(
|
|||
}
|
||||
|
||||
fn calc_byte_position(text: &[char], pos: usize) -> usize {
|
||||
text.iter()
|
||||
.take(pos)
|
||||
.fold(0, |byte_pos, text| byte_pos + text.len_utf8())
|
||||
text.iter().take(pos).fold(0, |byte_pos, text| byte_pos + text.len_utf8())
|
||||
}
|
||||
|
||||
/// Preedit text information to be drawn inline by the client.
|
||||
|
|
@ -112,9 +107,7 @@ extern "C" fn preedit_draw_callback(
|
|||
|
||||
let new_text = unsafe { CStr::from_ptr(new_text) };
|
||||
|
||||
String::from(new_text.to_str().expect("Invalid UTF-8 String from IME"))
|
||||
.chars()
|
||||
.collect()
|
||||
String::from(new_text.to_str().expect("Invalid UTF-8 String from IME")).chars().collect()
|
||||
};
|
||||
let mut old_text_tail = client_data.text.split_off(chg_range.end);
|
||||
client_data.text.truncate(chg_range.start);
|
||||
|
|
@ -171,12 +164,7 @@ impl PreeditCallbacks {
|
|||
let caret_callback = create_xim_callback(client_data, preedit_caret_callback);
|
||||
let draw_callback = create_xim_callback(client_data, preedit_draw_callback);
|
||||
|
||||
PreeditCallbacks {
|
||||
start_callback,
|
||||
done_callback,
|
||||
caret_callback,
|
||||
draw_callback,
|
||||
}
|
||||
PreeditCallbacks { start_callback, done_callback, caret_callback, draw_callback }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,8 +183,8 @@ pub struct ImeContext {
|
|||
pub(crate) ic: ffi::XIC,
|
||||
pub(crate) ic_spot: ffi::XPoint,
|
||||
pub(crate) style: Style,
|
||||
// Since the data is passed shared between X11 XIM callbacks, but couldn't be directly free from
|
||||
// there we keep the pointer to automatically deallocate it.
|
||||
// Since the data is passed shared between X11 XIM callbacks, but couldn't be directly free
|
||||
// from there we keep the pointer to automatically deallocate it.
|
||||
_client_data: Box<ImeContextClientData>,
|
||||
}
|
||||
|
||||
|
|
@ -233,9 +221,7 @@ impl ImeContext {
|
|||
}
|
||||
.ok_or(ImeContextCreationError::Null)?;
|
||||
|
||||
xconn
|
||||
.check_errors()
|
||||
.map_err(ImeContextCreationError::XError)?;
|
||||
xconn.check_errors().map_err(ImeContextCreationError::XError)?;
|
||||
|
||||
let mut context = ImeContext {
|
||||
ic,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use std::{collections::HashMap, mem, sync::Arc};
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{ffi, XConnection, XError};
|
||||
|
||||
use super::{
|
||||
context::ImeContext,
|
||||
input_method::{InputMethod, PotentialInputMethods},
|
||||
};
|
||||
use super::context::ImeContext;
|
||||
use super::input_method::{InputMethod, PotentialInputMethods};
|
||||
use crate::platform_impl::platform::x11::ime::ImeEventSender;
|
||||
|
||||
pub(crate) unsafe fn close_im(xconn: &Arc<XConnection>, im: ffi::XIM) -> Result<(), XError> {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
use std::{
|
||||
env,
|
||||
ffi::{CStr, CString, IntoStringError},
|
||||
fmt,
|
||||
os::raw::{c_char, c_ulong, c_ushort},
|
||||
ptr,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use std::ffi::{CStr, CString, IntoStringError};
|
||||
use std::os::raw::{c_char, c_ulong, c_ushort};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{env, fmt, ptr};
|
||||
|
||||
use super::{super::atoms::*, ffi, util, XConnection, XError};
|
||||
use super::super::atoms::*;
|
||||
use super::{ffi, util, XConnection, XError};
|
||||
use x11rb::protocol::xproto;
|
||||
|
||||
static GLOBAL_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
|
@ -18,17 +15,12 @@ unsafe fn open_im(xconn: &Arc<XConnection>, locale_modifiers: &CStr) -> Option<f
|
|||
// XSetLocaleModifiers returns...
|
||||
// * The current locale modifiers if it's given a NULL pointer.
|
||||
// * The new locale modifiers if we succeeded in setting them.
|
||||
// * NULL if the locale modifiers string is malformed or if the
|
||||
// current locale is not supported by Xlib.
|
||||
// * NULL if the locale modifiers string is malformed or if the current locale is not supported
|
||||
// by Xlib.
|
||||
unsafe { (xconn.xlib.XSetLocaleModifiers)(locale_modifiers.as_ptr()) };
|
||||
|
||||
let im = unsafe {
|
||||
(xconn.xlib.XOpenIM)(
|
||||
xconn.display,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
)
|
||||
(xconn.xlib.XOpenIM)(xconn.display, ptr::null_mut(), ptr::null_mut(), ptr::null_mut())
|
||||
};
|
||||
|
||||
if im.is_null() {
|
||||
|
|
@ -73,10 +65,10 @@ impl InputMethod {
|
|||
.for_each(|style| match *style {
|
||||
XIM_PREEDIT_STYLE => {
|
||||
preedit_style = Some(Style::Preedit(*style));
|
||||
}
|
||||
},
|
||||
XIM_NOTHING_STYLE if preedit_style.is_none() => {
|
||||
preedit_style = Some(Style::Nothing(*style))
|
||||
}
|
||||
},
|
||||
XIM_NONE_STYLE => none_style = Some(Style::None(*style)),
|
||||
_ => (),
|
||||
});
|
||||
|
|
@ -91,12 +83,7 @@ impl InputMethod {
|
|||
let preedit_style = preedit_style.unwrap_or_else(|| none_style.unwrap());
|
||||
let none_style = none_style.unwrap_or(preedit_style);
|
||||
|
||||
Some(InputMethod {
|
||||
im,
|
||||
_name: name,
|
||||
preedit_style,
|
||||
none_style,
|
||||
})
|
||||
Some(InputMethod { im, _name: name, preedit_style, none_style })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,10 +219,7 @@ impl InputMethodName {
|
|||
pub fn from_str(string: &str) -> Self {
|
||||
let c_string =
|
||||
CString::new(string).expect("String used to construct CString contained null byte");
|
||||
InputMethodName {
|
||||
c_string,
|
||||
string: string.to_owned(),
|
||||
}
|
||||
InputMethodName { c_string, string: string.to_owned() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -253,17 +237,11 @@ struct PotentialInputMethod {
|
|||
|
||||
impl PotentialInputMethod {
|
||||
pub fn from_string(string: String) -> Self {
|
||||
PotentialInputMethod {
|
||||
name: InputMethodName::from_string(string),
|
||||
successful: None,
|
||||
}
|
||||
PotentialInputMethod { name: InputMethodName::from_string(string), successful: None }
|
||||
}
|
||||
|
||||
pub fn from_str(string: &str) -> Self {
|
||||
PotentialInputMethod {
|
||||
name: InputMethodName::from_str(string),
|
||||
successful: None,
|
||||
}
|
||||
PotentialInputMethod { name: InputMethodName::from_str(string), successful: None }
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
|
|
@ -297,9 +275,7 @@ pub(crate) struct PotentialInputMethods {
|
|||
|
||||
impl PotentialInputMethods {
|
||||
pub fn new(xconn: &Arc<XConnection>) -> Self {
|
||||
let xmodifiers = env::var("XMODIFIERS")
|
||||
.ok()
|
||||
.map(PotentialInputMethod::from_string);
|
||||
let xmodifiers = env::var("XMODIFIERS").ok().map(PotentialInputMethod::from_string);
|
||||
PotentialInputMethods {
|
||||
// Since passing "" to XSetLocaleModifiers results in it defaulting to the value of
|
||||
// XMODIFIERS, it's worth noting what happens if XMODIFIERS is also "". If simply
|
||||
|
|
|
|||
|
|
@ -5,10 +5,8 @@ mod context;
|
|||
mod inner;
|
||||
mod input_method;
|
||||
|
||||
use std::sync::{
|
||||
mpsc::{Receiver, Sender},
|
||||
Arc,
|
||||
};
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -16,13 +14,11 @@ use tracing::debug;
|
|||
|
||||
use super::{ffi, util, XConnection, XError};
|
||||
|
||||
use self::callbacks::*;
|
||||
use self::context::ImeContext;
|
||||
pub use self::context::ImeContextCreationError;
|
||||
use self::{
|
||||
callbacks::*,
|
||||
context::ImeContext,
|
||||
inner::{close_im, ImeInner},
|
||||
input_method::{PotentialInputMethods, Style},
|
||||
};
|
||||
use self::inner::{close_im, ImeInner};
|
||||
use self::input_method::{PotentialInputMethods, Style};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
|
|
@ -73,10 +69,8 @@ impl Ime {
|
|||
let mut inner = Box::new(ImeInner::new(xconn, potential_input_methods, event_sender));
|
||||
let inner_ptr = Box::into_raw(inner);
|
||||
let client_data = inner_ptr as _;
|
||||
let destroy_callback = ffi::XIMCallback {
|
||||
client_data,
|
||||
callback: Some(xim_destroy_callback),
|
||||
};
|
||||
let destroy_callback =
|
||||
ffi::XIMCallback { client_data, callback: Some(xim_destroy_callback) };
|
||||
inner = unsafe { Box::from_raw(inner_ptr) };
|
||||
inner.destroy_callback = destroy_callback;
|
||||
(inner, client_data)
|
||||
|
|
@ -105,9 +99,7 @@ impl Ime {
|
|||
inner.im = Some(input_method);
|
||||
Ok(Ime { xconn, inner })
|
||||
} else {
|
||||
Err(ImeCreationError::OpenFailure(Box::new(
|
||||
inner.potential_input_methods,
|
||||
)))
|
||||
Err(ImeCreationError::OpenFailure(Box::new(inner.potential_input_methods)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,11 +121,7 @@ impl Ime {
|
|||
None
|
||||
} else {
|
||||
let im = self.inner.im.as_ref().unwrap();
|
||||
let style = if with_preedit {
|
||||
im.preedit_style
|
||||
} else {
|
||||
im.none_style
|
||||
};
|
||||
let style = if with_preedit { im.preedit_style } else { im.none_style };
|
||||
|
||||
let context = unsafe {
|
||||
ImeContext::new(
|
||||
|
|
@ -159,10 +147,7 @@ impl Ime {
|
|||
ImeEvent::Enabled
|
||||
};
|
||||
|
||||
self.inner
|
||||
.event_sender
|
||||
.send((window, event))
|
||||
.expect("Failed to send enabled event");
|
||||
self.inner.event_sender.send((window, event)).expect("Failed to send enabled event");
|
||||
|
||||
Some(context)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ops::Deref;
|
||||
|
|
@ -12,11 +11,11 @@ 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};
|
||||
use std::{fmt, ptr, slice, str};
|
||||
|
||||
use calloop::generic::Generic;
|
||||
use calloop::EventLoop as Loop;
|
||||
use calloop::{ping::Ping, Readiness};
|
||||
use calloop::ping::Ping;
|
||||
use calloop::{EventLoop as Loop, Readiness};
|
||||
use libc::{setlocale, LC_CTYPE};
|
||||
use tracing::warn;
|
||||
|
||||
|
|
@ -78,10 +77,7 @@ struct WakeSender<T> {
|
|||
|
||||
impl<T> Clone for WakeSender<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
sender: self.sender.clone(),
|
||||
waker: self.waker.clone(),
|
||||
}
|
||||
Self { sender: self.sender.clone(), waker: self.waker.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +100,7 @@ impl<T> PeekableReceiver<T> {
|
|||
pub fn from_recv(recv: Receiver<T>) -> Self {
|
||||
Self { recv, first: None }
|
||||
}
|
||||
|
||||
pub fn has_incoming(&mut self) -> bool {
|
||||
if self.first.is_some() {
|
||||
return true;
|
||||
|
|
@ -113,14 +110,15 @@ impl<T> PeekableReceiver<T> {
|
|||
Ok(v) => {
|
||||
self.first = Some(v);
|
||||
true
|
||||
}
|
||||
},
|
||||
Err(TryRecvError::Empty) => false,
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
warn!("Channel was disconnected when checking incoming");
|
||||
false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
|
||||
if let Some(first) = self.first.take() {
|
||||
return Ok(first);
|
||||
|
|
@ -171,9 +169,7 @@ pub struct EventLoopProxy<T: 'static> {
|
|||
|
||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
||||
fn clone(&self) -> Self {
|
||||
EventLoopProxy {
|
||||
user_sender: self.user_sender.clone(),
|
||||
}
|
||||
EventLoopProxy { user_sender: self.user_sender.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -223,9 +219,8 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
let ime = ime.ok().map(RefCell::new);
|
||||
|
||||
let randr_event_offset = xconn
|
||||
.select_xrandr_input(root)
|
||||
.expect("Failed to query XRandR extension");
|
||||
let randr_event_offset =
|
||||
xconn.select_xrandr_input(root).expect("Failed to query XRandR extension");
|
||||
|
||||
let xi2ext = xconn
|
||||
.xcb_connection()
|
||||
|
|
@ -315,10 +310,8 @@ impl<T: 'static> EventLoop<T> {
|
|||
// Set initial device event filter.
|
||||
window_target.update_listen_device_events(true);
|
||||
|
||||
let root_window_target = RootAEL {
|
||||
p: PlatformActiveEventLoop::X(window_target),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
let root_window_target =
|
||||
RootAEL { p: PlatformActiveEventLoop::X(window_target), _marker: PhantomData };
|
||||
|
||||
let event_processor = EventProcessor {
|
||||
target: root_window_target,
|
||||
|
|
@ -372,18 +365,13 @@ impl<T: 'static> EventLoop<T> {
|
|||
activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
|
||||
user_receiver: PeekableReceiver::from_recv(user_channel),
|
||||
user_sender,
|
||||
state: EventLoopState {
|
||||
x11_readiness: Readiness::EMPTY,
|
||||
},
|
||||
state: EventLoopState { x11_readiness: Readiness::EMPTY },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||
EventLoopProxy {
|
||||
user_sender: WakeSender {
|
||||
sender: self.user_sender.clone(),
|
||||
waker: self.waker.clone(),
|
||||
},
|
||||
user_sender: WakeSender { sender: self.user_sender.clone(), waker: self.waker.clone() },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -399,13 +387,13 @@ impl<T: 'static> EventLoop<T> {
|
|||
match self.pump_events(None, &mut event_handler) {
|
||||
PumpStatus::Exit(0) => {
|
||||
break Ok(());
|
||||
}
|
||||
},
|
||||
PumpStatus::Exit(code) => {
|
||||
break Err(EventLoopError::ExitFailure(code));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -471,17 +459,15 @@ impl<T: 'static> EventLoop<T> {
|
|||
ControlFlow::Poll => Some(Duration::ZERO),
|
||||
ControlFlow::WaitUntil(wait_deadline) => {
|
||||
Some(wait_deadline.saturating_duration_since(start))
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
min_timeout(control_flow_timeout, timeout)
|
||||
};
|
||||
|
||||
self.state.x11_readiness = Readiness::EMPTY;
|
||||
if let Err(error) = self
|
||||
.event_loop
|
||||
.dispatch(timeout, &mut self.state)
|
||||
.map_err(std::io::Error::from)
|
||||
if let Err(error) =
|
||||
self.event_loop.dispatch(timeout, &mut self.state).map_err(std::io::Error::from)
|
||||
{
|
||||
tracing::error!("Failed to poll for events: {error:?}");
|
||||
let exit_code = error.raw_os_error().unwrap_or(1);
|
||||
|
|
@ -493,23 +479,14 @@ impl<T: 'static> EventLoop<T> {
|
|||
// to be considered here
|
||||
let cause = match self.control_flow() {
|
||||
ControlFlow::Poll => StartCause::Poll,
|
||||
ControlFlow::Wait => StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: None,
|
||||
},
|
||||
ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
|
||||
ControlFlow::WaitUntil(deadline) => {
|
||||
if Instant::now() < deadline {
|
||||
StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: Some(deadline),
|
||||
}
|
||||
StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
|
||||
} else {
|
||||
StartCause::ResumeTimeReached {
|
||||
start,
|
||||
requested_resume: deadline,
|
||||
}
|
||||
StartCause::ResumeTimeReached { start, requested_resume: deadline }
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// False positive / spurious wake ups could lead to us spamming
|
||||
|
|
@ -521,10 +498,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
// running a loop iteration.
|
||||
// If we don't have any pending `_receiver`
|
||||
if !self.has_pending()
|
||||
&& !matches!(
|
||||
&cause,
|
||||
StartCause::ResumeTimeReached { .. } | StartCause::Poll
|
||||
)
|
||||
&& !matches!(&cause, StartCause::ResumeTimeReached { .. } | StartCause::Poll)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -549,11 +523,9 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
// Empty activation tokens.
|
||||
while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
|
||||
let token = self
|
||||
.event_processor
|
||||
.with_window(window_id.0 as xproto::Window, |window| {
|
||||
window.generate_activation_token()
|
||||
});
|
||||
let token = self.event_processor.with_window(window_id.0 as xproto::Window, |window| {
|
||||
window.generate_activation_token()
|
||||
});
|
||||
|
||||
match token {
|
||||
Some(Ok(token)) => {
|
||||
|
|
@ -565,11 +537,11 @@ impl<T: 'static> EventLoop<T> {
|
|||
},
|
||||
};
|
||||
callback(event, &self.event_processor.target)
|
||||
}
|
||||
},
|
||||
Some(Err(e)) => {
|
||||
tracing::error!("Failed to get activation token: {}", e);
|
||||
}
|
||||
None => {}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -591,10 +563,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
for window_id in windows {
|
||||
let window_id = crate::window::WindowId(window_id);
|
||||
callback(
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::RedrawRequested,
|
||||
},
|
||||
Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested },
|
||||
&self.event_processor.target,
|
||||
);
|
||||
}
|
||||
|
|
@ -614,19 +583,18 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
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, |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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -679,9 +647,7 @@ impl ActiveEventLoop {
|
|||
}
|
||||
|
||||
pub(crate) fn create_custom_cursor(&self, cursor: CustomCursorSource) -> RootCustomCursor {
|
||||
RootCustomCursor {
|
||||
inner: PlatformCustomCursor::X(CustomCursor::new(self, cursor.inner)),
|
||||
}
|
||||
RootCustomCursor { inner: PlatformCustomCursor::X(CustomCursor::new(self, cursor.inner)) }
|
||||
}
|
||||
|
||||
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
||||
|
|
@ -761,9 +727,7 @@ impl ActiveEventLoop {
|
|||
|
||||
impl<T: 'static> EventLoopProxy<T> {
|
||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
||||
self.user_sender
|
||||
.send(event)
|
||||
.map_err(|e| EventLoopClosed(e.0))
|
||||
self.user_sender.send(event).map_err(|e| EventLoopClosed(e.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -783,11 +747,7 @@ impl<'a> DeviceInfo<'a> {
|
|||
if info.is_null() || count == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(DeviceInfo {
|
||||
xconn,
|
||||
info,
|
||||
count: count as usize,
|
||||
})
|
||||
Some(DeviceInfo { xconn, info, count: count as usize })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -802,6 +762,7 @@ impl<'a> Drop for DeviceInfo<'a> {
|
|||
|
||||
impl<'a> Deref for DeviceInfo<'a> {
|
||||
type Target = [ffi::XIDeviceInfo];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { slice::from_raw_parts(self.info, self.count) }
|
||||
}
|
||||
|
|
@ -821,6 +782,7 @@ pub(crate) struct Window(Arc<UnownedWindow>);
|
|||
|
||||
impl Deref for Window {
|
||||
type Target = UnownedWindow;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &UnownedWindow {
|
||||
&self.0
|
||||
|
|
@ -833,10 +795,7 @@ impl Window {
|
|||
attribs: WindowAttributes,
|
||||
) -> Result<Self, RootOsError> {
|
||||
let window = Arc::new(UnownedWindow::new(event_loop, attribs)?);
|
||||
event_loop
|
||||
.windows
|
||||
.borrow_mut()
|
||||
.insert(window.id(), Arc::downgrade(&window));
|
||||
event_loop.windows.borrow_mut().insert(window.id(), Arc::downgrade(&window));
|
||||
Ok(Window(window))
|
||||
}
|
||||
}
|
||||
|
|
@ -846,10 +805,7 @@ impl Drop for Window {
|
|||
let window = self.deref();
|
||||
let xconn = &window.xconn;
|
||||
|
||||
if let Ok(c) = xconn
|
||||
.xcb_connection()
|
||||
.destroy_window(window.id().0 as xproto::Window)
|
||||
{
|
||||
if let Ok(c) = xconn.xcb_connection().destroy_window(window.id().0 as xproto::Window) {
|
||||
c.ignore_error();
|
||||
}
|
||||
}
|
||||
|
|
@ -909,15 +865,11 @@ impl fmt::Display for X11Error {
|
|||
),
|
||||
X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {}", s),
|
||||
X11Error::NoSuchVisual(visualid) => {
|
||||
write!(
|
||||
f,
|
||||
"Could not find a matching X11 visual for ID `{:x}`",
|
||||
visualid
|
||||
)
|
||||
}
|
||||
write!(f, "Could not find a matching X11 visual for ID `{:x}`", visualid)
|
||||
},
|
||||
X11Error::XsettingsParse(err) => {
|
||||
write!(f, "Failed to parse xsettings: {:?}", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1053,27 +1005,21 @@ impl Device {
|
|||
let ty = unsafe { (*class_ptr)._type };
|
||||
if ty == ffi::XIScrollClass {
|
||||
let info = unsafe { &*(class_ptr as *const ffi::XIScrollClassInfo) };
|
||||
scroll_axes.push((
|
||||
info.number,
|
||||
ScrollAxis {
|
||||
increment: info.increment,
|
||||
orientation: match info.scroll_type {
|
||||
ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
|
||||
ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
position: 0.0,
|
||||
scroll_axes.push((info.number, ScrollAxis {
|
||||
increment: info.increment,
|
||||
orientation: match info.scroll_type {
|
||||
ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
|
||||
ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
));
|
||||
position: 0.0,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut device = Device {
|
||||
_name: name.into_owned(),
|
||||
scroll_axes,
|
||||
attachment: info.attachment,
|
||||
};
|
||||
let mut device =
|
||||
Device { _name: name.into_owned(), scroll_axes, attachment: info.attachment };
|
||||
device.reset_scroll_position(info);
|
||||
device
|
||||
}
|
||||
|
|
@ -1084,10 +1030,8 @@ impl Device {
|
|||
let ty = unsafe { (*class_ptr)._type };
|
||||
if ty == ffi::XIValuatorClass {
|
||||
let info = unsafe { &*(class_ptr as *const ffi::XIValuatorClassInfo) };
|
||||
if let Some(&mut (_, ref mut axis)) = self
|
||||
.scroll_axes
|
||||
.iter_mut()
|
||||
.find(|&&mut (axis, _)| axis == info.number)
|
||||
if let Some(&mut (_, ref mut axis)) =
|
||||
self.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == info.number)
|
||||
{
|
||||
axis.position = info.value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
use super::{util, X11Error, XConnection};
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
platform_impl::VideoModeHandle as PlatformVideoModeHandle,
|
||||
};
|
||||
use x11rb::{
|
||||
connection::RequestConnection,
|
||||
protocol::{
|
||||
randr::{self, ConnectionExt as _},
|
||||
xproto,
|
||||
},
|
||||
};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::platform_impl::VideoModeHandle as PlatformVideoModeHandle;
|
||||
use x11rb::connection::RequestConnection;
|
||||
use x11rb::protocol::randr::{self, ConnectionExt as _};
|
||||
use x11rb::protocol::xproto;
|
||||
|
||||
// Used for testing. This should always be committed as false.
|
||||
const DISABLE_MONITOR_LIST_CACHING: bool = false;
|
||||
|
|
@ -240,18 +234,12 @@ impl XConnection {
|
|||
// Pipeline all of the get-crtc requests.
|
||||
let mut crtc_cookies = Vec::with_capacity(resources.crtcs().len());
|
||||
for &crtc in resources.crtcs() {
|
||||
crtc_cookies.push(
|
||||
self.xcb_connection()
|
||||
.randr_get_crtc_info(crtc, x11rb::CURRENT_TIME)?,
|
||||
);
|
||||
crtc_cookies
|
||||
.push(self.xcb_connection().randr_get_crtc_info(crtc, x11rb::CURRENT_TIME)?);
|
||||
}
|
||||
|
||||
// Do this here so we do all of our requests in one shot.
|
||||
let primary = self
|
||||
.xcb_connection()
|
||||
.randr_get_output_primary(root.root)?
|
||||
.reply()?
|
||||
.output;
|
||||
let primary = self.xcb_connection().randr_get_output_primary(root.root)?.reply()?.output;
|
||||
|
||||
let mut crtc_infos = Vec::with_capacity(crtc_cookies.len());
|
||||
for cookie in crtc_cookies {
|
||||
|
|
@ -293,7 +281,7 @@ impl XConnection {
|
|||
*monitors_lock = Some(monitors.clone());
|
||||
}
|
||||
Ok(monitors)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -347,9 +335,7 @@ impl ScreenResources {
|
|||
(major_version, minor_version): (u32, u32),
|
||||
) -> Result<Self, X11Error> {
|
||||
if (major_version == 1 && minor_version >= 3) || major_version > 1 {
|
||||
let reply = conn
|
||||
.randr_get_screen_resources_current(root.root)?
|
||||
.reply()?;
|
||||
let reply = conn.randr_get_screen_resources_current(root.root)?.reply()?;
|
||||
Ok(Self::from_get_screen_resources_current_reply(reply))
|
||||
} else {
|
||||
let reply = conn.randr_get_screen_resources(root.root)?.reply()?;
|
||||
|
|
@ -358,18 +344,12 @@ impl ScreenResources {
|
|||
}
|
||||
|
||||
pub(crate) fn from_get_screen_resources_reply(reply: randr::GetScreenResourcesReply) -> Self {
|
||||
Self {
|
||||
modes: reply.modes,
|
||||
crtcs: reply.crtcs,
|
||||
}
|
||||
Self { modes: reply.modes, crtcs: reply.crtcs }
|
||||
}
|
||||
|
||||
pub(crate) fn from_get_screen_resources_current_reply(
|
||||
reply: randr::GetScreenResourcesCurrentReply,
|
||||
) -> Self {
|
||||
Self {
|
||||
modes: reply.modes,
|
||||
crtcs: reply.crtcs,
|
||||
}
|
||||
Self { modes: reply.modes, crtcs: reply.crtcs }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
use std::{
|
||||
ffi::CString,
|
||||
hash::{Hash, Hasher},
|
||||
iter, slice,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::ffi::CString;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::sync::Arc;
|
||||
use std::{iter, slice};
|
||||
|
||||
use x11rb::connection::Connection;
|
||||
|
||||
use crate::{platform_impl::PlatformCustomCursorSource, window::CursorIcon};
|
||||
use crate::platform_impl::PlatformCustomCursorSource;
|
||||
use crate::window::CursorIcon;
|
||||
|
||||
use super::super::ActiveEventLoop;
|
||||
use super::*;
|
||||
|
|
@ -21,13 +20,11 @@ impl XConnection {
|
|||
.entry(cursor)
|
||||
.or_insert_with(|| self.get_cursor(cursor));
|
||||
|
||||
self.update_cursor(window, cursor)
|
||||
.expect("Failed to set cursor");
|
||||
self.update_cursor(window, cursor).expect("Failed to set cursor");
|
||||
}
|
||||
|
||||
pub(crate) fn set_custom_cursor(&self, window: xproto::Window, cursor: &CustomCursor) {
|
||||
self.update_cursor(window, cursor.inner.cursor)
|
||||
.expect("Failed to set cursor");
|
||||
self.update_cursor(window, cursor.inner.cursor).expect("Failed to set cursor");
|
||||
}
|
||||
|
||||
fn create_empty_cursor(&self) -> ffi::Cursor {
|
||||
|
|
@ -151,12 +148,7 @@ impl CustomCursor {
|
|||
let cursor =
|
||||
(event_loop.xconn.xcursor.XcursorImageLoadCursor)(event_loop.xconn.display, ximage);
|
||||
(event_loop.xconn.xcursor.XcursorImageDestroy)(ximage);
|
||||
Self {
|
||||
inner: Arc::new(CustomCursorInner {
|
||||
xconn: event_loop.xconn.clone(),
|
||||
cursor,
|
||||
}),
|
||||
}
|
||||
Self { inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,7 @@ impl AaRect {
|
|||
pub fn new((x, y): (i32, i32), (width, height): (u32, u32)) -> Self {
|
||||
let (x, y) = (x as i64, y as i64);
|
||||
let (width, height) = (width as i64, height as i64);
|
||||
AaRect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
}
|
||||
AaRect { x, y, width, height }
|
||||
}
|
||||
|
||||
pub fn contains_point(&self, x: i64, y: i64) -> bool {
|
||||
|
|
@ -50,12 +45,7 @@ pub struct FrameExtents {
|
|||
|
||||
impl FrameExtents {
|
||||
pub fn new(left: u32, right: u32, top: u32, bottom: u32) -> Self {
|
||||
FrameExtents {
|
||||
left,
|
||||
right,
|
||||
top,
|
||||
bottom,
|
||||
}
|
||||
FrameExtents { left, right, top, bottom }
|
||||
}
|
||||
|
||||
pub fn from_border(border: u32) -> Self {
|
||||
|
|
@ -80,10 +70,7 @@ impl FrameExtentsHeuristic {
|
|||
pub fn inner_pos_to_outer(&self, x: i32, y: i32) -> (i32, i32) {
|
||||
use self::FrameExtentsHeuristicPath::*;
|
||||
if self.heuristic_path != UnsupportedBordered {
|
||||
(
|
||||
x - self.frame_extents.left as i32,
|
||||
y - self.frame_extents.top as i32,
|
||||
)
|
||||
(x - self.frame_extents.left as i32, y - self.frame_extents.top as i32)
|
||||
} else {
|
||||
(x, y)
|
||||
}
|
||||
|
|
@ -92,14 +79,10 @@ impl FrameExtentsHeuristic {
|
|||
pub fn inner_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) {
|
||||
(
|
||||
width.saturating_add(
|
||||
self.frame_extents
|
||||
.left
|
||||
.saturating_add(self.frame_extents.right) as _,
|
||||
self.frame_extents.left.saturating_add(self.frame_extents.right) as _
|
||||
),
|
||||
height.saturating_add(
|
||||
self.frame_extents
|
||||
.top
|
||||
.saturating_add(self.frame_extents.bottom) as _,
|
||||
self.frame_extents.top.saturating_add(self.frame_extents.bottom) as _
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -112,10 +95,7 @@ impl XConnection {
|
|||
window: xproto::Window,
|
||||
root: xproto::Window,
|
||||
) -> Result<xproto::TranslateCoordinatesReply, X11Error> {
|
||||
self.xcb_connection()
|
||||
.translate_coordinates(window, root, 0, 0)?
|
||||
.reply()
|
||||
.map_err(Into::into)
|
||||
self.xcb_connection().translate_coordinates(window, root, 0, 0)?.reply().map_err(Into::into)
|
||||
}
|
||||
|
||||
// This is adequate for inner_size
|
||||
|
|
@ -123,10 +103,7 @@ impl XConnection {
|
|||
&self,
|
||||
window: xproto::Window,
|
||||
) -> Result<xproto::GetGeometryReply, X11Error> {
|
||||
self.xcb_connection()
|
||||
.get_geometry(window)?
|
||||
.reply()
|
||||
.map_err(Into::into)
|
||||
self.xcb_connection().get_geometry(window)?.reply().map_err(Into::into)
|
||||
}
|
||||
|
||||
fn get_frame_extents(&self, window: xproto::Window) -> Option<FrameExtents> {
|
||||
|
|
@ -141,11 +118,7 @@ impl XConnection {
|
|||
// support this. As this is part of EWMH (Extended Window Manager Hints), it's likely to
|
||||
// be unsupported by many smaller WMs.
|
||||
let extents: Option<Vec<u32>> = self
|
||||
.get_property(
|
||||
window,
|
||||
extents_atom,
|
||||
xproto::Atom::from(xproto::AtomEnum::CARDINAL),
|
||||
)
|
||||
.get_property(window, extents_atom, xproto::Atom::from(xproto::AtomEnum::CARDINAL))
|
||||
.ok();
|
||||
|
||||
extents.and_then(|extents| {
|
||||
|
|
@ -171,11 +144,7 @@ impl XConnection {
|
|||
}
|
||||
|
||||
let client_list: Option<Vec<xproto::Window>> = self
|
||||
.get_property(
|
||||
root,
|
||||
client_list_atom,
|
||||
xproto::Atom::from(xproto::AtomEnum::WINDOW),
|
||||
)
|
||||
.get_property(root, client_list_atom, xproto::Atom::from(xproto::AtomEnum::WINDOW))
|
||||
.ok();
|
||||
|
||||
client_list.map(|client_list| client_list.contains(&(window as xproto::Window)))
|
||||
|
|
@ -221,14 +190,9 @@ impl XConnection {
|
|||
};
|
||||
|
||||
let (width, height, border) = {
|
||||
let inner_geometry = self
|
||||
.get_geometry(window)
|
||||
.expect("Failed to get inner window geometry");
|
||||
(
|
||||
inner_geometry.width,
|
||||
inner_geometry.height,
|
||||
inner_geometry.border_width,
|
||||
)
|
||||
let inner_geometry =
|
||||
self.get_geometry(window).expect("Failed to get inner window geometry");
|
||||
(inner_geometry.width, inner_geometry.height, inner_geometry.border_width)
|
||||
};
|
||||
|
||||
// The first condition is only false for un-nested windows, but isn't always false for
|
||||
|
|
@ -253,39 +217,29 @@ impl XConnection {
|
|||
// known discrepancies:
|
||||
// * Mutter/Muffin/Budgie gives decorated windows a margin of 9px (only 7px on top) in
|
||||
// addition to a 1px semi-transparent border. The margin can be easily observed by
|
||||
// using a screenshot tool to get a screenshot of a selected window, and is
|
||||
// presumably used for drawing drop shadows. Getting window geometry information
|
||||
// via hierarchy-climbing results in this margin being included in both the
|
||||
// position and outer size, so a window positioned at (0, 0) would be reported as
|
||||
// having a position (-10, -8).
|
||||
// * Compiz has a drop shadow margin just like Mutter/Muffin/Budgie, though it's 10px
|
||||
// on all sides, and there's no additional border.
|
||||
// * Enlightenment otherwise gets a y position equivalent to inner_y_rel_root.
|
||||
// Without decorations, there's no difference. This is presumably related to
|
||||
// Enlightenment's fairly unique concept of window position; it interprets
|
||||
// positions given to XMoveWindow as a client area position rather than a position
|
||||
// of the overall window.
|
||||
// using a screenshot tool to get a screenshot of a selected window, and is presumably
|
||||
// used for drawing drop shadows. Getting window geometry information via
|
||||
// hierarchy-climbing results in this margin being included in both the position and
|
||||
// outer size, so a window positioned at (0, 0) would be reported as having a position
|
||||
// (-10, -8).
|
||||
// * Compiz has a drop shadow margin just like Mutter/Muffin/Budgie, though it's 10px on
|
||||
// all sides, and there's no additional border.
|
||||
// * Enlightenment otherwise gets a y position equivalent to inner_y_rel_root. Without
|
||||
// decorations, there's no difference. This is presumably related to Enlightenment's
|
||||
// fairly unique concept of window position; it interprets positions given to
|
||||
// XMoveWindow as a client area position rather than a position of the overall window.
|
||||
|
||||
FrameExtentsHeuristic {
|
||||
frame_extents,
|
||||
heuristic_path: Supported,
|
||||
}
|
||||
FrameExtentsHeuristic { frame_extents, heuristic_path: Supported }
|
||||
} else if nested {
|
||||
// If the position value we have is for a nested window used as the client area, we'll
|
||||
// just climb up the hierarchy and get the geometry of the outermost window we're
|
||||
// nested in.
|
||||
let outer_window = self
|
||||
.climb_hierarchy(window, root)
|
||||
.expect("Failed to climb window hierarchy");
|
||||
let outer_window =
|
||||
self.climb_hierarchy(window, root).expect("Failed to climb window hierarchy");
|
||||
let (outer_y, outer_width, outer_height) = {
|
||||
let outer_geometry = self
|
||||
.get_geometry(outer_window)
|
||||
.expect("Failed to get outer window geometry");
|
||||
(
|
||||
outer_geometry.y,
|
||||
outer_geometry.width,
|
||||
outer_geometry.height,
|
||||
)
|
||||
let outer_geometry =
|
||||
self.get_geometry(outer_window).expect("Failed to get outer window geometry");
|
||||
(outer_geometry.y, outer_geometry.width, outer_geometry.height)
|
||||
};
|
||||
|
||||
// Since we have the geometry of the outermost window and the geometry of the client
|
||||
|
|
@ -300,18 +254,12 @@ impl XConnection {
|
|||
let bottom = diff_y.saturating_sub(offset_y);
|
||||
|
||||
let frame_extents = FrameExtents::new(left, right, top, bottom);
|
||||
FrameExtentsHeuristic {
|
||||
frame_extents,
|
||||
heuristic_path: UnsupportedNested,
|
||||
}
|
||||
FrameExtentsHeuristic { frame_extents, heuristic_path: UnsupportedNested }
|
||||
} else {
|
||||
// This is the case for xmonad and dwm, AKA the only WMs tested that supplied a
|
||||
// border value. This is convenient, since we can use it to get an accurate frame.
|
||||
let frame_extents = FrameExtents::from_border(border.into());
|
||||
FrameExtentsHeuristic {
|
||||
frame_extents,
|
||||
heuristic_path: UnsupportedBordered,
|
||||
}
|
||||
FrameExtentsHeuristic { frame_extents, heuristic_path: UnsupportedBordered }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,13 +76,7 @@ mod mwm {
|
|||
impl MotifHints {
|
||||
pub fn new() -> MotifHints {
|
||||
MotifHints {
|
||||
hints: MwmHints {
|
||||
flags: 0,
|
||||
functions: 0,
|
||||
decorations: 0,
|
||||
input_mode: 0,
|
||||
status: 0,
|
||||
},
|
||||
hints: MwmHints { flags: 0, functions: 0, decorations: 0, input_mode: 0, status: 0 },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
use std::{slice, str};
|
||||
use x11rb::protocol::{
|
||||
xinput::{self, ConnectionExt as _},
|
||||
xkb,
|
||||
};
|
||||
use x11rb::protocol::xinput::{self, ConnectionExt as _};
|
||||
use x11rb::protocol::xkb;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -22,13 +20,10 @@ impl XConnection {
|
|||
mask: xinput::XIEventMask,
|
||||
) -> Result<VoidCookie<'_>, X11Error> {
|
||||
self.xcb_connection()
|
||||
.xinput_xi_select_events(
|
||||
window,
|
||||
&[xinput::EventMask {
|
||||
deviceid: device_id,
|
||||
mask: vec![mask],
|
||||
}],
|
||||
)
|
||||
.xinput_xi_select_events(window, &[xinput::EventMask {
|
||||
deviceid: device_id,
|
||||
mask: vec![mask],
|
||||
}])
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use std::{iter::Enumerate, slice::Iter};
|
||||
use std::iter::Enumerate;
|
||||
use std::slice::Iter;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -14,17 +15,13 @@ pub struct KeymapIter<'a> {
|
|||
|
||||
impl Keymap {
|
||||
pub fn iter(&self) -> KeymapIter<'_> {
|
||||
KeymapIter {
|
||||
iter: self.keys.iter().enumerate(),
|
||||
index: 0,
|
||||
item: None,
|
||||
}
|
||||
KeymapIter { iter: self.keys.iter().enumerate(), index: 0, item: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Keymap {
|
||||
type Item = ffi::KeyCode;
|
||||
type IntoIter = KeymapIter<'a>;
|
||||
type Item = ffi::KeyCode;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
// Welcome to the util module, where we try to keep you from shooting yourself in the foot.
|
||||
// *results may vary
|
||||
|
||||
use std::{
|
||||
mem::{self, MaybeUninit},
|
||||
ops::BitAnd,
|
||||
os::raw::*,
|
||||
};
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::ops::BitAnd;
|
||||
use std::os::raw::*;
|
||||
|
||||
mod client_msg;
|
||||
pub mod cookie;
|
||||
|
|
@ -22,12 +20,17 @@ mod window_property;
|
|||
mod wm;
|
||||
mod xmodmap;
|
||||
|
||||
pub use self::{
|
||||
cursor::*, geometry::*, hint::*, input::*, mouse::*, window_property::*, wm::*,
|
||||
xmodmap::ModifierKeymap,
|
||||
};
|
||||
pub use self::cursor::*;
|
||||
pub use self::geometry::*;
|
||||
pub use self::hint::*;
|
||||
pub use self::input::*;
|
||||
pub use self::mouse::*;
|
||||
pub use self::window_property::*;
|
||||
pub use self::wm::*;
|
||||
pub use self::xmodmap::ModifierKeymap;
|
||||
|
||||
use super::{atoms::*, ffi, VoidCookie, X11Error, XConnection, XError};
|
||||
use super::atoms::*;
|
||||
use super::{ffi, VoidCookie, X11Error, XConnection, XError};
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt as _};
|
||||
|
||||
pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool {
|
||||
|
|
@ -54,12 +57,13 @@ impl XConnection {
|
|||
// 1. `XPending`, `XNextEvent`, and `XWindowEvent` flush "as needed"
|
||||
// 2. `XFlush` explicitly flushes
|
||||
// 3. `XSync` flushes and blocks until all requests are responded to
|
||||
// 4. Calls that have a return dependent on a response (i.e. `XGetWindowProperty`) sync internally.
|
||||
// When in doubt, check the X11 source; if a function calls `_XReply`, it flushes and waits.
|
||||
// 4. Calls that have a return dependent on a response (i.e. `XGetWindowProperty`) sync
|
||||
// internally. When in doubt, check the X11 source; if a function calls `_XReply`, it flushes
|
||||
// and waits.
|
||||
// All util functions that abstract an async function will return a `Flusher`.
|
||||
pub fn flush_requests(&self) -> Result<(), XError> {
|
||||
unsafe { (self.xlib.XFlush)(self.display) };
|
||||
//println!("XFlush");
|
||||
// println!("XFlush");
|
||||
// This isn't necessarily a useful time to check for errors (since our request hasn't
|
||||
// necessarily been processed yet)
|
||||
self.check_errors()
|
||||
|
|
@ -67,7 +71,7 @@ impl XConnection {
|
|||
|
||||
pub fn sync_with_server(&self) -> Result<(), XError> {
|
||||
unsafe { (self.xlib.XSync)(self.display, ffi::False) };
|
||||
//println!("XSync");
|
||||
// println!("XSync");
|
||||
self.check_errors()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ pub struct Delta<T> {
|
|||
|
||||
impl<T: Default> Default for Delta<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
x: Default::default(),
|
||||
y: Default::default(),
|
||||
}
|
||||
Self { x: Default::default(), y: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use std::{env, str, str::FromStr};
|
||||
use std::str::FromStr;
|
||||
use std::{env, str};
|
||||
|
||||
use super::*;
|
||||
use crate::platform_impl::platform::x11::monitor;
|
||||
use crate::{dpi::validate_scale_factor, platform_impl::platform::x11::VideoModeHandle};
|
||||
use crate::dpi::validate_scale_factor;
|
||||
use crate::platform_impl::platform::x11::{monitor, VideoModeHandle};
|
||||
|
||||
use tracing::warn;
|
||||
use x11rb::protocol::randr::{self, ConnectionExt as _};
|
||||
|
|
@ -42,16 +43,14 @@ impl XConnection {
|
|||
if let Some(xsettings_screen) = self.xsettings_screen() {
|
||||
match self.xsettings_dpi(xsettings_screen) {
|
||||
Ok(Some(dpi)) => return Some(dpi),
|
||||
Ok(None) => {}
|
||||
Ok(None) => {},
|
||||
Err(err) => {
|
||||
tracing::warn!("failed to fetch XSettings: {err}");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
self.database()
|
||||
.get_string("Xft.dpi", "")
|
||||
.and_then(|s| f64::from_str(s).ok())
|
||||
self.database().get_string("Xft.dpi", "").and_then(|s| f64::from_str(s).ok())
|
||||
}
|
||||
|
||||
pub fn get_output_info(
|
||||
|
|
@ -69,7 +68,7 @@ impl XConnection {
|
|||
Err(err) => {
|
||||
warn!("Failed to get output info: {:?}", err);
|
||||
return None;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let bit_depth = self.default_root().root_depth;
|
||||
|
|
@ -100,14 +99,15 @@ impl XConnection {
|
|||
Err(err) => {
|
||||
warn!("Failed to get output name: {:?}", err);
|
||||
return None;
|
||||
}
|
||||
},
|
||||
};
|
||||
// Override DPI if `WINIT_X11_SCALE_FACTOR` variable is set
|
||||
let deprecated_dpi_override = env::var("WINIT_HIDPI_FACTOR").ok();
|
||||
if deprecated_dpi_override.is_some() {
|
||||
warn!(
|
||||
"The WINIT_HIDPI_FACTOR environment variable is deprecated; use WINIT_X11_SCALE_FACTOR"
|
||||
)
|
||||
"The WINIT_HIDPI_FACTOR environment variable is deprecated; use \
|
||||
WINIT_X11_SCALE_FACTOR"
|
||||
)
|
||||
}
|
||||
let dpi_env = env::var("WINIT_X11_SCALE_FACTOR").ok().map_or_else(
|
||||
|| EnvVarDPI::NotSet,
|
||||
|
|
@ -120,7 +120,8 @@ impl XConnection {
|
|||
EnvVarDPI::NotSet
|
||||
} else {
|
||||
panic!(
|
||||
"`WINIT_X11_SCALE_FACTOR` invalid; DPI factors must be either normal floats greater than 0, or `randr`. Got `{var}`"
|
||||
"`WINIT_X11_SCALE_FACTOR` invalid; DPI factors must be either normal \
|
||||
floats greater than 0, or `randr`. Got `{var}`"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
@ -134,11 +135,12 @@ impl XConnection {
|
|||
EnvVarDPI::Scale(dpi_override) => {
|
||||
if !validate_scale_factor(dpi_override) {
|
||||
panic!(
|
||||
"`WINIT_X11_SCALE_FACTOR` invalid; DPI factors must be either normal floats greater than 0, or `randr`. Got `{dpi_override}`",
|
||||
"`WINIT_X11_SCALE_FACTOR` invalid; DPI factors must be either normal \
|
||||
floats greater than 0, or `randr`. Got `{dpi_override}`",
|
||||
);
|
||||
}
|
||||
dpi_override
|
||||
}
|
||||
},
|
||||
EnvVarDPI::NotSet => {
|
||||
if let Some(dpi) = self.get_xft_dpi() {
|
||||
dpi / 96.
|
||||
|
|
@ -148,7 +150,7 @@ impl XConnection {
|
|||
(output_info.mm_width as _, output_info.mm_height as _),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Some((name, scale_factor, modes))
|
||||
|
|
@ -159,10 +161,8 @@ impl XConnection {
|
|||
crtc_id: randr::Crtc,
|
||||
mode_id: randr::Mode,
|
||||
) -> Result<(), X11Error> {
|
||||
let crtc = self
|
||||
.xcb_connection()
|
||||
.randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?
|
||||
.reply()?;
|
||||
let crtc =
|
||||
self.xcb_connection().randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?.reply()?;
|
||||
|
||||
self.xcb_connection()
|
||||
.randr_set_crtc_config(
|
||||
|
|
@ -181,10 +181,6 @@ impl XConnection {
|
|||
}
|
||||
|
||||
pub fn get_crtc_mode(&self, crtc_id: randr::Crtc) -> Result<randr::Mode, X11Error> {
|
||||
Ok(self
|
||||
.xcb_connection()
|
||||
.randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?
|
||||
.reply()?
|
||||
.mode)
|
||||
Ok(self.xcb_connection().randr_get_crtc_info(crtc_id, x11rb::CURRENT_TIME)?.reply()?.mode)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,10 +87,7 @@ impl XConnection {
|
|||
property,
|
||||
property_type,
|
||||
(mem::size_of::<T>() * 8) as u8,
|
||||
new_value
|
||||
.len()
|
||||
.try_into()
|
||||
.expect("too many items for property"),
|
||||
new_value.len().try_into().expect("too many items for property"),
|
||||
bytemuck::cast_slice::<T, u8>(new_value),
|
||||
)
|
||||
.map_err(Into::into)
|
||||
|
|
|
|||
|
|
@ -38,12 +38,8 @@ impl XConnection {
|
|||
fn get_supported_hints(&self, root: xproto::Window) -> Vec<xproto::Atom> {
|
||||
let atoms = self.atoms();
|
||||
let supported_atom = atoms[_NET_SUPPORTED];
|
||||
self.get_property(
|
||||
root,
|
||||
supported_atom,
|
||||
xproto::Atom::from(xproto::AtomEnum::ATOM),
|
||||
)
|
||||
.unwrap_or_else(|_| Vec::with_capacity(0))
|
||||
self.get_property(root, supported_atom, xproto::Atom::from(xproto::AtomEnum::ATOM))
|
||||
.unwrap_or_else(|_| Vec::with_capacity(0))
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_conversion)]
|
||||
|
|
@ -57,22 +53,22 @@ impl XConnection {
|
|||
// inavailability of time machines, we'll just try to get _NET_SUPPORTING_WM_CHECK
|
||||
// regardless of whether or not the WM claims to support it.
|
||||
//
|
||||
// Blackbox 0.70 also incorrectly reports not supporting this, though that appears to be fixed
|
||||
// in 0.72.
|
||||
/*if !supported_hints.contains(&check_atom) {
|
||||
return None;
|
||||
}*/
|
||||
// Blackbox 0.70 also incorrectly reports not supporting this, though that appears to be
|
||||
// fixed in 0.72.
|
||||
// if !supported_hints.contains(&check_atom) {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// IceWM (1.3.x and earlier) doesn't report supporting _NET_WM_NAME, but will nonetheless
|
||||
// provide us with a value for it. Note that the unofficial 1.4 fork of IceWM works fine.
|
||||
/*if !supported_hints.contains(&wm_name_atom) {
|
||||
return None;
|
||||
}*/
|
||||
// if !supported_hints.contains(&wm_name_atom) {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// Of the WMs tested, only xmonad and dwm fail to provide a WM name.
|
||||
|
||||
// Querying this property on the root window will give us the ID of a child window created by
|
||||
// the WM.
|
||||
// Querying this property on the root window will give us the ID of a child window created
|
||||
// by the WM.
|
||||
let root_window_wm_check = {
|
||||
let result = self.get_property::<xproto::Window>(
|
||||
root,
|
||||
|
|
|
|||
|
|
@ -1,50 +1,40 @@
|
|||
use std::{
|
||||
cmp, env,
|
||||
ffi::CString,
|
||||
mem::replace,
|
||||
os::raw::*,
|
||||
path::Path,
|
||||
sync::{Arc, Mutex, MutexGuard},
|
||||
};
|
||||
use std::ffi::CString;
|
||||
use std::mem::replace;
|
||||
use std::os::raw::*;
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use std::{cmp, env};
|
||||
|
||||
use tracing::{debug, info, warn};
|
||||
use x11rb::{
|
||||
connection::Connection,
|
||||
properties::{WmHints, WmSizeHints, WmSizeHintsSpecification},
|
||||
protocol::{
|
||||
randr,
|
||||
shape::SK,
|
||||
xfixes::{ConnectionExt, RegionWrapper},
|
||||
xinput,
|
||||
xproto::{self, ConnectionExt as _, Rectangle},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
cursor::{Cursor, CustomCursor as RootCustomCursor},
|
||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
event::{Event, InnerSizeWriter, WindowEvent},
|
||||
event_loop::AsyncRequestSerial,
|
||||
platform::x11::WindowType,
|
||||
platform_impl::{
|
||||
x11::{
|
||||
atoms::*, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender,
|
||||
X11Error,
|
||||
},
|
||||
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor,
|
||||
PlatformIcon, VideoModeHandle as PlatformVideoModeHandle,
|
||||
},
|
||||
window::{
|
||||
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
|
||||
WindowButtons, WindowLevel,
|
||||
},
|
||||
use x11rb::connection::Connection;
|
||||
use x11rb::properties::{WmHints, WmSizeHints, WmSizeHintsSpecification};
|
||||
use x11rb::protocol::shape::SK;
|
||||
use x11rb::protocol::xfixes::{ConnectionExt, RegionWrapper};
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt as _, Rectangle};
|
||||
use x11rb::protocol::{randr, xinput};
|
||||
|
||||
use crate::cursor::{Cursor, CustomCursor as RootCustomCursor};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
||||
use crate::event::{Event, InnerSizeWriter, WindowEvent};
|
||||
use crate::event_loop::AsyncRequestSerial;
|
||||
use crate::platform::x11::WindowType;
|
||||
use crate::platform_impl::x11::atoms::*;
|
||||
use crate::platform_impl::x11::{
|
||||
xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error,
|
||||
};
|
||||
use crate::platform_impl::{
|
||||
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor,
|
||||
PlatformIcon, VideoModeHandle as PlatformVideoModeHandle,
|
||||
};
|
||||
use crate::window::{
|
||||
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
|
||||
WindowButtons, WindowLevel,
|
||||
};
|
||||
|
||||
use super::util::{self, SelectedCursor};
|
||||
use super::{
|
||||
ffi,
|
||||
util::{self, SelectedCursor},
|
||||
ActiveEventLoop, CookieResultExt, ImeRequest, ImeSender, VoidCookie, WindowId, XConnection,
|
||||
ffi, ActiveEventLoop, CookieResultExt, ImeRequest, ImeSender, VoidCookie, WindowId, XConnection,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -86,11 +76,8 @@ pub enum Visibility {
|
|||
|
||||
impl SharedState {
|
||||
fn new(last_monitor: X11MonitorHandle, window_attributes: &WindowAttributes) -> Mutex<Self> {
|
||||
let visibility = if window_attributes.visible {
|
||||
Visibility::YesWait
|
||||
} else {
|
||||
Visibility::No
|
||||
};
|
||||
let visibility =
|
||||
if window_attributes.visible { Visibility::YesWait } else { Visibility::No };
|
||||
|
||||
Mutex::new(SharedState {
|
||||
last_monitor,
|
||||
|
|
@ -191,16 +178,13 @@ impl UnownedWindow {
|
|||
|
||||
info!("Guessed window scale factor: {}", scale_factor);
|
||||
|
||||
let max_inner_size: Option<(u32, u32)> = window_attrs
|
||||
.max_inner_size
|
||||
.map(|size| size.to_physical::<u32>(scale_factor).into());
|
||||
let min_inner_size: Option<(u32, u32)> = window_attrs
|
||||
.min_inner_size
|
||||
.map(|size| size.to_physical::<u32>(scale_factor).into());
|
||||
let max_inner_size: Option<(u32, u32)> =
|
||||
window_attrs.max_inner_size.map(|size| size.to_physical::<u32>(scale_factor).into());
|
||||
let min_inner_size: Option<(u32, u32)> =
|
||||
window_attrs.min_inner_size.map(|size| size.to_physical::<u32>(scale_factor).into());
|
||||
|
||||
let position = window_attrs
|
||||
.position
|
||||
.map(|position| position.to_physical::<i32>(scale_factor));
|
||||
let position =
|
||||
window_attrs.position.map(|position| position.to_physical::<i32>(scale_factor));
|
||||
|
||||
let dimensions = {
|
||||
// x11 only applies constraints when the window is actively resized
|
||||
|
|
@ -219,10 +203,7 @@ impl UnownedWindow {
|
|||
dimensions.0 = cmp::max(dimensions.0, min.0);
|
||||
dimensions.1 = cmp::max(dimensions.1, min.1);
|
||||
}
|
||||
debug!(
|
||||
"Calculated physical dimensions: {}x{}",
|
||||
dimensions.0, dimensions.1
|
||||
);
|
||||
debug!("Calculated physical dimensions: {}x{}", dimensions.0, dimensions.1);
|
||||
dimensions
|
||||
};
|
||||
|
||||
|
|
@ -238,41 +219,37 @@ impl UnownedWindow {
|
|||
.roots
|
||||
.iter()
|
||||
.flat_map(|root| &root.allowed_depths)
|
||||
.flat_map(|depth| {
|
||||
depth
|
||||
.visuals
|
||||
.iter()
|
||||
.map(move |visual| (visual, depth.depth))
|
||||
});
|
||||
.flat_map(|depth| depth.visuals.iter().map(move |visual| (visual, depth.depth)));
|
||||
|
||||
// creating
|
||||
let (visualtype, depth, require_colormap) = match window_attrs
|
||||
.platform_specific
|
||||
.x11
|
||||
.visual_id
|
||||
{
|
||||
Some(vi) => {
|
||||
// Find this specific visual.
|
||||
let (visualtype, depth) = all_visuals
|
||||
.find(|(visual, _)| visual.visual_id == vi)
|
||||
.ok_or_else(|| os_error!(OsError::XError(X11Error::NoSuchVisual(vi).into())))?;
|
||||
let (visualtype, depth, require_colormap) =
|
||||
match window_attrs.platform_specific.x11.visual_id {
|
||||
Some(vi) => {
|
||||
// Find this specific visual.
|
||||
let (visualtype, depth) =
|
||||
all_visuals.find(|(visual, _)| visual.visual_id == vi).ok_or_else(
|
||||
|| os_error!(OsError::XError(X11Error::NoSuchVisual(vi).into())),
|
||||
)?;
|
||||
|
||||
(Some(visualtype), depth, true)
|
||||
}
|
||||
None if window_attrs.transparent => {
|
||||
// Find a suitable visual, true color with 32 bits of depth.
|
||||
all_visuals
|
||||
.find_map(|(visual, depth)| {
|
||||
(depth == 32 && visual.class == xproto::VisualClass::TRUE_COLOR)
|
||||
.then_some((Some(visual), depth, true))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
debug!("Could not set transparency, because XMatchVisualInfo returned zero for the required parameters");
|
||||
(None as _, x11rb::COPY_FROM_PARENT as _, false)
|
||||
})
|
||||
}
|
||||
_ => (None, x11rb::COPY_FROM_PARENT as _, false),
|
||||
};
|
||||
(Some(visualtype), depth, true)
|
||||
},
|
||||
None if window_attrs.transparent => {
|
||||
// Find a suitable visual, true color with 32 bits of depth.
|
||||
all_visuals
|
||||
.find_map(|(visual, depth)| {
|
||||
(depth == 32 && visual.class == xproto::VisualClass::TRUE_COLOR)
|
||||
.then_some((Some(visual), depth, true))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
debug!(
|
||||
"Could not set transparency, because XMatchVisualInfo returned \
|
||||
zero for the required parameters"
|
||||
);
|
||||
(None as _, x11rb::COPY_FROM_PARENT as _, false)
|
||||
})
|
||||
},
|
||||
_ => (None, x11rb::COPY_FROM_PARENT as _, false),
|
||||
};
|
||||
let mut visual = visualtype.map_or(x11rb::COPY_FROM_PARENT, |v| v.visual_id);
|
||||
|
||||
let window_attributes = {
|
||||
|
|
@ -320,11 +297,7 @@ impl UnownedWindow {
|
|||
};
|
||||
|
||||
// Figure out the window's parent.
|
||||
let parent = window_attrs
|
||||
.platform_specific
|
||||
.x11
|
||||
.embed_window
|
||||
.unwrap_or(root);
|
||||
let parent = window_attrs.platform_specific.x11.embed_window.unwrap_or(root);
|
||||
|
||||
// finally creating the window
|
||||
let xwindow = {
|
||||
|
|
@ -419,9 +392,7 @@ impl UnownedWindow {
|
|||
.map(|bin_name| bin_name.to_owned())
|
||||
.unwrap_or_else(|| window_attrs.title.clone());
|
||||
// This environment variable is extraordinarily unlikely to actually be used...
|
||||
let instance = env::var("RESOURCE_NAME")
|
||||
.ok()
|
||||
.unwrap_or_else(|| class.clone());
|
||||
let instance = env::var("RESOURCE_NAME").ok().unwrap_or_else(|| class.clone());
|
||||
(instance, class)
|
||||
};
|
||||
|
||||
|
|
@ -444,12 +415,10 @@ impl UnownedWindow {
|
|||
.ignore_error();
|
||||
|
||||
// Set size hints.
|
||||
let mut min_inner_size = window_attrs
|
||||
.min_inner_size
|
||||
.map(|size| size.to_physical::<u32>(scale_factor));
|
||||
let mut max_inner_size = window_attrs
|
||||
.max_inner_size
|
||||
.map(|size| size.to_physical::<u32>(scale_factor));
|
||||
let mut min_inner_size =
|
||||
window_attrs.min_inner_size.map(|size| size.to_physical::<u32>(scale_factor));
|
||||
let mut max_inner_size =
|
||||
window_attrs.max_inner_size.map(|size| size.to_physical::<u32>(scale_factor));
|
||||
|
||||
if !window_attrs.resizable {
|
||||
if util::wm_name_is_one_of(&["Xfwm4"]) {
|
||||
|
|
@ -534,9 +503,7 @@ impl UnownedWindow {
|
|||
&mut supported_ptr,
|
||||
);
|
||||
if supported_ptr == ffi::False {
|
||||
return Err(os_error!(OsError::Misc(
|
||||
"`XkbSetDetectableAutoRepeat` failed"
|
||||
)));
|
||||
return Err(os_error!(OsError::Misc("`XkbSetDetectableAutoRepeat` failed")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -556,9 +523,7 @@ impl UnownedWindow {
|
|||
|
||||
// Try to create input context for the window.
|
||||
if let Some(ime) = event_loop.ime.as_ref() {
|
||||
let result = ime
|
||||
.borrow_mut()
|
||||
.create_context(window.xwindow as ffi::Window, false);
|
||||
let result = ime.borrow_mut().create_context(window.xwindow as ffi::Window, false);
|
||||
leap!(result);
|
||||
}
|
||||
|
||||
|
|
@ -647,10 +612,7 @@ impl UnownedWindow {
|
|||
fn set_window_types(&self, window_types: Vec<WindowType>) -> Result<VoidCookie<'_>, X11Error> {
|
||||
let atoms = self.xconn.atoms();
|
||||
let hint_atom = atoms[_NET_WM_WINDOW_TYPE];
|
||||
let atoms: Vec<_> = window_types
|
||||
.iter()
|
||||
.map(|t| t.as_atom(&self.xconn))
|
||||
.collect();
|
||||
let atoms: Vec<_> = window_types.iter().map(|t| t.as_atom(&self.xconn)).collect();
|
||||
|
||||
self.xconn.change_property(
|
||||
self.xwindow,
|
||||
|
|
@ -682,13 +644,9 @@ impl UnownedWindow {
|
|||
|
||||
#[inline]
|
||||
pub fn set_theme(&self, theme: Option<Theme>) {
|
||||
self.set_theme_inner(theme)
|
||||
.expect("Failed to change window theme")
|
||||
.ignore_error();
|
||||
self.set_theme_inner(theme).expect("Failed to change window theme").ignore_error();
|
||||
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to change window theme");
|
||||
self.xconn.flush_requests().expect("Failed to change window theme");
|
||||
}
|
||||
|
||||
fn set_netwm(
|
||||
|
|
@ -703,13 +661,7 @@ impl UnownedWindow {
|
|||
self.root,
|
||||
state_atom,
|
||||
Some(xproto::EventMask::SUBSTRUCTURE_REDIRECT | xproto::EventMask::SUBSTRUCTURE_NOTIFY),
|
||||
[
|
||||
operation as u32,
|
||||
properties.0,
|
||||
properties.1,
|
||||
properties.2,
|
||||
properties.3,
|
||||
],
|
||||
[operation as u32, properties.0, properties.1, properties.2, properties.3],
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -723,11 +675,7 @@ impl UnownedWindow {
|
|||
// locking up the user's display.
|
||||
self.xconn
|
||||
.xcb_connection()
|
||||
.set_input_focus(
|
||||
xproto::InputFocus::PARENT,
|
||||
self.xwindow,
|
||||
x11rb::CURRENT_TIME,
|
||||
)?
|
||||
.set_input_focus(xproto::InputFocus::PARENT, self.xwindow, x11rb::CURRENT_TIME)?
|
||||
.ignore_error();
|
||||
}
|
||||
|
||||
|
|
@ -745,7 +693,7 @@ impl UnownedWindow {
|
|||
Visibility::No | Visibility::YesWait => {
|
||||
shared_state_lock.desired_fullscreen = Some(fullscreen);
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
Visibility::Yes => (),
|
||||
}
|
||||
|
||||
|
|
@ -768,11 +716,9 @@ impl UnownedWindow {
|
|||
let monitor = video_mode.monitor.as_ref().unwrap();
|
||||
shared_state_lock.desktop_video_mode = Some((
|
||||
monitor.id,
|
||||
self.xconn
|
||||
.get_crtc_mode(monitor.id)
|
||||
.expect("Failed to get desktop video mode"),
|
||||
self.xconn.get_crtc_mode(monitor.id).expect("Failed to get desktop video mode"),
|
||||
));
|
||||
}
|
||||
},
|
||||
// Restore desktop video mode upon exiting exclusive fullscreen
|
||||
(&Some(Fullscreen::Exclusive(_)), &None)
|
||||
| (&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Borderless(_))) => {
|
||||
|
|
@ -780,7 +726,7 @@ impl UnownedWindow {
|
|||
self.xconn
|
||||
.set_crtc_config(monitor_id, mode_id)
|
||||
.expect("failed to restore desktop video mode");
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
|
@ -796,18 +742,18 @@ impl UnownedWindow {
|
|||
.expect_then_ignore_error("Failed to restore window position");
|
||||
}
|
||||
flusher.map(Some)
|
||||
}
|
||||
},
|
||||
Some(fullscreen) => {
|
||||
let (video_mode, monitor) = match fullscreen {
|
||||
Fullscreen::Exclusive(PlatformVideoModeHandle::X(ref video_mode)) => {
|
||||
(Some(video_mode), video_mode.monitor.clone().unwrap())
|
||||
}
|
||||
},
|
||||
Fullscreen::Borderless(Some(PlatformMonitorHandle::X(monitor))) => {
|
||||
(None, monitor)
|
||||
}
|
||||
},
|
||||
Fullscreen::Borderless(None) => {
|
||||
(None, self.shared_state_lock().last_monitor.clone())
|
||||
}
|
||||
},
|
||||
#[cfg(wayland_platform)]
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
|
@ -854,7 +800,7 @@ impl UnownedWindow {
|
|||
self.set_position_inner(monitor_origin.0, monitor_origin.1)
|
||||
.expect_then_ignore_error("Failed to set window position");
|
||||
self.set_fullscreen_hint(true).map(Some)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -862,21 +808,15 @@ impl UnownedWindow {
|
|||
pub(crate) fn fullscreen(&self) -> Option<Fullscreen> {
|
||||
let shared_state = self.shared_state_lock();
|
||||
|
||||
shared_state
|
||||
.desired_fullscreen
|
||||
.clone()
|
||||
.unwrap_or_else(|| shared_state.fullscreen.clone())
|
||||
shared_state.desired_fullscreen.clone().unwrap_or_else(|| shared_state.fullscreen.clone())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
|
||||
if let Some(flusher) = self
|
||||
.set_fullscreen_inner(fullscreen)
|
||||
.expect("Failed to change window fullscreen state")
|
||||
if let Some(flusher) =
|
||||
self.set_fullscreen_inner(fullscreen).expect("Failed to change window fullscreen state")
|
||||
{
|
||||
flusher
|
||||
.check()
|
||||
.expect("Failed to change window fullscreen state");
|
||||
flusher.check().expect("Failed to change window fullscreen state");
|
||||
self.invalidate_cached_frame_extents();
|
||||
}
|
||||
}
|
||||
|
|
@ -899,7 +839,7 @@ impl UnownedWindow {
|
|||
drop(shared_state);
|
||||
self.set_fullscreen(fullscreen);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -908,17 +848,11 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
pub fn available_monitors(&self) -> Vec<X11MonitorHandle> {
|
||||
self.xconn
|
||||
.available_monitors()
|
||||
.expect("Failed to get available monitors")
|
||||
self.xconn.available_monitors().expect("Failed to get available monitors")
|
||||
}
|
||||
|
||||
pub fn primary_monitor(&self) -> Option<X11MonitorHandle> {
|
||||
Some(
|
||||
self.xconn
|
||||
.primary_monitor()
|
||||
.expect("Failed to get primary monitor"),
|
||||
)
|
||||
Some(self.xconn.primary_monitor().expect("Failed to get primary monitor"))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -933,9 +867,9 @@ impl UnownedWindow {
|
|||
let hidden_atom = atoms[_NET_WM_STATE_HIDDEN];
|
||||
|
||||
Some(match state {
|
||||
Ok(atoms) => atoms
|
||||
.iter()
|
||||
.any(|atom: &xproto::Atom| *atom as xproto::Atom == hidden_atom),
|
||||
Ok(atoms) => {
|
||||
atoms.iter().any(|atom: &xproto::Atom| *atom as xproto::Atom == hidden_atom)
|
||||
},
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
@ -1020,9 +954,7 @@ impl UnownedWindow {
|
|||
self.set_minimized_inner(minimized)
|
||||
.expect_then_ignore_error("Failed to change window minimization");
|
||||
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to change window minimization");
|
||||
self.xconn.flush_requests().expect("Failed to change window minimization");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1041,7 +973,7 @@ impl UnownedWindow {
|
|||
let horz_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == horz_atom);
|
||||
let vert_maximized = atoms.iter().any(|atom: &xproto::Atom| *atom == vert_atom);
|
||||
horz_maximized && vert_maximized
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -1058,9 +990,7 @@ impl UnownedWindow {
|
|||
pub fn set_maximized(&self, maximized: bool) {
|
||||
self.set_maximized_inner(maximized)
|
||||
.expect_then_ignore_error("Failed to change window maximization");
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to change window maximization");
|
||||
self.xconn.flush_requests().expect("Failed to change window maximization");
|
||||
self.invalidate_cached_frame_extents();
|
||||
}
|
||||
|
||||
|
|
@ -1088,12 +1018,9 @@ impl UnownedWindow {
|
|||
|
||||
#[inline]
|
||||
pub fn set_title(&self, title: &str) {
|
||||
self.set_title_inner(title)
|
||||
.expect_then_ignore_error("Failed to set window title");
|
||||
self.set_title_inner(title).expect_then_ignore_error("Failed to set window title");
|
||||
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to set window title");
|
||||
self.xconn.flush_requests().expect("Failed to set window title");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1115,9 +1042,7 @@ impl UnownedWindow {
|
|||
pub fn set_decorations(&self, decorations: bool) {
|
||||
self.set_decorations_inner(decorations)
|
||||
.expect_then_ignore_error("Failed to set decoration state");
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to set decoration state");
|
||||
self.xconn.flush_requests().expect("Failed to set decoration state");
|
||||
self.invalidate_cached_frame_extents();
|
||||
}
|
||||
|
||||
|
|
@ -1141,8 +1066,7 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
fn set_window_level_inner(&self, level: WindowLevel) -> Result<VoidCookie<'_>, X11Error> {
|
||||
self.toggle_atom(_NET_WM_STATE_ABOVE, level == WindowLevel::AlwaysOnTop)?
|
||||
.ignore_error();
|
||||
self.toggle_atom(_NET_WM_STATE_ABOVE, level == WindowLevel::AlwaysOnTop)?.ignore_error();
|
||||
self.toggle_atom(_NET_WM_STATE_BELOW, level == WindowLevel::AlwaysOnBottom)
|
||||
}
|
||||
|
||||
|
|
@ -1150,9 +1074,7 @@ impl UnownedWindow {
|
|||
pub fn set_window_level(&self, level: WindowLevel) {
|
||||
self.set_window_level_inner(level)
|
||||
.expect_then_ignore_error("Failed to set window-level state");
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to set window-level state");
|
||||
self.xconn.flush_requests().expect("Failed to set window-level state");
|
||||
}
|
||||
|
||||
fn set_icon_inner(&self, icon: PlatformIcon) -> Result<VoidCookie<'_>, X11Error> {
|
||||
|
|
@ -1199,7 +1121,7 @@ impl UnownedWindow {
|
|||
match (visible, shared_state.visibility) {
|
||||
(true, Visibility::Yes) | (true, Visibility::YesWait) | (false, Visibility::No) => {
|
||||
return
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
|
@ -1215,18 +1137,14 @@ impl UnownedWindow {
|
|||
&xproto::ConfigureWindowAux::new().stack_mode(xproto::StackMode::ABOVE),
|
||||
)
|
||||
.expect_then_ignore_error("Failed to call `xcb_configure_window`");
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to call XMapRaised");
|
||||
self.xconn.flush_requests().expect("Failed to call XMapRaised");
|
||||
shared_state.visibility = Visibility::YesWait;
|
||||
} else {
|
||||
self.xconn
|
||||
.xcb_connection()
|
||||
.unmap_window(self.xwindow)
|
||||
.expect_then_ignore_error("Failed to call `xcb_unmap_window`");
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to call XUnmapWindow");
|
||||
self.xconn.flush_requests().expect("Failed to call XUnmapWindow");
|
||||
shared_state.visibility = Visibility::No;
|
||||
}
|
||||
}
|
||||
|
|
@ -1237,9 +1155,7 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
fn update_cached_frame_extents(&self) {
|
||||
let extents = self
|
||||
.xconn
|
||||
.get_frame_extents_heuristic(self.xwindow, self.root);
|
||||
let extents = self.xconn.get_frame_extents_heuristic(self.xwindow, self.root);
|
||||
self.shared_state_lock().frame_extents = Some(extents);
|
||||
}
|
||||
|
||||
|
|
@ -1309,8 +1225,7 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
pub(crate) fn set_position_physical(&self, x: i32, y: i32) {
|
||||
self.set_position_inner(x, y)
|
||||
.expect_then_ignore_error("Failed to call `XMoveWindow`");
|
||||
self.set_position_inner(x, y).expect_then_ignore_error("Failed to call `XMoveWindow`");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1350,14 +1265,10 @@ impl UnownedWindow {
|
|||
.xcb_connection()
|
||||
.configure_window(
|
||||
self.xwindow,
|
||||
&xproto::ConfigureWindowAux::new()
|
||||
.width(width)
|
||||
.height(height),
|
||||
&xproto::ConfigureWindowAux::new().width(width).height(height),
|
||||
)
|
||||
.expect_then_ignore_error("Failed to call `xcb_configure_window`");
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to call XResizeWindow");
|
||||
self.xconn.flush_requests().expect("Failed to call XResizeWindow");
|
||||
// cursor_hittest needs to be reapplied after each window resize.
|
||||
if self.shared_state_lock().cursor_hittest.unwrap_or(false) {
|
||||
let _ = self.set_cursor_hittest(true);
|
||||
|
|
@ -1488,19 +1399,17 @@ impl UnownedWindow {
|
|||
|
||||
pub fn set_resizable(&self, resizable: bool) {
|
||||
if util::wm_name_is_one_of(&["Xfwm4"]) {
|
||||
// Making the window unresizable on Xfwm prevents further changes to `WM_NORMAL_HINTS` from being detected.
|
||||
// This makes it impossible for resizing to be re-enabled, and also breaks DPI scaling. As such, we choose
|
||||
// the lesser of two evils and do nothing.
|
||||
// Making the window unresizable on Xfwm prevents further changes to `WM_NORMAL_HINTS`
|
||||
// from being detected. This makes it impossible for resizing to be
|
||||
// re-enabled, and also breaks DPI scaling. As such, we choose the lesser of
|
||||
// two evils and do nothing.
|
||||
warn!("To avoid a WM bug, disabling resizing has no effect on Xfwm4");
|
||||
return;
|
||||
}
|
||||
|
||||
let (min_size, max_size) = if resizable {
|
||||
let shared_state_lock = self.shared_state_lock();
|
||||
(
|
||||
shared_state_lock.min_inner_size,
|
||||
shared_state_lock.max_inner_size,
|
||||
)
|
||||
(shared_state_lock.min_inner_size, shared_state_lock.max_inner_size)
|
||||
} else {
|
||||
let window_size = Some(Size::from(self.inner_size()));
|
||||
(window_size, window_size)
|
||||
|
|
@ -1559,21 +1468,19 @@ impl UnownedWindow {
|
|||
{
|
||||
self.xconn.set_cursor_icon(self.xwindow, Some(icon));
|
||||
}
|
||||
}
|
||||
Cursor::Custom(RootCustomCursor {
|
||||
inner: PlatformCustomCursor::X(cursor),
|
||||
}) => {
|
||||
},
|
||||
Cursor::Custom(RootCustomCursor { inner: PlatformCustomCursor::X(cursor) }) => {
|
||||
#[allow(clippy::mutex_atomic)]
|
||||
if *self.cursor_visible.lock().unwrap() {
|
||||
self.xconn.set_custom_cursor(self.xwindow, &cursor);
|
||||
}
|
||||
|
||||
*self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(cursor);
|
||||
}
|
||||
},
|
||||
#[cfg(wayland_platform)]
|
||||
Cursor::Custom(RootCustomCursor {
|
||||
inner: PlatformCustomCursor::Wayland(_),
|
||||
}) => tracing::error!("passed a Wayland cursor to X11 backend"),
|
||||
Cursor::Custom(RootCustomCursor { inner: PlatformCustomCursor::Wayland(_) }) => {
|
||||
tracing::error!("passed a Wayland cursor to X11 backend")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1629,23 +1536,23 @@ impl UnownedWindow {
|
|||
xproto::GrabStatus::SUCCESS => Ok(()),
|
||||
xproto::GrabStatus::ALREADY_GRABBED => {
|
||||
Err("Cursor could not be confined: already confined by another client")
|
||||
}
|
||||
},
|
||||
xproto::GrabStatus::INVALID_TIME => {
|
||||
Err("Cursor could not be confined: invalid time")
|
||||
}
|
||||
},
|
||||
xproto::GrabStatus::NOT_VIEWABLE => {
|
||||
Err("Cursor could not be confined: confine location not viewable")
|
||||
}
|
||||
},
|
||||
xproto::GrabStatus::FROZEN => {
|
||||
Err("Cursor could not be confined: frozen by another client")
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.map_err(|err| ExternalError::Os(os_error!(OsError::Misc(err))))
|
||||
}
|
||||
},
|
||||
CursorGrabMode::Locked => {
|
||||
return Err(ExternalError::NotSupported(NotSupportedError::new()));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if result.is_ok() {
|
||||
|
|
@ -1662,23 +1569,20 @@ impl UnownedWindow {
|
|||
if visible == *visible_lock {
|
||||
return;
|
||||
}
|
||||
let cursor = if visible {
|
||||
Some((*self.selected_cursor.lock().unwrap()).clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let cursor =
|
||||
if visible { Some((*self.selected_cursor.lock().unwrap()).clone()) } else { None };
|
||||
*visible_lock = visible;
|
||||
drop(visible_lock);
|
||||
match cursor {
|
||||
Some(SelectedCursor::Custom(cursor)) => {
|
||||
self.xconn.set_custom_cursor(self.xwindow, &cursor);
|
||||
}
|
||||
},
|
||||
Some(SelectedCursor::Named(cursor)) => {
|
||||
self.xconn.set_cursor_icon(self.xwindow, Some(cursor));
|
||||
}
|
||||
},
|
||||
None => {
|
||||
self.xconn.set_cursor_icon(self.xwindow, None);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1831,8 +1735,7 @@ impl UnownedWindow {
|
|||
let state_atom = atoms[WM_STATE];
|
||||
let state_type_atom = atoms[CARD32];
|
||||
let is_minimized = if let Ok(state) =
|
||||
self.xconn
|
||||
.get_property::<u32>(self.xwindow, state_atom, state_type_atom)
|
||||
self.xconn.get_property::<u32>(self.xwindow, state_atom, state_type_atom)
|
||||
{
|
||||
state.contains(&super::ICONIC_STATE)
|
||||
} else {
|
||||
|
|
@ -1915,9 +1818,7 @@ impl UnownedWindow {
|
|||
|
||||
#[inline]
|
||||
pub fn request_redraw(&self) {
|
||||
self.redraw_sender
|
||||
.send(WindowId(self.xwindow as _))
|
||||
.unwrap();
|
||||
self.redraw_sender.send(WindowId(self.xwindow as _)).unwrap();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -2001,10 +1902,7 @@ fn cast_dimension_to_hint(val: u32) -> i32 {
|
|||
/// Use the above strategy to cast a physical size into a hinted size.
|
||||
fn cast_physical_size_to_hint(size: PhysicalSize<u32>) -> (i32, i32) {
|
||||
let PhysicalSize { width, height } = size;
|
||||
(
|
||||
cast_dimension_to_hint(width),
|
||||
cast_dimension_to_hint(height),
|
||||
)
|
||||
(cast_dimension_to_hint(width), cast_dimension_to_hint(height))
|
||||
}
|
||||
|
||||
/// Use the above strategy to cast a size into a hinted size.
|
||||
|
|
|
|||
|
|
@ -1,25 +1,19 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
error::Error,
|
||||
fmt, ptr,
|
||||
sync::{
|
||||
atomic::{AtomicU32, Ordering},
|
||||
Arc, Mutex, RwLock, RwLockReadGuard,
|
||||
},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard};
|
||||
use std::{fmt, ptr};
|
||||
|
||||
use crate::window::CursorIcon;
|
||||
|
||||
use super::{atoms::Atoms, ffi, monitor::MonitorHandle};
|
||||
use x11rb::{
|
||||
connection::Connection,
|
||||
protocol::{
|
||||
randr::ConnectionExt as _,
|
||||
xproto::{self, ConnectionExt},
|
||||
},
|
||||
resource_manager,
|
||||
xcb_ffi::XCBConnection,
|
||||
};
|
||||
use super::atoms::Atoms;
|
||||
use super::ffi;
|
||||
use super::monitor::MonitorHandle;
|
||||
use x11rb::connection::Connection;
|
||||
use x11rb::protocol::randr::ConnectionExt as _;
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt};
|
||||
use x11rb::resource_manager;
|
||||
use x11rb::xcb_ffi::XCBConnection;
|
||||
|
||||
/// A connection to an X server.
|
||||
pub struct XConnection {
|
||||
|
|
@ -158,14 +152,9 @@ impl XConnection {
|
|||
.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 accommodate for a changed window here.
|
||||
let selector_window = xcb
|
||||
.get_selection_owner(xsettings_screen)
|
||||
.ok()?
|
||||
.reply()
|
||||
.ok()?
|
||||
.owner;
|
||||
// TODO: The XSETTINGS window here can change. In the future, listen for DestroyNotify on
|
||||
// this window in order to accommodate for a changed window here.
|
||||
let selector_window = xcb.get_selection_owner(xsettings_screen).ok()?.reply().ok()?.owner;
|
||||
|
||||
xcb.change_window_attributes(
|
||||
selector_window,
|
||||
|
|
@ -198,9 +187,7 @@ impl XConnection {
|
|||
/// Get the underlying XCB connection.
|
||||
#[inline]
|
||||
pub fn xcb_connection(&self) -> &XCBConnection {
|
||||
self.xcb
|
||||
.as_ref()
|
||||
.expect("xcb_connection somehow called after drop?")
|
||||
self.xcb.as_ref().expect("xcb_connection somehow called after drop?")
|
||||
}
|
||||
|
||||
/// Get the list of atoms.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ use std::num::NonZeroUsize;
|
|||
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt};
|
||||
|
||||
use super::{atoms::*, XConnection};
|
||||
use super::atoms::*;
|
||||
use super::XConnection;
|
||||
|
||||
type Result<T> = core::result::Result<T, ParserError>;
|
||||
|
||||
|
|
@ -27,17 +28,11 @@ impl XConnection {
|
|||
let atoms = self.atoms();
|
||||
|
||||
// Get the current owner of the screen's settings.
|
||||
let owner = self
|
||||
.xcb_connection()
|
||||
.get_selection_owner(xsettings_screen)?
|
||||
.reply()?;
|
||||
let owner = self.xcb_connection().get_selection_owner(xsettings_screen)?.reply()?;
|
||||
|
||||
// Read the _XSETTINGS_SETTINGS property.
|
||||
let data: Vec<u8> = self.get_property(
|
||||
owner.owner,
|
||||
atoms[_XSETTINGS_SETTINGS],
|
||||
atoms[_XSETTINGS_SETTINGS],
|
||||
)?;
|
||||
let data: Vec<u8> =
|
||||
self.get_property(owner.owner, atoms[_XSETTINGS_SETTINGS], atoms[_XSETTINGS_SETTINGS])?;
|
||||
|
||||
// Parse the property.
|
||||
let dpi_setting = read_settings(&data)?
|
||||
|
|
@ -48,10 +43,10 @@ impl XConnection {
|
|||
SettingData::Integer(dpi) => dpi as f64,
|
||||
SettingData::String(_) => {
|
||||
return Err(ParserError::BadType(SettingType::String).into())
|
||||
}
|
||||
},
|
||||
SettingData::Color(_) => {
|
||||
return Err(ParserError::BadType(SettingType::Color).into())
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(Some(base_dpi / DPI_MULTIPLIER))
|
||||
|
|
@ -111,7 +106,7 @@ impl<'a> Setting<'a> {
|
|||
SettingType::Integer => {
|
||||
// Read a 32-bit integer.
|
||||
SettingData::Integer(parser.i32()?)
|
||||
}
|
||||
},
|
||||
|
||||
SettingType::String => {
|
||||
// Read the data.
|
||||
|
|
@ -120,7 +115,7 @@ impl<'a> Setting<'a> {
|
|||
parser.pad(data.len(), 4)?;
|
||||
|
||||
SettingData::String(data)
|
||||
}
|
||||
},
|
||||
|
||||
SettingType::Color => {
|
||||
// Read i16's of color.
|
||||
|
|
@ -128,7 +123,7 @@ impl<'a> Setting<'a> {
|
|||
(parser.i16()?, parser.i16()?, parser.i16()?, parser.i16()?);
|
||||
|
||||
SettingData::Color([red, blue, green, alpha])
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(Setting { name, data })
|
||||
|
|
@ -164,9 +159,7 @@ struct Parser<'a> {
|
|||
impl<'a> Parser<'a> {
|
||||
/// Create a new parser.
|
||||
fn new(bytes: &'a [u8]) -> Result<Self> {
|
||||
let (endianness, bytes) = bytes
|
||||
.split_first()
|
||||
.ok_or_else(|| ParserError::ran_out(1, 0))?;
|
||||
let (endianness, bytes) = bytes.split_first().ok_or_else(|| ParserError::ran_out(1, 0))?;
|
||||
let endianness = match *endianness {
|
||||
BIG_ENDIAN => Endianness::Big,
|
||||
LITTLE_ENDIAN => Endianness::Little,
|
||||
|
|
@ -175,9 +168,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
Ok(Self {
|
||||
// Ignore three bytes of padding and the four-byte serial.
|
||||
bytes: bytes
|
||||
.get(7..)
|
||||
.ok_or_else(|| ParserError::ran_out(7, bytes.len()))?,
|
||||
bytes: bytes.get(7..).ok_or_else(|| ParserError::ran_out(7, bytes.len()))?,
|
||||
endianness,
|
||||
})
|
||||
}
|
||||
|
|
@ -255,10 +246,7 @@ impl Endianness {
|
|||
#[derive(Debug)]
|
||||
pub enum ParserError {
|
||||
/// Ran out of bytes.
|
||||
NoMoreBytes {
|
||||
expected: NonZeroUsize,
|
||||
found: usize,
|
||||
},
|
||||
NoMoreBytes { expected: NonZeroUsize, found: usize },
|
||||
|
||||
/// Invalid type.
|
||||
InvalidType(i8),
|
||||
|
|
@ -291,7 +279,7 @@ mod tests {
|
|||
ParserError::NoMoreBytes { expected, found } => {
|
||||
assert_eq!(expected.get(), 1);
|
||||
assert_eq!(found, 0);
|
||||
}
|
||||
},
|
||||
|
||||
_ => panic!(),
|
||||
}
|
||||
|
|
@ -308,10 +296,7 @@ mod tests {
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let settings = read_settings(&data)
|
||||
.unwrap()
|
||||
.collect::<Result<Vec<_>>>()
|
||||
.unwrap();
|
||||
let settings = read_settings(&data).unwrap().collect::<Result<Vec<_>>>().unwrap();
|
||||
|
||||
let dpi = settings.iter().find(|s| s.name == b"Xft/DPI").unwrap();
|
||||
assert_int(&dpi.data, 96 * 1024);
|
||||
|
|
@ -320,10 +305,7 @@ mod tests {
|
|||
|
||||
let rgba = settings.iter().find(|s| s.name == b"Xft/RGBA").unwrap();
|
||||
assert_string(&rgba.data, "rgb");
|
||||
let lcd = settings
|
||||
.iter()
|
||||
.find(|s| s.name == b"Xft/Lcdfilter")
|
||||
.unwrap();
|
||||
let lcd = settings.iter().find(|s| s.name == b"Xft/Lcdfilter").unwrap();
|
||||
assert_string(&lcd.data, "lcddefault");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue