Skip to content

Commit

Permalink
On Wayland, implement 'request_user_attention'
Browse files Browse the repository at this point in the history
This commit implements 'request_user_attention' on Wayland with
new 'xdg_activation_v1' protocol.
  • Loading branch information
kchibisov authored Aug 17, 2021
1 parent c9520de commit b5d0d6f
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 81 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down Expand Up @@ -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 }
Expand Down
6 changes: 3 additions & 3 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}

Expand Down
19 changes: 18 additions & 1 deletion src/platform_impl/linux/wayland/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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,
Expand All @@ -50,6 +60,7 @@ sctk::environment!(WinitEnv,
ZwpRelativePointerManagerV1 => relative_pointer_manager,
ZwpPointerConstraintsV1 => pointer_constraints,
ZwpTextInputManagerV3 => text_input_manager,
XdgActivationV1 => xdg_activation,
],
multis = [
WlSeat => seats,
Expand Down Expand Up @@ -78,6 +89,8 @@ pub struct WinitEnv {
text_input_manager: SimpleGlobal<ZwpTextInputManagerV3>,

decoration_manager: SimpleGlobal<ZxdgDecorationManagerV1>,

xdg_activation: SimpleGlobal<XdgActivationV1>,
}

impl WinitEnv {
Expand Down Expand Up @@ -109,6 +122,9 @@ impl WinitEnv {
// IME handling.
let text_input_manager = SimpleGlobal::new();

// Surface activation.
let xdg_activation = SimpleGlobal::new();

Self {
seats,
outputs,
Expand All @@ -120,6 +136,7 @@ impl WinitEnv {
relative_pointer_manager,
pointer_constraints,
text_input_manager,
xdg_activation,
}
}
}
Expand Down
111 changes: 38 additions & 73 deletions src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand All @@ -305,42 +306,28 @@ 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]
pub fn set_min_inner_size(&self, dimensions: Option<Size>) {
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]
pub fn set_max_inner_size(&self, dimensions: Option<Size>) {
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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand Down Expand Up @@ -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]
Expand All @@ -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
Expand All @@ -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(())
}
Expand All @@ -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]
Expand Down Expand Up @@ -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);
}
}
Loading

0 comments on commit b5d0d6f

Please sign in to comment.