Update SCTK to 0.18.0
The update is pretty minor, however we support now `WindowEvent::Occluded` when xdg-shell v6 is available. It also adds support for `Window::show_window_menu`. Fixes #2927.
This commit is contained in:
parent
844269d017
commit
b7e3649e8b
15 changed files with 224 additions and 165 deletions
|
|
@ -30,9 +30,10 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
- On Android, fix `DeviceId` to contain device id's.
|
- On Android, fix `DeviceId` to contain device id's.
|
||||||
- Add `Window::set_blur` to request a blur behind the window; implemented on Wayland for now.
|
- Add `Window::set_blur` to request a blur behind the window; implemented on Wayland for now.
|
||||||
- On Web, fix `ControlFlow::WaitUntil` to never wake up **before** the given time.
|
- On Web, fix `ControlFlow::WaitUntil` to never wake up **before** the given time.
|
||||||
- Add `Window::show_window_menu` to request a titlebar/system menu; implemented on Windows for now.
|
- Add `Window::show_window_menu` to request a titlebar/system menu; implemented on Wayland/Windows for now.
|
||||||
- On iOS, send events `WindowEvent::Occluded(false)`, `WindowEvent::Occluded(true)` when application enters/leaves foreground.
|
- On iOS, send events `WindowEvent::Occluded(false)`, `WindowEvent::Occluded(true)` when application enters/leaves foreground.
|
||||||
- **Breaking** add `Event::MemoryWarning`; implemented on iOS/Android.
|
- **Breaking** add `Event::MemoryWarning`; implemented on iOS/Android.
|
||||||
|
- On Wayland, support `Occluded` event with xdg-shell v6
|
||||||
|
|
||||||
# 0.29.1-beta
|
# 0.29.1-beta
|
||||||
|
|
||||||
|
|
|
||||||
20
Cargo.toml
20
Cargo.toml
|
|
@ -37,7 +37,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||||
[features]
|
[features]
|
||||||
default = ["rwh_06", "x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
|
default = ["rwh_06", "x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
|
||||||
x11 = ["x11-dl", "bytemuck", "percent-encoding", "xkbcommon-dl/x11", "x11rb"]
|
x11 = ["x11-dl", "bytemuck", "percent-encoding", "xkbcommon-dl/x11", "x11rb"]
|
||||||
wayland = ["wayland-client", "wayland-backend", "wayland-protocols", "wayland-protocols-plasma", "sctk", "fnv", "memmap2"]
|
wayland = ["wayland-client", "wayland-backend", "wayland-protocols", "wayland-protocols-plasma", "sctk", "ahash", "memmap2"]
|
||||||
wayland-dlopen = ["wayland-backend/dlopen"]
|
wayland-dlopen = ["wayland-backend/dlopen"]
|
||||||
wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/ab_glyph"]
|
wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/ab_glyph"]
|
||||||
wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"]
|
wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"]
|
||||||
|
|
@ -142,22 +142,22 @@ features = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_os = "ios", target_os = "macos"))))'.dependencies]
|
[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_os = "ios", target_os = "macos"))))'.dependencies]
|
||||||
|
ahash = { version = "0.8.3", features = ["no-rng"], optional = true }
|
||||||
bytemuck = { version = "1.13.1", default-features = false, optional = true }
|
bytemuck = { version = "1.13.1", default-features = false, optional = true }
|
||||||
|
calloop = "0.12.3"
|
||||||
libc = "0.2.64"
|
libc = "0.2.64"
|
||||||
|
memmap2 = { version = "0.9.0", optional = true }
|
||||||
percent-encoding = { version = "2.0", optional = true }
|
percent-encoding = { version = "2.0", optional = true }
|
||||||
fnv = { version = "1.0.3", optional = true }
|
|
||||||
sctk = { package = "smithay-client-toolkit", version = "0.17.0", default-features = false, features = ["calloop"], optional = true }
|
|
||||||
sctk-adwaita = { version = "0.6.0", default_features = false, optional = true }
|
|
||||||
wayland-client = { version = "0.30.0", optional = true }
|
|
||||||
wayland-backend = { version = "0.1.0", default_features = false, features = ["client_system"], optional = true }
|
|
||||||
wayland-protocols = { version = "0.30.0", features = [ "staging"], optional = true }
|
|
||||||
wayland-protocols-plasma = { version = "0.1.0", features = [ "client" ], optional = true }
|
|
||||||
calloop = "0.10.5"
|
|
||||||
rustix = { version = "0.38.4", default-features = false, features = ["std", "system", "thread", "process"] }
|
rustix = { version = "0.38.4", default-features = false, features = ["std", "system", "thread", "process"] }
|
||||||
|
sctk = { package = "smithay-client-toolkit", version = "0.18.0", default-features = false, features = ["calloop"], optional = true }
|
||||||
|
sctk-adwaita = { version = "0.7.0", default_features = false, optional = true }
|
||||||
|
wayland-backend = { version = "0.3.0", default_features = false, features = ["client_system"], optional = true }
|
||||||
|
wayland-client = { version = "0.31.1", optional = true }
|
||||||
|
wayland-protocols = { version = "0.31.0", features = [ "staging"], optional = true }
|
||||||
|
wayland-protocols-plasma = { version = "0.2.0", features = [ "client" ], optional = true }
|
||||||
x11-dl = { version = "2.18.5", optional = true }
|
x11-dl = { version = "2.18.5", optional = true }
|
||||||
x11rb = { version = "0.12.0", default-features = false, features = ["allow-unsafe-code", "dl-libxcb", "randr", "resource_manager", "xinput", "xkb"], optional = true }
|
x11rb = { version = "0.12.0", default-features = false, features = ["allow-unsafe-code", "dl-libxcb", "randr", "resource_manager", "xinput", "xkb"], optional = true }
|
||||||
xkbcommon-dl = "0.4.0"
|
xkbcommon-dl = "0.4.0"
|
||||||
memmap2 = { version = "0.5.0", optional = true }
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "redox")'.dependencies]
|
[target.'cfg(target_os = "redox")'.dependencies]
|
||||||
orbclient = { version = "0.3.42", default-features = false }
|
orbclient = { version = "0.3.42", default-features = false }
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,6 @@ deny = []
|
||||||
skip = [
|
skip = [
|
||||||
{ name = "raw-window-handle" }, # we intentionally have multiple versions of this
|
{ name = "raw-window-handle" }, # we intentionally have multiple versions of this
|
||||||
{ name = "bitflags" }, # the ecosystem is in the process of migrating.
|
{ name = "bitflags" }, # the ecosystem is in the process of migrating.
|
||||||
{ name = "nix" }, # differing version - as of 2023-03-02 whis can be solved with `cargo update && cargo update -p calloop --precise 0.10.2`
|
|
||||||
{ name = "memoffset"}, # due to different nix versions.
|
|
||||||
{ name = "memmap2" }, # sctk uses a different version until the next update
|
|
||||||
{ name = "libloading" }, # x11rb uses a different version until the next update
|
{ name = "libloading" }, # x11rb uses a different version until the next update
|
||||||
{ name = "syn" }, # https://github.com/rust-mobile/ndk/issues/392
|
{ name = "syn" }, # https://github.com/rust-mobile/ndk/issues/392
|
||||||
{ name = "num_enum"}, # See above ^, waiting for release
|
{ name = "num_enum"}, # See above ^, waiting for release
|
||||||
|
|
|
||||||
|
|
@ -574,7 +574,7 @@ pub enum WindowEvent {
|
||||||
/// ### Others
|
/// ### Others
|
||||||
///
|
///
|
||||||
/// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`].
|
/// - **Web:** Doesn't take into account CSS [`border`], [`padding`], or [`transform`].
|
||||||
/// - **Android / Wayland / Windows / Orbital:** Unsupported.
|
/// - **Android / Windows / Orbital:** Unsupported.
|
||||||
///
|
///
|
||||||
/// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border
|
/// [`border`]: https://developer.mozilla.org/en-US/docs/Web/CSS/border
|
||||||
/// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding
|
/// [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use xkbcommon_dl::{
|
||||||
XkbCommonCompose,
|
XkbCommonCompose,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
use {memmap2::MmapOptions, wayland_backend::io_lifetimes::OwnedFd};
|
use {memmap2::MmapOptions, std::os::unix::io::OwnedFd};
|
||||||
#[cfg(feature = "x11")]
|
#[cfg(feature = "x11")]
|
||||||
use {x11_dl::xlib_xcb::xcb_connection_t, xkbcommon_dl::x11::xkbcommon_x11_handle};
|
use {x11_dl::xlib_xcb::xcb_connection_t, xkbcommon_dl::x11::xkbcommon_x11_handle};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -444,7 +444,9 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn show_window_menu(&self, _position: Position) {}
|
pub fn show_window_menu(&self, position: Position) {
|
||||||
|
x11_or_wayland!(match self; Window(w) => w.show_window_menu(position))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
|
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,9 @@ use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use sctk::reexports::calloop;
|
use sctk::reexports::calloop;
|
||||||
use sctk::reexports::calloop::Error as CalloopError;
|
use sctk::reexports::calloop::Error as CalloopError;
|
||||||
|
use sctk::reexports::calloop_wayland_source::WaylandSource;
|
||||||
use sctk::reexports::client::globals;
|
use sctk::reexports::client::globals;
|
||||||
use sctk::reexports::client::{Connection, QueueHandle, WaylandSource};
|
use sctk::reexports::client::{Connection, QueueHandle};
|
||||||
|
|
||||||
use crate::dpi::{LogicalSize, PhysicalSize};
|
use crate::dpi::{LogicalSize, PhysicalSize};
|
||||||
use crate::error::{EventLoopError, OsError as RootOsError};
|
use crate::error::{EventLoopError, OsError as RootOsError};
|
||||||
|
|
@ -100,7 +101,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Register Wayland source.
|
// Register Wayland source.
|
||||||
let wayland_source = map_err!(WaylandSource::new(event_queue), WaylandError::Wire)?;
|
let wayland_source = WaylandSource::new(connection.clone(), event_queue);
|
||||||
let wayland_dispatcher =
|
let wayland_dispatcher =
|
||||||
calloop::Dispatcher::new(wayland_source, |_, queue, winit_state: &mut WinitState| {
|
calloop::Dispatcher::new(wayland_source, |_, queue, winit_state: &mut WinitState| {
|
||||||
let result = queue.dispatch_pending(winit_state);
|
let result = queue.dispatch_pending(winit_state);
|
||||||
|
|
@ -252,46 +253,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let cause = loop {
|
let cause = loop {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
// TODO(rib): remove this workaround and instead make sure that the calloop
|
timeout = {
|
||||||
// WaylandSource correctly implements the cooperative prepare_read protocol
|
|
||||||
// that support multithreaded wayland clients that may all read from the
|
|
||||||
// same socket.
|
|
||||||
//
|
|
||||||
// During the run of the user callback, some other code monitoring and reading the
|
|
||||||
// Wayland socket may have been run (mesa for example does this with vsync), if that
|
|
||||||
// is the case, some events may have been enqueued in our event queue.
|
|
||||||
//
|
|
||||||
// If some messages are there, the event loop needs to behave as if it was instantly
|
|
||||||
// woken up by messages arriving from the Wayland socket, to avoid delaying the
|
|
||||||
// dispatch of these events until we're woken up again.
|
|
||||||
let instant_wakeup = {
|
|
||||||
let mut wayland_source = self.wayland_dispatcher.as_source_mut();
|
|
||||||
let queue = wayland_source.queue();
|
|
||||||
let state = match &mut self.window_target.p {
|
|
||||||
PlatformEventLoopWindowTarget::Wayland(window_target) => {
|
|
||||||
window_target.state.get_mut()
|
|
||||||
}
|
|
||||||
#[cfg(x11_platform)]
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match queue.dispatch_pending(state) {
|
|
||||||
Ok(dispatched) => {
|
|
||||||
state.dispatched_events |= !state.events_sink.is_empty()
|
|
||||||
|| !state.window_compositor_updates.is_empty();
|
|
||||||
dispatched > 0
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
error!("Error dispatching wayland queue: {}", error);
|
|
||||||
self.set_exit_code(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
timeout = if instant_wakeup {
|
|
||||||
Some(Duration::ZERO)
|
|
||||||
} else {
|
|
||||||
let control_flow_timeout = match self.control_flow() {
|
let control_flow_timeout = match self.control_flow() {
|
||||||
ControlFlow::Wait => None,
|
ControlFlow::Wait => None,
|
||||||
ControlFlow::Poll => Some(Duration::ZERO),
|
ControlFlow::Poll => Some(Duration::ZERO),
|
||||||
|
|
@ -305,7 +267,13 @@ impl<T: 'static> EventLoop<T> {
|
||||||
// NOTE Ideally we should flush as the last thing we do before polling
|
// NOTE Ideally we should flush as the last thing we do before polling
|
||||||
// to wait for events, and this should be done by the calloop
|
// to wait for events, and this should be done by the calloop
|
||||||
// WaylandSource but we currently need to flush writes manually.
|
// WaylandSource but we currently need to flush writes manually.
|
||||||
let _ = self.connection.flush();
|
//
|
||||||
|
// Checking for flush error is essential to perform an exit with error, since
|
||||||
|
// once we have a protocol error, we could get stuck retrying...
|
||||||
|
if self.connection.flush().is_err() {
|
||||||
|
self.set_exit_code(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(error) = self.loop_dispatch(timeout) {
|
if let Err(error) = self.loop_dispatch(timeout) {
|
||||||
// NOTE We exit on errors from dispatches, since if we've got protocol error
|
// NOTE We exit on errors from dispatches, since if we've got protocol error
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,11 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Drop the repeat, if there were any.
|
// Drop the repeat, if there were any.
|
||||||
seat_state.keyboard_state.as_mut().unwrap().current_repeat = None;
|
let keyboard_state = seat_state.keyboard_state.as_mut().unwrap();
|
||||||
|
keyboard_state.current_repeat = None;
|
||||||
|
if let Some(token) = keyboard_state.repeat_token.take() {
|
||||||
|
keyboard_state.loop_handle.remove(token);
|
||||||
|
}
|
||||||
|
|
||||||
// The keyboard focus is considered as general focus.
|
// The keyboard focus is considered as general focus.
|
||||||
state
|
state
|
||||||
|
|
@ -89,7 +93,11 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
||||||
|
|
||||||
// NOTE: we should drop the repeat regardless whethere it was for the present
|
// NOTE: we should drop the repeat regardless whethere it was for the present
|
||||||
// window of for the window which just went gone.
|
// window of for the window which just went gone.
|
||||||
seat_state.keyboard_state.as_mut().unwrap().current_repeat = None;
|
let keyboard_state = seat_state.keyboard_state.as_mut().unwrap();
|
||||||
|
keyboard_state.current_repeat = None;
|
||||||
|
if let Some(token) = keyboard_state.repeat_token.take() {
|
||||||
|
keyboard_state.loop_handle.remove(token);
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: The check whether the window exists is essential as we might get a
|
// NOTE: The check whether the window exists is essential as we might get a
|
||||||
// nil surface, regardless of what protocol says.
|
// nil surface, regardless of what protocol says.
|
||||||
|
|
@ -204,6 +212,9 @@ impl Dispatch<WlKeyboard, KeyboardData, WinitState> for WinitState {
|
||||||
&& Some(key) == keyboard_state.current_repeat
|
&& Some(key) == keyboard_state.current_repeat
|
||||||
{
|
{
|
||||||
keyboard_state.current_repeat = None;
|
keyboard_state.current_repeat = None;
|
||||||
|
if let Some(token) = keyboard_state.repeat_token.take() {
|
||||||
|
keyboard_state.loop_handle.remove(token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WlKeyboardEvent::Modifiers {
|
WlKeyboardEvent::Modifiers {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use fnv::FnvHashMap;
|
use ahash::AHashMap;
|
||||||
|
|
||||||
use sctk::reexports::client::protocol::wl_seat::WlSeat;
|
use sctk::reexports::client::protocol::wl_seat::WlSeat;
|
||||||
use sctk::reexports::client::protocol::wl_touch::WlTouch;
|
use sctk::reexports::client::protocol::wl_touch::WlTouch;
|
||||||
|
|
@ -29,7 +29,7 @@ use keyboard::{KeyboardData, KeyboardState};
|
||||||
use text_input::TextInputData;
|
use text_input::TextInputData;
|
||||||
use touch::TouchPoint;
|
use touch::TouchPoint;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct WinitSeatState {
|
pub struct WinitSeatState {
|
||||||
/// The pointer bound on the seat.
|
/// The pointer bound on the seat.
|
||||||
pointer: Option<Arc<ThemedPointer<WinitPointerData>>>,
|
pointer: Option<Arc<ThemedPointer<WinitPointerData>>>,
|
||||||
|
|
@ -38,7 +38,7 @@ pub struct WinitSeatState {
|
||||||
touch: Option<WlTouch>,
|
touch: Option<WlTouch>,
|
||||||
|
|
||||||
/// The mapping from touched points to the surfaces they're present.
|
/// The mapping from touched points to the surfaces they're present.
|
||||||
touch_map: FnvHashMap<i32, TouchPoint>,
|
touch_map: AHashMap<i32, TouchPoint>,
|
||||||
|
|
||||||
/// The text input bound on the seat.
|
/// The text input bound on the seat.
|
||||||
text_input: Option<Arc<ZwpTextInputV3>>,
|
text_input: Option<Arc<ZwpTextInputV3>>,
|
||||||
|
|
@ -58,16 +58,7 @@ pub struct WinitSeatState {
|
||||||
|
|
||||||
impl WinitSeatState {
|
impl WinitSeatState {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Default::default()
|
||||||
pointer: None,
|
|
||||||
touch: None,
|
|
||||||
relative_pointer: None,
|
|
||||||
text_input: None,
|
|
||||||
touch_map: Default::default(),
|
|
||||||
keyboard_state: None,
|
|
||||||
modifiers: ModifiersState::empty(),
|
|
||||||
modifiers_pending: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,12 +88,14 @@ impl SeatHandler for WinitState {
|
||||||
SeatCapability::Pointer if seat_state.pointer.is_none() => {
|
SeatCapability::Pointer if seat_state.pointer.is_none() => {
|
||||||
let surface = self.compositor_state.create_surface(queue_handle);
|
let surface = self.compositor_state.create_surface(queue_handle);
|
||||||
let surface_id = surface.id();
|
let surface_id = surface.id();
|
||||||
let pointer_data = WinitPointerData::new(seat.clone(), surface);
|
let pointer_data = WinitPointerData::new(seat.clone());
|
||||||
let themed_pointer = self
|
let themed_pointer = self
|
||||||
.seat_state
|
.seat_state
|
||||||
.get_pointer_with_theme_and_data(
|
.get_pointer_with_theme_and_data(
|
||||||
queue_handle,
|
queue_handle,
|
||||||
&seat,
|
&seat,
|
||||||
|
self.shm.wl_shm(),
|
||||||
|
surface,
|
||||||
ThemeSpec::System,
|
ThemeSpec::System,
|
||||||
pointer_data,
|
pointer_data,
|
||||||
)
|
)
|
||||||
|
|
@ -167,7 +160,7 @@ impl SeatHandler for WinitState {
|
||||||
let pointer_data = pointer.pointer().winit_data();
|
let pointer_data = pointer.pointer().winit_data();
|
||||||
|
|
||||||
// Remove the cursor from the mapping.
|
// Remove the cursor from the mapping.
|
||||||
let surface_id = pointer_data.cursor_surface().id();
|
let surface_id = pointer.surface().id();
|
||||||
let _ = self.pointer_surfaces.remove(&surface_id);
|
let _ = self.pointer_surfaces.remove(&surface_id);
|
||||||
|
|
||||||
// Remove the inner locks/confines before dropping the pointer.
|
// Remove the inner locks/confines before dropping the pointer.
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use sctk::reexports::client::delegate_dispatch;
|
use sctk::reexports::client::delegate_dispatch;
|
||||||
use sctk::reexports::client::protocol::wl_pointer::WlPointer;
|
use sctk::reexports::client::protocol::wl_pointer::WlPointer;
|
||||||
|
|
@ -10,15 +11,17 @@ use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||||
use sctk::reexports::client::{Connection, Proxy, QueueHandle, Dispatch};
|
use sctk::reexports::client::{Connection, Proxy, QueueHandle, Dispatch};
|
||||||
use sctk::reexports::protocols::wp::pointer_constraints::zv1::client::zwp_confined_pointer_v1::ZwpConfinedPointerV1;
|
use sctk::reexports::protocols::wp::pointer_constraints::zv1::client::zwp_confined_pointer_v1::ZwpConfinedPointerV1;
|
||||||
use sctk::reexports::protocols::wp::pointer_constraints::zv1::client::zwp_locked_pointer_v1::ZwpLockedPointerV1;
|
use sctk::reexports::protocols::wp::pointer_constraints::zv1::client::zwp_locked_pointer_v1::ZwpLockedPointerV1;
|
||||||
|
use sctk::reexports::protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::WpCursorShapeDeviceV1;
|
||||||
|
use sctk::reexports::protocols::wp::cursor_shape::v1::client::wp_cursor_shape_manager_v1::WpCursorShapeManagerV1;
|
||||||
use sctk::reexports::protocols::wp::pointer_constraints::zv1::client::zwp_pointer_constraints_v1::{Lifetime, ZwpPointerConstraintsV1};
|
use sctk::reexports::protocols::wp::pointer_constraints::zv1::client::zwp_pointer_constraints_v1::{Lifetime, ZwpPointerConstraintsV1};
|
||||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||||
|
use sctk::reexports::csd_frame::FrameClick;
|
||||||
|
|
||||||
use sctk::compositor::SurfaceData;
|
use sctk::compositor::SurfaceData;
|
||||||
use sctk::globals::GlobalData;
|
use sctk::globals::GlobalData;
|
||||||
use sctk::seat::pointer::{PointerData, PointerDataExt};
|
use sctk::seat::pointer::{PointerData, PointerDataExt};
|
||||||
use sctk::seat::pointer::{PointerEvent, PointerEventKind, PointerHandler};
|
use sctk::seat::pointer::{PointerEvent, PointerEventKind, PointerHandler};
|
||||||
use sctk::seat::SeatState;
|
use sctk::seat::SeatState;
|
||||||
use sctk::shell::xdg::frame::FrameClick;
|
|
||||||
|
|
||||||
use crate::dpi::{LogicalPosition, PhysicalPosition};
|
use crate::dpi::{LogicalPosition, PhysicalPosition};
|
||||||
use crate::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent};
|
use crate::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent};
|
||||||
|
|
@ -67,35 +70,31 @@ impl PointerHandler for WinitState {
|
||||||
PointerEventKind::Enter { .. } | PointerEventKind::Motion { .. }
|
PointerEventKind::Enter { .. } | PointerEventKind::Motion { .. }
|
||||||
if parent_surface != surface =>
|
if parent_surface != surface =>
|
||||||
{
|
{
|
||||||
if let Some(icon) =
|
if let Some(icon) = window.frame_point_moved(
|
||||||
window.frame_point_moved(seat, surface, event.position.0, event.position.1)
|
seat,
|
||||||
{
|
surface,
|
||||||
|
Duration::ZERO,
|
||||||
|
event.position.0,
|
||||||
|
event.position.1,
|
||||||
|
) {
|
||||||
if let Some(pointer) = seat_state.pointer.as_ref() {
|
if let Some(pointer) = seat_state.pointer.as_ref() {
|
||||||
let surface = pointer
|
let _ = pointer.set_cursor(connection, icon);
|
||||||
.pointer()
|
|
||||||
.data::<WinitPointerData>()
|
|
||||||
.unwrap()
|
|
||||||
.cursor_surface();
|
|
||||||
let scale_factor =
|
|
||||||
surface.data::<SurfaceData>().unwrap().scale_factor();
|
|
||||||
|
|
||||||
let _ = pointer.set_cursor(
|
|
||||||
connection,
|
|
||||||
icon,
|
|
||||||
self.shm.wl_shm(),
|
|
||||||
surface,
|
|
||||||
scale_factor,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PointerEventKind::Leave { .. } if parent_surface != surface => {
|
PointerEventKind::Leave { .. } if parent_surface != surface => {
|
||||||
window.frame_point_left();
|
window.frame_point_left();
|
||||||
}
|
}
|
||||||
ref kind @ PointerEventKind::Press { button, serial, .. }
|
ref kind @ PointerEventKind::Press {
|
||||||
| ref kind @ PointerEventKind::Release { button, serial, .. }
|
button,
|
||||||
if parent_surface != surface =>
|
serial,
|
||||||
{
|
time,
|
||||||
|
}
|
||||||
|
| ref kind @ PointerEventKind::Release {
|
||||||
|
button,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
} if parent_surface != surface => {
|
||||||
let click = match wayland_button_to_winit(button) {
|
let click = match wayland_button_to_winit(button) {
|
||||||
MouseButton::Left => FrameClick::Normal,
|
MouseButton::Left => FrameClick::Normal,
|
||||||
MouseButton::Right => FrameClick::Alternate,
|
MouseButton::Right => FrameClick::Alternate,
|
||||||
|
|
@ -109,6 +108,7 @@ impl PointerHandler for WinitState {
|
||||||
pressed,
|
pressed,
|
||||||
seat,
|
seat,
|
||||||
serial,
|
serial,
|
||||||
|
Duration::from_millis(time as u64),
|
||||||
window_id,
|
window_id,
|
||||||
&mut self.window_compositor_updates,
|
&mut self.window_compositor_updates,
|
||||||
);
|
);
|
||||||
|
|
@ -238,9 +238,6 @@ impl PointerHandler for WinitState {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WinitPointerData {
|
pub struct WinitPointerData {
|
||||||
/// The surface associated with this pointer, which is used for icons.
|
|
||||||
cursor_surface: WlSurface,
|
|
||||||
|
|
||||||
/// The inner winit data associated with the pointer.
|
/// The inner winit data associated with the pointer.
|
||||||
inner: Mutex<WinitPointerDataInner>,
|
inner: Mutex<WinitPointerDataInner>,
|
||||||
|
|
||||||
|
|
@ -249,9 +246,8 @@ pub struct WinitPointerData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WinitPointerData {
|
impl WinitPointerData {
|
||||||
pub fn new(seat: WlSeat, surface: WlSurface) -> Self {
|
pub fn new(seat: WlSeat) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cursor_surface: surface,
|
|
||||||
inner: Mutex::new(WinitPointerDataInner::default()),
|
inner: Mutex::new(WinitPointerDataInner::default()),
|
||||||
sctk_data: PointerData::new(seat),
|
sctk_data: PointerData::new(seat),
|
||||||
}
|
}
|
||||||
|
|
@ -313,11 +309,6 @@ impl WinitPointerData {
|
||||||
self.sctk_data.seat()
|
self.sctk_data.seat()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The WlSurface used to set cursor theme.
|
|
||||||
pub fn cursor_surface(&self) -> &WlSurface {
|
|
||||||
&self.cursor_surface
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Active window.
|
/// Active window.
|
||||||
pub fn focused_window(&self) -> Option<WindowId> {
|
pub fn focused_window(&self) -> Option<WindowId> {
|
||||||
self.inner.lock().unwrap().surface
|
self.inner.lock().unwrap().surface
|
||||||
|
|
@ -325,7 +316,7 @@ impl WinitPointerData {
|
||||||
|
|
||||||
/// Last button serial.
|
/// Last button serial.
|
||||||
pub fn latest_button_serial(&self) -> u32 {
|
pub fn latest_button_serial(&self) -> u32 {
|
||||||
self.inner.lock().unwrap().latest_button_serial
|
self.sctk_data.latest_button_serial().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Last enter serial.
|
/// Last enter serial.
|
||||||
|
|
@ -341,12 +332,6 @@ impl WinitPointerData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for WinitPointerData {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.cursor_surface.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PointerDataExt for WinitPointerData {
|
impl PointerDataExt for WinitPointerData {
|
||||||
fn pointer_data(&self) -> &PointerData {
|
fn pointer_data(&self) -> &PointerData {
|
||||||
&self.sctk_data
|
&self.sctk_data
|
||||||
|
|
@ -486,7 +471,35 @@ impl Dispatch<ZwpConfinedPointerV1, GlobalData, WinitState> for PointerConstrain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Dispatch<WpCursorShapeDeviceV1, GlobalData, WinitState> for SeatState {
|
||||||
|
fn event(
|
||||||
|
_: &mut WinitState,
|
||||||
|
_: &WpCursorShapeDeviceV1,
|
||||||
|
_: <WpCursorShapeDeviceV1 as Proxy>::Event,
|
||||||
|
_: &GlobalData,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<WinitState>,
|
||||||
|
) {
|
||||||
|
unreachable!("wp_cursor_shape_manager has no events")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<WpCursorShapeManagerV1, GlobalData, WinitState> for SeatState {
|
||||||
|
fn event(
|
||||||
|
_: &mut WinitState,
|
||||||
|
_: &WpCursorShapeManagerV1,
|
||||||
|
_: <WpCursorShapeManagerV1 as Proxy>::Event,
|
||||||
|
_: &GlobalData,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<WinitState>,
|
||||||
|
) {
|
||||||
|
unreachable!("wp_cursor_device_manager has no events")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delegate_dispatch!(WinitState: [ WlPointer: WinitPointerData] => SeatState);
|
delegate_dispatch!(WinitState: [ WlPointer: WinitPointerData] => SeatState);
|
||||||
|
delegate_dispatch!(WinitState: [ WpCursorShapeManagerV1: GlobalData] => SeatState);
|
||||||
|
delegate_dispatch!(WinitState: [ WpCursorShapeDeviceV1: GlobalData] => SeatState);
|
||||||
delegate_dispatch!(WinitState: [ZwpPointerConstraintsV1: GlobalData] => PointerConstraintsState);
|
delegate_dispatch!(WinitState: [ZwpPointerConstraintsV1: GlobalData] => PointerConstraintsState);
|
||||||
delegate_dispatch!(WinitState: [ZwpLockedPointerV1: GlobalData] => PointerConstraintsState);
|
delegate_dispatch!(WinitState: [ZwpLockedPointerV1: GlobalData] => PointerConstraintsState);
|
||||||
delegate_dispatch!(WinitState: [ZwpConfinedPointerV1: GlobalData] => PointerConstraintsState);
|
delegate_dispatch!(WinitState: [ZwpConfinedPointerV1: GlobalData] => PointerConstraintsState);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::cell::RefCell;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use fnv::FnvHashMap;
|
use ahash::AHashMap;
|
||||||
|
|
||||||
use sctk::reexports::calloop::LoopHandle;
|
use sctk::reexports::calloop::LoopHandle;
|
||||||
use sctk::reexports::client::backend::ObjectId;
|
use sctk::reexports::client::backend::ObjectId;
|
||||||
|
|
@ -62,10 +62,10 @@ pub struct WinitState {
|
||||||
pub xdg_shell: XdgShell,
|
pub xdg_shell: XdgShell,
|
||||||
|
|
||||||
/// The currently present windows.
|
/// The currently present windows.
|
||||||
pub windows: RefCell<FnvHashMap<WindowId, Arc<Mutex<WindowState>>>>,
|
pub windows: RefCell<AHashMap<WindowId, Arc<Mutex<WindowState>>>>,
|
||||||
|
|
||||||
/// The requests from the `Window` to EventLoop, such as close operations and redraw requests.
|
/// The requests from the `Window` to EventLoop, such as close operations and redraw requests.
|
||||||
pub window_requests: RefCell<FnvHashMap<WindowId, Arc<WindowRequests>>>,
|
pub window_requests: RefCell<AHashMap<WindowId, Arc<WindowRequests>>>,
|
||||||
|
|
||||||
/// The events that were generated directly from the window.
|
/// The events that were generated directly from the window.
|
||||||
pub window_events_sink: Arc<Mutex<EventSink>>,
|
pub window_events_sink: Arc<Mutex<EventSink>>,
|
||||||
|
|
@ -74,10 +74,10 @@ pub struct WinitState {
|
||||||
pub window_compositor_updates: Vec<WindowCompositorUpdate>,
|
pub window_compositor_updates: Vec<WindowCompositorUpdate>,
|
||||||
|
|
||||||
/// Currently handled seats.
|
/// Currently handled seats.
|
||||||
pub seats: FnvHashMap<ObjectId, WinitSeatState>,
|
pub seats: AHashMap<ObjectId, WinitSeatState>,
|
||||||
|
|
||||||
/// Currently present cursor surfaces.
|
/// Currently present cursor surfaces.
|
||||||
pub pointer_surfaces: FnvHashMap<ObjectId, Arc<ThemedPointer<WinitPointerData>>>,
|
pub pointer_surfaces: AHashMap<ObjectId, Arc<ThemedPointer<WinitPointerData>>>,
|
||||||
|
|
||||||
/// The state of the text input on the client.
|
/// The state of the text input on the client.
|
||||||
pub text_input_state: Option<TextInputState>,
|
pub text_input_state: Option<TextInputState>,
|
||||||
|
|
@ -136,7 +136,7 @@ impl WinitState {
|
||||||
|
|
||||||
let seat_state = SeatState::new(globals, queue_handle);
|
let seat_state = SeatState::new(globals, queue_handle);
|
||||||
|
|
||||||
let mut seats = FnvHashMap::default();
|
let mut seats = AHashMap::default();
|
||||||
for seat in seat_state.seats() {
|
for seat in seat_state.seats() {
|
||||||
seats.insert(seat.id(), WinitSeatState::new());
|
seats.insert(seat.id(), WinitSeatState::new());
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +287,12 @@ impl WindowHandler for WinitState {
|
||||||
.expect("got configure for dead window.")
|
.expect("got configure for dead window.")
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.configure(configure, &self.shm, &self.subcompositor_state);
|
.configure(
|
||||||
|
configure,
|
||||||
|
&self.shm,
|
||||||
|
&self.subcompositor_state,
|
||||||
|
&mut self.events_sink,
|
||||||
|
);
|
||||||
|
|
||||||
self.window_compositor_updates[pos].size = Some(new_size);
|
self.window_compositor_updates[pos].size = Some(new_size);
|
||||||
}
|
}
|
||||||
|
|
@ -325,6 +330,16 @@ impl OutputHandler for WinitState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompositorHandler for WinitState {
|
impl CompositorHandler for WinitState {
|
||||||
|
fn transform_changed(
|
||||||
|
&mut self,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
_: &wayland_client::protocol::wl_surface::WlSurface,
|
||||||
|
_: wayland_client::protocol::wl_output::Transform,
|
||||||
|
) {
|
||||||
|
// TODO(kchibisov) we need to expose it somehow in winit.
|
||||||
|
}
|
||||||
|
|
||||||
fn scale_factor_changed(
|
fn scale_factor_changed(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &Connection,
|
_: &Connection,
|
||||||
|
|
|
||||||
|
|
@ -374,6 +374,13 @@ impl Window {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn show_window_menu(&self, position: Position) {
|
||||||
|
let scale_factor = self.scale_factor();
|
||||||
|
let position = position.to_logical(scale_factor);
|
||||||
|
self.window_state.lock().unwrap().show_window_menu(position);
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
||||||
self.window_state
|
self.window_state
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
|
|
@ -10,14 +11,16 @@ use sctk::reexports::client::protocol::wl_seat::WlSeat;
|
||||||
use sctk::reexports::client::protocol::wl_shm::WlShm;
|
use sctk::reexports::client::protocol::wl_shm::WlShm;
|
||||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||||
use sctk::reexports::client::{Connection, Proxy, QueueHandle};
|
use sctk::reexports::client::{Connection, Proxy, QueueHandle};
|
||||||
|
use sctk::reexports::csd_frame::{
|
||||||
|
DecorationsFrame, FrameAction, FrameClick, ResizeEdge, WindowState as XdgWindowState,
|
||||||
|
};
|
||||||
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::WpFractionalScaleV1;
|
||||||
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::ZwpTextInputV3;
|
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::ZwpTextInputV3;
|
||||||
use sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport;
|
use sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport;
|
||||||
use sctk::reexports::protocols::xdg::shell::client::xdg_toplevel::ResizeEdge;
|
use sctk::reexports::protocols::xdg::shell::client::xdg_toplevel::ResizeEdge as XdgResizeEdge;
|
||||||
|
|
||||||
use sctk::compositor::{CompositorState, Region, SurfaceData};
|
use sctk::compositor::{CompositorState, Region};
|
||||||
use sctk::seat::pointer::ThemedPointer;
|
use sctk::seat::pointer::ThemedPointer;
|
||||||
use sctk::shell::xdg::frame::{DecorationsFrame, FrameAction, FrameClick};
|
|
||||||
use sctk::shell::xdg::window::{DecorationMode, Window, WindowConfigure};
|
use sctk::shell::xdg::window::{DecorationMode, Window, WindowConfigure};
|
||||||
use sctk::shell::xdg::XdgSurface;
|
use sctk::shell::xdg::XdgSurface;
|
||||||
use sctk::shell::WaylandSurface;
|
use sctk::shell::WaylandSurface;
|
||||||
|
|
@ -27,6 +30,9 @@ use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
||||||
|
|
||||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
use crate::dpi::{LogicalPosition, LogicalSize};
|
||||||
use crate::error::{ExternalError, NotSupportedError};
|
use crate::error::{ExternalError, NotSupportedError};
|
||||||
|
use crate::event::WindowEvent;
|
||||||
|
use crate::platform_impl::wayland::event_loop::sink::EventSink;
|
||||||
|
use crate::platform_impl::wayland::make_wid;
|
||||||
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
|
||||||
use crate::platform_impl::WindowId;
|
use crate::platform_impl::WindowId;
|
||||||
use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme};
|
use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme};
|
||||||
|
|
@ -39,7 +45,7 @@ use crate::platform_impl::wayland::state::{WindowCompositorUpdate, WinitState};
|
||||||
#[cfg(feature = "sctk-adwaita")]
|
#[cfg(feature = "sctk-adwaita")]
|
||||||
pub type WinitFrame = sctk_adwaita::AdwaitaFrame<WinitState>;
|
pub type WinitFrame = sctk_adwaita::AdwaitaFrame<WinitState>;
|
||||||
#[cfg(not(feature = "sctk-adwaita"))]
|
#[cfg(not(feature = "sctk-adwaita"))]
|
||||||
pub type WinitFrame = sctk::shell::xdg::frame::fallback_frame::FallbackFrame<WinitState>;
|
pub type WinitFrame = sctk::shell::xdg::fallback_frame::FallbackFrame<WinitState>;
|
||||||
|
|
||||||
// Minimum window inner size.
|
// Minimum window inner size.
|
||||||
const MIN_WINDOW_SIZE: LogicalSize<u32> = LogicalSize::new(2, 1);
|
const MIN_WINDOW_SIZE: LogicalSize<u32> = LogicalSize::new(2, 1);
|
||||||
|
|
@ -245,6 +251,7 @@ impl WindowState {
|
||||||
configure: WindowConfigure,
|
configure: WindowConfigure,
|
||||||
shm: &Shm,
|
shm: &Shm,
|
||||||
subcompositor: &Arc<SubcompositorState>,
|
subcompositor: &Arc<SubcompositorState>,
|
||||||
|
event_sink: &mut EventSink,
|
||||||
) -> LogicalSize<u32> {
|
) -> LogicalSize<u32> {
|
||||||
if configure.decoration_mode == DecorationMode::Client
|
if configure.decoration_mode == DecorationMode::Client
|
||||||
&& self.frame.is_none()
|
&& self.frame.is_none()
|
||||||
|
|
@ -260,6 +267,7 @@ impl WindowState {
|
||||||
) {
|
) {
|
||||||
Ok(mut frame) => {
|
Ok(mut frame) => {
|
||||||
frame.set_title(&self.title);
|
frame.set_title(&self.title);
|
||||||
|
frame.set_scaling_factor(self.scale_factor);
|
||||||
// Hide the frame if we were asked to not decorate.
|
// Hide the frame if we were asked to not decorate.
|
||||||
frame.set_hidden(!self.decorate);
|
frame.set_hidden(!self.decorate);
|
||||||
self.frame = Some(frame);
|
self.frame = Some(frame);
|
||||||
|
|
@ -276,6 +284,19 @@ impl WindowState {
|
||||||
|
|
||||||
let stateless = Self::is_stateless(&configure);
|
let stateless = Self::is_stateless(&configure);
|
||||||
|
|
||||||
|
// Emit `Occluded` event on suspension change.
|
||||||
|
let occluded = configure.state.contains(XdgWindowState::SUSPENDED);
|
||||||
|
if self
|
||||||
|
.last_configure
|
||||||
|
.as_ref()
|
||||||
|
.map(|c| c.state.contains(XdgWindowState::SUSPENDED))
|
||||||
|
.unwrap_or(false)
|
||||||
|
!= occluded
|
||||||
|
{
|
||||||
|
let window_id = make_wid(self.window.wl_surface());
|
||||||
|
event_sink.push_window_event(WindowEvent::Occluded(occluded), window_id);
|
||||||
|
}
|
||||||
|
|
||||||
let new_size = if let Some(frame) = self.frame.as_mut() {
|
let new_size = if let Some(frame) = self.frame.as_mut() {
|
||||||
// Configure the window states.
|
// Configure the window states.
|
||||||
frame.update_state(configure.state);
|
frame.update_state(configure.state);
|
||||||
|
|
@ -342,23 +363,40 @@ impl WindowState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tells whether the window should be closed.
|
/// Tells whether the window should be closed.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn frame_click(
|
pub fn frame_click(
|
||||||
&mut self,
|
&mut self,
|
||||||
click: FrameClick,
|
click: FrameClick,
|
||||||
pressed: bool,
|
pressed: bool,
|
||||||
seat: &WlSeat,
|
seat: &WlSeat,
|
||||||
serial: u32,
|
serial: u32,
|
||||||
|
timestamp: Duration,
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
updates: &mut Vec<WindowCompositorUpdate>,
|
updates: &mut Vec<WindowCompositorUpdate>,
|
||||||
) -> Option<bool> {
|
) -> Option<bool> {
|
||||||
match self.frame.as_mut()?.on_click(click, pressed)? {
|
match self.frame.as_mut()?.on_click(timestamp, click, pressed)? {
|
||||||
FrameAction::Minimize => self.window.set_minimized(),
|
FrameAction::Minimize => self.window.set_minimized(),
|
||||||
FrameAction::Maximize => self.window.set_maximized(),
|
FrameAction::Maximize => self.window.set_maximized(),
|
||||||
FrameAction::UnMaximize => self.window.unset_maximized(),
|
FrameAction::UnMaximize => self.window.unset_maximized(),
|
||||||
FrameAction::Close => WinitState::queue_close(updates, window_id),
|
FrameAction::Close => WinitState::queue_close(updates, window_id),
|
||||||
FrameAction::Move => self.has_pending_move = Some(serial),
|
FrameAction::Move => self.has_pending_move = Some(serial),
|
||||||
FrameAction::Resize(edge) => self.window.resize(seat, serial, edge),
|
FrameAction::Resize(edge) => {
|
||||||
|
let edge = match edge {
|
||||||
|
ResizeEdge::None => XdgResizeEdge::None,
|
||||||
|
ResizeEdge::Top => XdgResizeEdge::Top,
|
||||||
|
ResizeEdge::Bottom => XdgResizeEdge::Bottom,
|
||||||
|
ResizeEdge::Left => XdgResizeEdge::Left,
|
||||||
|
ResizeEdge::TopLeft => XdgResizeEdge::TopLeft,
|
||||||
|
ResizeEdge::BottomLeft => XdgResizeEdge::BottomLeft,
|
||||||
|
ResizeEdge::Right => XdgResizeEdge::Right,
|
||||||
|
ResizeEdge::TopRight => XdgResizeEdge::TopRight,
|
||||||
|
ResizeEdge::BottomRight => XdgResizeEdge::BottomRight,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
self.window.resize(seat, serial, edge);
|
||||||
|
}
|
||||||
FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)),
|
FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)),
|
||||||
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(false)
|
Some(false)
|
||||||
|
|
@ -375,14 +413,15 @@ impl WindowState {
|
||||||
&mut self,
|
&mut self,
|
||||||
seat: &WlSeat,
|
seat: &WlSeat,
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
|
timestamp: Duration,
|
||||||
x: f64,
|
x: f64,
|
||||||
y: f64,
|
y: f64,
|
||||||
) -> Option<&str> {
|
) -> Option<CursorIcon> {
|
||||||
// Take the serial if we had any, so it doesn't stick around.
|
// Take the serial if we had any, so it doesn't stick around.
|
||||||
let serial = self.has_pending_move.take();
|
let serial = self.has_pending_move.take();
|
||||||
|
|
||||||
if let Some(frame) = self.frame.as_mut() {
|
if let Some(frame) = self.frame.as_mut() {
|
||||||
let cursor = frame.click_point_moved(surface, x, y);
|
let cursor = frame.click_point_moved(timestamp, &surface.id(), x, y);
|
||||||
// If we have a cursor change, that means that cursor is over the decorations,
|
// If we have a cursor change, that means that cursor is over the decorations,
|
||||||
// so try to apply move.
|
// so try to apply move.
|
||||||
if let Some(serial) = cursor.is_some().then_some(serial).flatten() {
|
if let Some(serial) = cursor.is_some().then_some(serial).flatten() {
|
||||||
|
|
@ -498,14 +537,12 @@ impl WindowState {
|
||||||
/// Refresh the decorations frame if it's present returning whether the client should redraw.
|
/// Refresh the decorations frame if it's present returning whether the client should redraw.
|
||||||
pub fn refresh_frame(&mut self) -> bool {
|
pub fn refresh_frame(&mut self) -> bool {
|
||||||
if let Some(frame) = self.frame.as_mut() {
|
if let Some(frame) = self.frame.as_mut() {
|
||||||
let dirty = frame.is_dirty();
|
if frame.is_dirty() {
|
||||||
if dirty {
|
return frame.draw();
|
||||||
frame.draw();
|
|
||||||
}
|
}
|
||||||
dirty
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reload the cursor style on the given window.
|
/// Reload the cursor style on the given window.
|
||||||
|
|
@ -592,20 +629,8 @@ impl WindowState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.apply_on_poiner(|pointer, data| {
|
self.apply_on_poiner(|pointer, _| {
|
||||||
let surface = data.cursor_surface();
|
if pointer.set_cursor(&self.connection, cursor_icon).is_err() {
|
||||||
let scale_factor = surface.data::<SurfaceData>().unwrap().scale_factor();
|
|
||||||
|
|
||||||
if pointer
|
|
||||||
.set_cursor(
|
|
||||||
&self.connection,
|
|
||||||
cursor_icon.name(),
|
|
||||||
&self.shm,
|
|
||||||
surface,
|
|
||||||
scale_factor,
|
|
||||||
)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
warn!("Failed to set cursor to {:?}", cursor_icon);
|
warn!("Failed to set cursor to {:?}", cursor_icon);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -709,6 +734,15 @@ impl WindowState {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn show_window_menu(&self, position: LogicalPosition<u32>) {
|
||||||
|
// TODO(kchibisov) handle touch serials.
|
||||||
|
self.apply_on_poiner(|_, data| {
|
||||||
|
let serial = data.latest_button_serial();
|
||||||
|
let seat = data.seat();
|
||||||
|
self.window.show_window_menu(seat, serial, position.into());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the position of the cursor.
|
/// Set the position of the cursor.
|
||||||
pub fn set_cursor_position(&self, position: LogicalPosition<f64>) -> Result<(), ExternalError> {
|
pub fn set_cursor_position(&self, position: LogicalPosition<f64>) -> Result<(), ExternalError> {
|
||||||
if self.pointer_constraints.is_none() {
|
if self.pointer_constraints.is_none() {
|
||||||
|
|
@ -844,6 +878,10 @@ impl WindowState {
|
||||||
if self.fractional_scale.is_none() {
|
if self.fractional_scale.is_none() {
|
||||||
let _ = self.window.set_buffer_scale(self.scale_factor as _);
|
let _ = self.window.set_buffer_scale(self.scale_factor as _);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(frame) = self.frame.as_mut() {
|
||||||
|
frame.set_scaling_factor(scale_factor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make window background blurred
|
/// Make window background blurred
|
||||||
|
|
@ -926,10 +964,20 @@ impl Drop for WindowState {
|
||||||
ManuallyDrop::drop(&mut self.window);
|
ManuallyDrop::drop(&mut self.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(blur) = &self.blur {
|
// Cleanup objects.
|
||||||
|
|
||||||
|
if let Some(blur) = self.blur.take() {
|
||||||
blur.release();
|
blur.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(fs) = self.fractional_scale.take() {
|
||||||
|
fs.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(viewport) = self.viewport.take() {
|
||||||
|
viewport.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
surface.destroy();
|
surface.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -965,17 +1013,17 @@ pub enum FrameCallbackState {
|
||||||
Received,
|
Received,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ResizeDirection> for ResizeEdge {
|
impl From<ResizeDirection> for XdgResizeEdge {
|
||||||
fn from(value: ResizeDirection) -> Self {
|
fn from(value: ResizeDirection) -> Self {
|
||||||
match value {
|
match value {
|
||||||
ResizeDirection::North => ResizeEdge::Top,
|
ResizeDirection::North => XdgResizeEdge::Top,
|
||||||
ResizeDirection::West => ResizeEdge::Left,
|
ResizeDirection::West => XdgResizeEdge::Left,
|
||||||
ResizeDirection::NorthWest => ResizeEdge::TopLeft,
|
ResizeDirection::NorthWest => XdgResizeEdge::TopLeft,
|
||||||
ResizeDirection::NorthEast => ResizeEdge::TopRight,
|
ResizeDirection::NorthEast => XdgResizeEdge::TopRight,
|
||||||
ResizeDirection::East => ResizeEdge::Right,
|
ResizeDirection::East => XdgResizeEdge::Right,
|
||||||
ResizeDirection::SouthWest => ResizeEdge::BottomLeft,
|
ResizeDirection::SouthWest => XdgResizeEdge::BottomLeft,
|
||||||
ResizeDirection::SouthEast => ResizeEdge::BottomRight,
|
ResizeDirection::SouthEast => XdgResizeEdge::BottomRight,
|
||||||
ResizeDirection::South => ResizeEdge::Bottom,
|
ResizeDirection::South => XdgResizeEdge::Bottom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ use std::{
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
os::{
|
os::{
|
||||||
raw::*,
|
raw::*,
|
||||||
unix::io::{AsRawFd, RawFd},
|
unix::io::{AsRawFd, BorrowedFd},
|
||||||
},
|
},
|
||||||
ptr,
|
ptr,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
|
@ -82,7 +82,7 @@ use crate::{
|
||||||
const ALL_DEVICES: u16 = 0;
|
const ALL_DEVICES: u16 = 0;
|
||||||
const ALL_MASTER_DEVICES: u16 = 1;
|
const ALL_MASTER_DEVICES: u16 = 1;
|
||||||
|
|
||||||
type X11Source = Generic<RawFd>;
|
type X11Source = Generic<BorrowedFd<'static>>;
|
||||||
|
|
||||||
struct WakeSender<T> {
|
struct WakeSender<T> {
|
||||||
sender: Sender<T>,
|
sender: Sender<T>,
|
||||||
|
|
@ -268,7 +268,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
// Create the X11 event dispatcher.
|
// Create the X11 event dispatcher.
|
||||||
let source = X11Source::new(
|
let source = X11Source::new(
|
||||||
xconn.xcb_connection().as_raw_fd(),
|
// SAFETY: xcb owns the FD and outlives the source.
|
||||||
|
unsafe { BorrowedFd::borrow_raw(xconn.xcb_connection().as_raw_fd()) },
|
||||||
calloop::Interest::READ,
|
calloop::Interest::READ,
|
||||||
calloop::Mode::Level,
|
calloop::Mode::Level,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1636,6 +1636,9 @@ impl UnownedWindow {
|
||||||
self.drag_initiate(util::MOVERESIZE_MOVE)
|
self.drag_initiate(util::MOVERESIZE_MOVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn show_window_menu(&self, _position: Position) {}
|
||||||
|
|
||||||
/// Resizes the window while it is being dragged.
|
/// Resizes the window while it is being dragged.
|
||||||
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
||||||
self.drag_initiate(match direction {
|
self.drag_initiate(match direction {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue