mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-22 18:06:33 +11:00
On Wayland, implement 'request_user_attention'
This commit implements 'request_user_attention' on Wayland with new 'xdg_activation_v1' protocol.
This commit is contained in:
parent
c9520deef8
commit
b5d0d6ff3e
7 changed files with 133 additions and 81 deletions
|
@ -11,6 +11,7 @@
|
|||
- On Wayland, load cursor icons `hand2` and `hand1` for `CursorIcon::Hand`.
|
||||
- **Breaking:** On Wayland, Theme trait and its support types are dropped.
|
||||
- On Wayland, bump `smithay-client-toolkit` to 0.15.
|
||||
- On Wayland, implement `request_user_attention` with `xdg_activation_v1`.
|
||||
|
||||
|
||||
# 0.25.0 (2021-05-15)
|
||||
|
|
|
@ -19,7 +19,7 @@ targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "i686-unknown-linux
|
|||
[features]
|
||||
default = ["x11", "wayland"]
|
||||
x11 = ["x11-dl", "mio", "mio-misc", "percent-encoding", "parking_lot"]
|
||||
wayland = ["wayland-client", "sctk"]
|
||||
wayland = ["wayland-client", "wayland-protocols", "sctk"]
|
||||
|
||||
[dependencies]
|
||||
instant = { version = "0.1", features = ["wasm-bindgen"] }
|
||||
|
@ -83,7 +83,8 @@ features = [
|
|||
]
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
|
||||
wayland-client = { version = "0.28", features = [ "dlopen"] , optional = true }
|
||||
wayland-client = { version = "0.29", features = [ "dlopen"], optional = true }
|
||||
wayland-protocols = { version = "0.29", features = [ "staging_protocols"], optional = true }
|
||||
sctk = { package = "smithay-client-toolkit", version = "0.15.0", optional = true }
|
||||
mio = { version = "0.7", features = ["os-ext"], optional = true }
|
||||
mio-misc = { version = "1.0", optional = true }
|
||||
|
|
|
@ -437,12 +437,12 @@ impl Window {
|
|||
_ => (),
|
||||
}
|
||||
}
|
||||
pub fn request_user_attention(&self, _request_type: Option<UserAttentionType>) {
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
match self {
|
||||
#[cfg(feature = "x11")]
|
||||
Window::X(ref w) => w.request_user_attention(_request_type),
|
||||
Window::X(ref w) => w.request_user_attention(request_type),
|
||||
#[cfg(feature = "wayland")]
|
||||
_ => (),
|
||||
Window::Wayland(ref w) => w.request_user_attention(request_type),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ use sctk::reexports::protocols::xdg_shell::client::xdg_wm_base::XdgWmBase;
|
|||
use sctk::reexports::protocols::unstable::relative_pointer::v1::client::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1;
|
||||
use sctk::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1;
|
||||
use sctk::reexports::protocols::unstable::text_input::v3::client::zwp_text_input_manager_v3::ZwpTextInputManagerV3;
|
||||
use sctk::reexports::protocols::staging::xdg_activation::v1::client::xdg_activation_v1::XdgActivationV1;
|
||||
|
||||
use sctk::environment::{Environment, SimpleGlobal};
|
||||
use sctk::output::{OutputHandler, OutputHandling, OutputInfo, OutputStatusListener};
|
||||
|
@ -24,18 +25,27 @@ use sctk::shm::ShmHandler;
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct WindowingFeatures {
|
||||
cursor_grab: bool,
|
||||
xdg_activation: bool,
|
||||
}
|
||||
|
||||
impl WindowingFeatures {
|
||||
/// Create `WindowingFeatures` based on the presented interfaces.
|
||||
pub fn new(env: &Environment<WinitEnv>) -> Self {
|
||||
let cursor_grab = env.get_global::<ZwpPointerConstraintsV1>().is_some();
|
||||
Self { cursor_grab }
|
||||
let xdg_activation = env.get_global::<XdgActivationV1>().is_some();
|
||||
Self {
|
||||
cursor_grab,
|
||||
xdg_activation,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cursor_grab(&self) -> bool {
|
||||
self.cursor_grab
|
||||
}
|
||||
|
||||
pub fn xdg_activation(&self) -> bool {
|
||||
self.xdg_activation
|
||||
}
|
||||
}
|
||||
|
||||
sctk::environment!(WinitEnv,
|
||||
|
@ -50,6 +60,7 @@ sctk::environment!(WinitEnv,
|
|||
ZwpRelativePointerManagerV1 => relative_pointer_manager,
|
||||
ZwpPointerConstraintsV1 => pointer_constraints,
|
||||
ZwpTextInputManagerV3 => text_input_manager,
|
||||
XdgActivationV1 => xdg_activation,
|
||||
],
|
||||
multis = [
|
||||
WlSeat => seats,
|
||||
|
@ -78,6 +89,8 @@ pub struct WinitEnv {
|
|||
text_input_manager: SimpleGlobal<ZwpTextInputManagerV3>,
|
||||
|
||||
decoration_manager: SimpleGlobal<ZxdgDecorationManagerV1>,
|
||||
|
||||
xdg_activation: SimpleGlobal<XdgActivationV1>,
|
||||
}
|
||||
|
||||
impl WinitEnv {
|
||||
|
@ -109,6 +122,9 @@ impl WinitEnv {
|
|||
// IME handling.
|
||||
let text_input_manager = SimpleGlobal::new();
|
||||
|
||||
// Surface activation.
|
||||
let xdg_activation = SimpleGlobal::new();
|
||||
|
||||
Self {
|
||||
seats,
|
||||
outputs,
|
||||
|
@ -120,6 +136,7 @@ impl WinitEnv {
|
|||
relative_pointer_manager,
|
||||
pointer_constraints,
|
||||
text_input_manager,
|
||||
xdg_activation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::platform_impl::{
|
|||
MonitorHandle as PlatformMonitorHandle, OsError,
|
||||
PlatformSpecificWindowBuilderAttributes as PlatformAttributes,
|
||||
};
|
||||
use crate::window::{CursorIcon, Fullscreen, WindowAttributes};
|
||||
use crate::window::{CursorIcon, Fullscreen, UserAttentionType, WindowAttributes};
|
||||
|
||||
use super::env::WindowingFeatures;
|
||||
use super::event_loop::WinitState;
|
||||
|
@ -197,7 +197,12 @@ impl Window {
|
|||
let window_requests = Arc::new(Mutex::new(Vec::with_capacity(64)));
|
||||
|
||||
// Create a handle that performs all the requests on underlying sctk a window.
|
||||
let window_handle = WindowHandle::new(window, size.clone(), window_requests.clone());
|
||||
let window_handle = WindowHandle::new(
|
||||
&event_loop_window_target.env,
|
||||
window,
|
||||
size.clone(),
|
||||
window_requests.clone(),
|
||||
);
|
||||
|
||||
let mut winit_state = event_loop_window_target.state.borrow_mut();
|
||||
|
||||
|
@ -251,9 +256,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn set_title(&self, title: &str) {
|
||||
let title_request = WindowRequest::Title(title.to_owned());
|
||||
self.window_requests.lock().unwrap().push(title_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::Title(title.to_owned()));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -285,9 +288,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn request_redraw(&self) {
|
||||
let redraw_request = WindowRequest::Redraw;
|
||||
self.window_requests.lock().unwrap().push(redraw_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::Redraw);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -305,12 +306,7 @@ impl Window {
|
|||
let size = size.to_logical::<u32>(scale_factor);
|
||||
*self.size.lock().unwrap() = size;
|
||||
|
||||
let frame_size_request = WindowRequest::FrameSize(size);
|
||||
self.window_requests
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(frame_size_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::FrameSize(size));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -318,9 +314,7 @@ impl Window {
|
|||
let scale_factor = self.scale_factor() as f64;
|
||||
let size = dimensions.map(|size| size.to_logical::<u32>(scale_factor));
|
||||
|
||||
let min_size_request = WindowRequest::MinSize(size);
|
||||
self.window_requests.lock().unwrap().push(min_size_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::MinSize(size));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -328,19 +322,12 @@ impl Window {
|
|||
let scale_factor = self.scale_factor() as f64;
|
||||
let size = dimensions.map(|size| size.to_logical::<u32>(scale_factor));
|
||||
|
||||
let max_size_request = WindowRequest::MaxSize(size);
|
||||
self.window_requests.lock().unwrap().push(max_size_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::MaxSize(size));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_resizable(&self, resizable: bool) {
|
||||
let resizeable_request = WindowRequest::Resizeable(resizable);
|
||||
self.window_requests
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(resizeable_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::Resizeable(resizable));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -352,9 +339,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn set_decorations(&self, decorate: bool) {
|
||||
let decorate_request = WindowRequest::Decorate(decorate);
|
||||
self.window_requests.lock().unwrap().push(decorate_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::Decorate(decorate));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -364,9 +349,7 @@ impl Window {
|
|||
return;
|
||||
}
|
||||
|
||||
let minimize_request = WindowRequest::Minimize;
|
||||
self.window_requests.lock().unwrap().push(minimize_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::Minimize);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -376,9 +359,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, maximized: bool) {
|
||||
let maximize_request = WindowRequest::Maximize(maximized);
|
||||
self.window_requests.lock().unwrap().push(maximize_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::Maximize(maximized));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -414,31 +395,17 @@ impl Window {
|
|||
None => WindowRequest::UnsetFullscreen,
|
||||
};
|
||||
|
||||
self.window_requests
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(fullscreen_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(fullscreen_request);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
||||
let cursor_icon_request = WindowRequest::NewCursorIcon(cursor);
|
||||
self.window_requests
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(cursor_icon_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::NewCursorIcon(cursor));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_visible(&self, visible: bool) {
|
||||
let cursor_visible_request = WindowRequest::ShowCursor(visible);
|
||||
self.window_requests
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(cursor_visible_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::ShowCursor(visible));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -447,16 +414,20 @@ impl Window {
|
|||
return Err(ExternalError::NotSupported(NotSupportedError::new()));
|
||||
}
|
||||
|
||||
let cursor_grab_request = WindowRequest::GrabCursor(grab);
|
||||
self.window_requests
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(cursor_grab_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::GrabCursor(grab));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
if !self.windowing_features.xdg_activation() {
|
||||
warn!("`request_user_attention` isn't supported");
|
||||
return;
|
||||
}
|
||||
|
||||
self.send_request(WindowRequest::Attention(request_type));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_position(&self, _: Position) -> Result<(), ExternalError> {
|
||||
// XXX This is possible if the locked pointer is being used. We don't have any
|
||||
|
@ -471,12 +442,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
||||
let drag_window_request = WindowRequest::DragWindow;
|
||||
self.window_requests
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(drag_window_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::DragWindow);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -485,12 +451,7 @@ impl Window {
|
|||
pub fn set_ime_position(&self, position: Position) {
|
||||
let scale_factor = self.scale_factor() as f64;
|
||||
let position = position.to_logical(scale_factor);
|
||||
let ime_position_request = WindowRequest::IMEPosition(position);
|
||||
self.window_requests
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(ime_position_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::IMEPosition(position));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -530,12 +491,16 @@ impl Window {
|
|||
..WaylandHandle::empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn send_request(&self, request: WindowRequest) {
|
||||
self.window_requests.lock().unwrap().push(request);
|
||||
self.event_loop_awakener.ping();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
fn drop(&mut self) {
|
||||
let close_request = WindowRequest::Close;
|
||||
self.window_requests.lock().unwrap().push(close_request);
|
||||
self.event_loop_awakener.ping();
|
||||
self.send_request(WindowRequest::Close);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,23 @@ use std::cell::Cell;
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use sctk::reexports::client::protocol::wl_output::WlOutput;
|
||||
use sctk::reexports::client::Attached;
|
||||
use sctk::reexports::protocols::staging::xdg_activation::v1::client::xdg_activation_token_v1;
|
||||
use sctk::reexports::protocols::staging::xdg_activation::v1::client::xdg_activation_v1::XdgActivationV1;
|
||||
|
||||
use sctk::environment::Environment;
|
||||
use sctk::window::{Decorations, FallbackFrame, Window};
|
||||
|
||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
||||
|
||||
use crate::event::WindowEvent;
|
||||
use crate::platform_impl::wayland;
|
||||
use crate::platform_impl::wayland::env::WinitEnv;
|
||||
use crate::platform_impl::wayland::event_loop::WinitState;
|
||||
use crate::platform_impl::wayland::seat::pointer::WinitPointer;
|
||||
use crate::platform_impl::wayland::seat::text_input::TextInputHandler;
|
||||
use crate::platform_impl::wayland::WindowId;
|
||||
use crate::window::CursorIcon;
|
||||
use crate::window::{CursorIcon, UserAttentionType};
|
||||
|
||||
/// A request to SCTK window from Winit window.
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -64,6 +70,11 @@ pub enum WindowRequest {
|
|||
/// Set IME window position.
|
||||
IMEPosition(LogicalPosition<u32>),
|
||||
|
||||
/// Request Attention.
|
||||
///
|
||||
/// `None` unsets the attention request.
|
||||
Attention(Option<UserAttentionType>),
|
||||
|
||||
/// Redraw was requested.
|
||||
Redraw,
|
||||
|
||||
|
@ -150,14 +161,23 @@ pub struct WindowHandle {
|
|||
|
||||
/// Text inputs on the current surface.
|
||||
text_inputs: Vec<TextInputHandler>,
|
||||
|
||||
/// XdgActivation object.
|
||||
xdg_activation: Option<Attached<XdgActivationV1>>,
|
||||
|
||||
/// Indicator whether user attention is requested.
|
||||
attention_requested: Cell<bool>,
|
||||
}
|
||||
|
||||
impl WindowHandle {
|
||||
pub fn new(
|
||||
env: &Environment<WinitEnv>,
|
||||
window: Window<FallbackFrame>,
|
||||
size: Arc<Mutex<LogicalSize<u32>>>,
|
||||
pending_window_requests: Arc<Mutex<Vec<WindowRequest>>>,
|
||||
) -> Self {
|
||||
let xdg_activation = env.get_global::<XdgActivationV1>();
|
||||
|
||||
Self {
|
||||
window,
|
||||
size,
|
||||
|
@ -167,6 +187,8 @@ impl WindowHandle {
|
|||
cursor_visible: Cell::new(true),
|
||||
pointers: Vec::new(),
|
||||
text_inputs: Vec::new(),
|
||||
xdg_activation,
|
||||
attention_requested: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,6 +210,48 @@ impl WindowHandle {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
let xdg_activation = match self.xdg_activation.as_ref() {
|
||||
None => return,
|
||||
Some(xdg_activation) => xdg_activation,
|
||||
};
|
||||
|
||||
// Urgency is only removed by the compositor and there's no need to raise urgency when it
|
||||
// was already raised.
|
||||
if request_type.is_none() || self.attention_requested.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
let xdg_activation_token = xdg_activation.get_activation_token();
|
||||
let surface = self.window.surface();
|
||||
let window_id = wayland::make_wid(surface);
|
||||
let xdg_activation = xdg_activation.clone();
|
||||
|
||||
xdg_activation_token.quick_assign(move |xdg_token, event, mut dispatch_data| {
|
||||
let token = match event {
|
||||
xdg_activation_token_v1::Event::Done { token } => token,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let winit_state = dispatch_data.get::<WinitState>().unwrap();
|
||||
let window_handle = match winit_state.window_map.get_mut(&window_id) {
|
||||
Some(window_handle) => window_handle,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let surface = window_handle.window.surface();
|
||||
xdg_activation.activate(token, surface);
|
||||
|
||||
// Mark that attention request was done and drop the token.
|
||||
window_handle.attention_requested.replace(false);
|
||||
xdg_token.destroy();
|
||||
});
|
||||
|
||||
xdg_activation_token.set_surface(surface);
|
||||
xdg_activation_token.commit();
|
||||
self.attention_requested.replace(true);
|
||||
}
|
||||
|
||||
/// Pointer appeared over the window.
|
||||
pub fn pointer_entered(&mut self, pointer: WinitPointer) {
|
||||
let position = self.pointers.iter().position(|p| *p == pointer);
|
||||
|
@ -361,6 +425,9 @@ pub fn handle_window_requests(winit_state: &mut WinitState) {
|
|||
let window_update = window_updates.get_mut(window_id).unwrap();
|
||||
window_update.refresh_frame = true;
|
||||
}
|
||||
WindowRequest::Attention(request_type) => {
|
||||
window_handle.set_user_attention(request_type);
|
||||
}
|
||||
WindowRequest::Redraw => {
|
||||
let window_update = window_updates.get_mut(window_id).unwrap();
|
||||
window_update.redraw_requested = true;
|
||||
|
|
|
@ -755,9 +755,10 @@ impl Window {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Web / Wayland:** Unsupported.
|
||||
/// - **iOS / Android / Web :** Unsupported.
|
||||
/// - **macOS:** `None` has no effect.
|
||||
/// - **X11:** Requests for user attention must be manually cleared.
|
||||
/// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.
|
||||
#[inline]
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
self.window.request_user_attention(request_type)
|
||||
|
|
Loading…
Add table
Reference in a new issue