Add platform::startup_notify for Wayland/X11
The utils in this module should help the users to activate the windows they create, as well as manage activation tokens environment variables. The API is essential for Wayland in the first place, since some compositors may decide initial focus of the window based on whether the activation token was during the window creation. Fixes #2279. Co-authored-by: John Nunley <jtnunley01@gmail.com>
This commit is contained in:
parent
89aa7cc06e
commit
f7a84a5b50
17 changed files with 771 additions and 35 deletions
|
|
@ -16,7 +16,10 @@ use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_v1::
|
|||
|
||||
use sctk::globals::GlobalData;
|
||||
|
||||
use crate::event_loop::AsyncRequestSerial;
|
||||
use crate::platform_impl::wayland::state::WinitState;
|
||||
use crate::platform_impl::WindowId;
|
||||
use crate::window::ActivationToken;
|
||||
|
||||
pub struct XdgActivationState {
|
||||
xdg_activation: XdgActivationV1,
|
||||
|
|
@ -62,16 +65,29 @@ impl Dispatch<XdgActivationTokenV1, XdgActivationTokenData, WinitState> for XdgA
|
|||
_ => return,
|
||||
};
|
||||
|
||||
state
|
||||
let global = state
|
||||
.xdg_activation
|
||||
.as_ref()
|
||||
.expect("got xdg_activation event without global.")
|
||||
.global()
|
||||
.activate(token, &data.surface);
|
||||
.global();
|
||||
|
||||
// Mark that no request attention is in process.
|
||||
if let Some(attention_requested) = data.attention_requested.upgrade() {
|
||||
attention_requested.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||
match data {
|
||||
XdgActivationTokenData::Attention((surface, fence)) => {
|
||||
global.activate(token, surface);
|
||||
// Mark that no request attention is in process.
|
||||
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 {
|
||||
serial: *serial,
|
||||
token: ActivationToken::_new(token),
|
||||
},
|
||||
*window_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
proxy.destroy();
|
||||
|
|
@ -79,24 +95,11 @@ impl Dispatch<XdgActivationTokenV1, XdgActivationTokenData, WinitState> for XdgA
|
|||
}
|
||||
|
||||
/// The data associated with the activation request.
|
||||
pub struct XdgActivationTokenData {
|
||||
/// The surface we're raising.
|
||||
surface: WlSurface,
|
||||
|
||||
/// Flag to throttle attention requests.
|
||||
attention_requested: Weak<AtomicBool>,
|
||||
}
|
||||
|
||||
impl XdgActivationTokenData {
|
||||
/// Create a new data.
|
||||
///
|
||||
/// The `attenteion_requested` is marked as `false` on complition.
|
||||
pub fn new(surface: WlSurface, attention_requested: Weak<AtomicBool>) -> Self {
|
||||
Self {
|
||||
surface,
|
||||
attention_requested,
|
||||
}
|
||||
}
|
||||
pub enum XdgActivationTokenData {
|
||||
/// Request user attention for the given surface.
|
||||
Attention((WlSurface, Weak<AtomicBool>)),
|
||||
/// Get a token to be passed outside of the winit.
|
||||
Obtain((WindowId, AsyncRequestSerial)),
|
||||
}
|
||||
|
||||
delegate_dispatch!(WinitState: [ XdgActivationV1: GlobalData] => XdgActivationState);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use sctk::shell::WaylandSurface;
|
|||
use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
||||
use crate::event::{Ime, WindowEvent};
|
||||
use crate::event_loop::AsyncRequestSerial;
|
||||
use crate::platform_impl::{
|
||||
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError,
|
||||
PlatformSpecificWindowBuilderAttributes as PlatformAttributes,
|
||||
|
|
@ -168,6 +169,14 @@ impl Window {
|
|||
_ => (),
|
||||
};
|
||||
|
||||
// Activate the window when the token is passed.
|
||||
if let (Some(xdg_activation), Some(token)) = (
|
||||
xdg_activation.as_ref(),
|
||||
platform_attributes.activation_token,
|
||||
) {
|
||||
xdg_activation.activate(token._token, &surface);
|
||||
}
|
||||
|
||||
// XXX Do initial commit.
|
||||
window.commit();
|
||||
|
||||
|
|
@ -496,13 +505,31 @@ impl Window {
|
|||
|
||||
self.attention_requested.store(true, Ordering::Relaxed);
|
||||
let surface = self.surface().clone();
|
||||
let data =
|
||||
XdgActivationTokenData::new(surface.clone(), Arc::downgrade(&self.attention_requested));
|
||||
let data = XdgActivationTokenData::Attention((
|
||||
surface.clone(),
|
||||
Arc::downgrade(&self.attention_requested),
|
||||
));
|
||||
let xdg_activation_token = xdg_activation.get_activation_token(&self.queue_handle, data);
|
||||
xdg_activation_token.set_surface(&surface);
|
||||
xdg_activation_token.commit();
|
||||
}
|
||||
|
||||
pub fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError> {
|
||||
let xdg_activation = match self.xdg_activation.as_ref() {
|
||||
Some(xdg_activation) => xdg_activation,
|
||||
None => return Err(NotSupportedError::new()),
|
||||
};
|
||||
|
||||
let serial = AsyncRequestSerial::get();
|
||||
|
||||
let data = XdgActivationTokenData::Obtain((self.window_id, serial));
|
||||
let xdg_activation_token = xdg_activation.get_activation_token(&self.queue_handle, data);
|
||||
xdg_activation_token.set_surface(self.surface());
|
||||
xdg_activation_token.commit();
|
||||
|
||||
Ok(serial)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
||||
self.window_state.lock().unwrap().set_cursor_grab(mode)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue