Skip to content

Commit

Permalink
sctk: Implement xdg-activation support
Browse files Browse the repository at this point in the history
  • Loading branch information
Drakulix committed Nov 1, 2023
1 parent 6d8f942 commit f5a37bb
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 3 deletions.
2 changes: 2 additions & 0 deletions core/src/event/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ pub enum Event {
SelectionOffer(SelectionOfferEvent),
/// Frame events
Frame(Instant, WlSurface, Id),
/// Activation event
ActivationToken(String, Option<Id>),
}
66 changes: 66 additions & 0 deletions runtime/src/command/platform_specific/wayland/activation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use iced_core::window::Id;
use iced_futures::MaybeSend;

use std::{fmt, marker::PhantomData};

/// xdg-activation Actions
#[derive(Clone)]
pub enum Action<T> {
/// request an activation token
RequestToken {
/// application id
app_id: Option<String>,
/// window, if provided
window: Option<Id>,
/// phantom
_phantom: PhantomData<T>,
},
/// request a window to be activated
Activate {
/// window to activate
window: Id,
/// activation token
token: String,
},
}

impl<T> Action<T> {
/// Maps the output of a window [`Action`] using the provided closure.
pub fn map<A>(
self,
_: impl Fn(T) -> A + 'static + MaybeSend + Sync,
) -> Action<A>
where
T: 'static,
{
match self {
Action::RequestToken { app_id, window, .. } => {
Action::RequestToken {
app_id,
window,
_phantom: PhantomData,
}
}
Action::Activate { window, token } => {
Action::Activate { window, token }
}
}
}
}

impl<T> fmt::Debug for Action<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Action::RequestToken { app_id, window, .. } => write!(
f,
"Action::ActivationAction::RequestToken {{ app_id: {:?}, window: {:?} }}",
app_id, window,
),
Action::Activate { window, token } => write!(
f,
"Action::ActivationAction::Activate {{ window: {:?}, token: {:?} }}",
window, token,
)
}
}
}
8 changes: 8 additions & 0 deletions runtime/src/command/platform_specific/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::fmt::Debug;

use iced_futures::MaybeSend;

/// activation Actions
pub mod activation;
/// data device Actions
pub mod data_device;
/// layer surface actions
Expand All @@ -21,6 +23,8 @@ pub enum Action<T> {
Popup(popup::Action<T>),
/// data device
DataDevice(data_device::Action<T>),
/// activation
Activation(activation::Action<T>),
}

impl<T> Action<T> {
Expand All @@ -38,6 +42,7 @@ impl<T> Action<T> {
Action::Window(a) => Action::Window(a.map(f)),
Action::Popup(a) => Action::Popup(a.map(f)),
Action::DataDevice(a) => Action::DataDevice(a.map(f)),
Action::Activation(a) => Action::Activation(a.map(f)),
}
}
}
Expand All @@ -53,6 +58,9 @@ impl<T> Debug for Action<T> {
Self::DataDevice(arg0) => {
f.debug_tuple("DataDevice").field(arg0).finish()
}
Self::Activation(arg0) => {
f.debug_tuple("Activation").field(arg0).finish()
}
}
}
}
16 changes: 14 additions & 2 deletions sctk/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ use sctk::{
seat::{keyboard::Modifiers, pointer::PointerEventKind},
};
use std::{
collections::HashMap, ffi::c_void, hash::Hash, marker::PhantomData,
time::Duration,
collections::HashMap, hash::Hash, marker::PhantomData, time::Duration,
};
use wayland_backend::client::ObjectId;
use wayland_protocols::wp::viewporter::client::wp_viewport::WpViewport;
Expand Down Expand Up @@ -92,6 +91,8 @@ pub enum Event<Message> {
Popup(platform_specific::wayland::popup::Action<Message>),
/// data device requests from the client
DataDevice(platform_specific::wayland::data_device::Action<Message>),
/// xdg-activation request from the client
Activation(platform_specific::wayland::activation::Action<Message>),
/// request sctk to set the cursor of the active pointer
SetCursor(Interaction),
/// Application Message
Expand Down Expand Up @@ -2063,6 +2064,13 @@ where
command::Action::PlatformSpecific(platform_specific::Action::Wayland(platform_specific::wayland::Action::DataDevice(data_device_action))) => {
proxy.send_event(Event::DataDevice(data_device_action));
}
command::Action::PlatformSpecific(
platform_specific::Action::Wayland(
platform_specific::wayland::Action::Activation(activation_action)
)
) => {
proxy.send_event(Event::Activation(activation_action));
}
_ => {}
};
None
Expand Down Expand Up @@ -2136,5 +2144,9 @@ fn event_is_for_surface(
SctkEvent::DndOffer { surface, .. } => &surface.id() == object_id,
SctkEvent::SelectionOffer(_) => true,
SctkEvent::DataSource(_) => true,
SctkEvent::Activation { window, .. } => window
.as_ref()
.map(|w| &w.id() == object_id)
.unwrap_or(true),
}
}
31 changes: 31 additions & 0 deletions sctk/src/commands/activation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use iced_runtime::command::Command;
use iced_runtime::command::{
self,
platform_specific::{self, wayland},
};
use iced_runtime::window::Id as SurfaceId;

use std::marker::PhantomData;

pub fn request_token<Message>(
app_id: Option<String>,
window: Option<SurfaceId>,
) -> Command<Message> {
Command::single(command::Action::PlatformSpecific(
platform_specific::Action::Wayland(wayland::Action::Activation(
wayland::activation::Action::RequestToken {
app_id,
window,
_phantom: PhantomData,
},
)),
))
}

pub fn activate<Message>(window: SurfaceId, token: String) -> Command<Message> {
Command::single(command::Action::PlatformSpecific(
platform_specific::Action::Wayland(wayland::Action::Activation(
wayland::activation::Action::Activate { window, token },
)),
))
}
1 change: 1 addition & 0 deletions sctk/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Interact with the wayland objects of your application.

pub mod activation;
pub mod data_device;
pub mod layer_surface;
pub mod popup;
Expand Down
40 changes: 39 additions & 1 deletion sctk/src/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use iced_runtime::command::platform_specific::{
},
};
use sctk::{
activation::{ActivationState, RequestData},
compositor::CompositorState,
data_device_manager::DataDeviceManagerState,
output::OutputState,
Expand Down Expand Up @@ -179,6 +180,7 @@ where
&globals, &qh,
)
.expect("data device manager is not available"),
activation_state: ActivationState::bind(&globals, &qh).ok(),

queue_handle: qh,
loop_handle,
Expand Down Expand Up @@ -1297,7 +1299,43 @@ where
}
}
}
}
},
Event::Activation(activation_event) => match activation_event {
platform_specific::wayland::activation::Action::RequestToken { app_id, window, _phantom } => {
if let Some(activation_state) = self.state.activation_state.as_ref() {
let (seat_and_serial, surface) = if let Some(id) = window {
let window = self.state.windows.iter().find(|w| w.id == id);
let surface = window.as_ref().map(|w| w.window.wl_surface().clone());
let seat_and_serial = surface.as_ref().and_then(|surface| {
self.state.seats.first().and_then(|seat| if seat.kbd_focus.as_ref().map(|focus| focus == surface).unwrap_or(false) {
seat.last_kbd_press.as_ref().map(|(_, serial)| (seat.seat.clone(), *serial))
} else if seat.ptr_focus.as_ref().map(|focus| focus == surface).unwrap_or(false) {
seat.last_ptr_press.as_ref().map(|(_, _, serial)| (seat.seat.clone(), *serial))
} else {
None
})
});

(seat_and_serial, surface)
} else {
(None, None)
};

activation_state.request_token(&self.state.queue_handle, RequestData {
app_id,
seat_and_serial,
surface,
});
}
},
platform_specific::wayland::activation::Action::Activate { window, token } => {
if let Some(activation_state) = self.state.activation_state.as_ref() {
if let Some(surface) = self.state.windows.iter().find(|w| w.id == window).map(|w| w.window.wl_surface()) {
activation_state.activate::<SctkState<T>>(surface, token)
}
}
},
},
}
}

Expand Down
2 changes: 2 additions & 0 deletions sctk/src/event_loop/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use iced_runtime::{
window,
};
use sctk::{
activation::ActivationState,
compositor::CompositorState,
data_device_manager::{
data_device::DataDevice,
Expand Down Expand Up @@ -329,6 +330,7 @@ pub struct SctkState<T> {
pub(crate) xdg_shell_state: XdgShell,
pub(crate) layer_shell: Option<LayerShell>,
pub(crate) data_device_manager_state: DataDeviceManagerState,
pub(crate) activation_state: Option<ActivationState>,
pub(crate) token_ctr: u32,
}

Expand Down
20 changes: 20 additions & 0 deletions sctk/src/handlers/activation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use sctk::{
activation::{ActivationHandler, RequestData, RequestDataExt},
delegate_activation,
};

use crate::event_loop::state::SctkState;

impl<T> ActivationHandler for SctkState<T> {
type RequestData = RequestData;

fn new_token(&mut self, token: String, data: &Self::RequestData) {
self.sctk_events
.push(crate::sctk_event::SctkEvent::Activation {
token,
window: data.surface().cloned(),
})
}
}

delegate_activation!(@<T> SctkState<T>);
1 change: 1 addition & 0 deletions sctk/src/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// handlers
pub mod activation;
pub mod compositor;
pub mod data_device;
pub mod output;
Expand Down
16 changes: 16 additions & 0 deletions sctk/src/sctk_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ pub enum SctkEvent {
surface: WlSurface,
},
SelectionOffer(SelectionOfferEvent),
Activation {
token: String,
window: Option<WlSurface>,
},
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -956,6 +960,18 @@ impl SctkEvent {
.collect()
}
},
SctkEvent::Activation { token, window } => {
Some(iced_runtime::core::Event::PlatformSpecific(
PlatformSpecific::Wayland(wayland::Event::ActivationToken(
token,
window
.and_then(|w| surface_ids.get(&w.id()))
.map(SurfaceIdWrapper::inner),
)),
))
.into_iter()
.collect()
}
}
}
}

0 comments on commit f5a37bb

Please sign in to comment.