Skip to content

Commit

Permalink
sctk: WIP session lock surface support
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 committed Oct 20, 2023
1 parent ea61623 commit 218146d
Show file tree
Hide file tree
Showing 14 changed files with 400 additions and 0 deletions.
4 changes: 4 additions & 0 deletions core/src/event/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod layer;
mod output;
mod popup;
mod seat;
mod session_lock;
mod window;

use crate::{time::Instant, window::Id};
Expand All @@ -15,6 +16,7 @@ pub use layer::*;
pub use output::*;
pub use popup::*;
pub use seat::*;
pub use session_lock::*;
pub use window::*;

/// wayland events
Expand All @@ -36,6 +38,8 @@ pub enum Event {
DndOffer(DndOfferEvent),
/// Selection Offer events
SelectionOffer(SelectionOfferEvent),
/// Session lock events
SessionLock(SessionLockEvent),
/// Frame events
Frame(Instant, WlSurface, Id),
}
10 changes: 10 additions & 0 deletions core/src/event/wayland/session_lock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// session lock events
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SessionLockEvent {
/// Compositor has activated lock
Locked,
/// Lock rejected / canceled by compositor
Finished,
/// Session lock protocol not supported
NotSupported,
}
10 changes: 10 additions & 0 deletions examples/sctk_session_lock/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "sctk_session_lock"
version = "0.1.0"
edition = "2021"

[dependencies]
sctk = { package = "smithay-client-toolkit", git = "https://github.com/smithay/client-toolkit", rev = "828b1eb" }
iced = { path = "../..", default-features = false, features = ["wayland", "debug", "a11y"] }
iced_runtime = { path = "../../runtime" }
env_logger = "0.10"
99 changes: 99 additions & 0 deletions examples/sctk_session_lock/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use iced::{

Check failure on line 1 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs

Check failure on line 1 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs
event::wayland::{Event as WaylandEvent, OutputEvent, SessionLockEvent},
subscription,
wayland::InitialSurface,
widget::{column, container, text},

Check failure on line 5 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs

Check failure on line 5 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs
window, Application, Color, Command, Element, Length, Subscription, Theme,
};
use iced_runtime::{
window::Id as SurfaceId,
};
use iced::wayland::session_lock;

fn main() {
let mut settings = iced::Settings::default();
settings.initial_surface = InitialSurface::None;
DndTest::run(settings).unwrap();
}

#[derive(Debug, Clone, Default)]
struct DndTest {
max_surface_id: u128,
}

#[derive(Debug, Clone)]
pub enum Message {
WaylandEvent(WaylandEvent),
Ignore,
}

impl DndTest {
fn next_surface_id(&mut self) -> SurfaceId {
self.max_surface_id += 1;
SurfaceId(self.max_surface_id)
}
}

impl Application for DndTest {
type Executor = iced::executor::Default;
type Message = Message;
type Flags = ();
type Theme = Theme;

fn new(_flags: ()) -> (DndTest, Command<Self::Message>) {
(
DndTest {
..DndTest::default()
},
session_lock::lock(),
)
}

fn title(&self) -> String {
String::from("DndTest")
}

fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
match message {
Message::WaylandEvent(evt) => {
match evt {
// TODO handle creation/removal after lock

Check failure on line 60 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs

Check failure on line 60 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs
WaylandEvent::Output(evt, output) => match evt {
OutputEvent::Created(_) => {
return session_lock::get_lock_surface(self.next_surface_id(), output);
}
OutputEvent::Removed => {}
_ => {}
}

Check failure on line 67 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs

Check failure on line 67 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs
WaylandEvent::SessionLock(evt) => match evt {
SessionLockEvent::Locked => {
}
_ => {} // TODO
}
_ => {}
}
}
Message::Ignore => {}
}
Command::none()
}

fn view(&self, id: window::Id) -> Element<Self::Message> {
text("Lock").into()
}

Check failure on line 84 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs

Check failure on line 84 in examples/sctk_session_lock/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/sctk_session_lock/src/main.rs
fn subscription(&self) -> Subscription<Self::Message> {
iced::subscription::events_with(|evt, _| {
if let iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland(evt)) = evt
{
Some(Message::WaylandEvent(evt))
} else {
None
}
})
}

fn close_requested(&self, _id: window::Id) -> Self::Message {
Message::Ignore
}
}
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 @@ -8,6 +8,8 @@ pub mod data_device;
pub mod layer_surface;
/// popup actions
pub mod popup;
/// session locks
pub mod session_lock;
/// window actions
pub mod window;

Expand All @@ -21,6 +23,8 @@ pub enum Action<T> {
Popup(popup::Action<T>),
/// data device
DataDevice(data_device::Action<T>),
/// session lock
SessionLock(session_lock::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::SessionLock(a) => Action::SessionLock(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::SessionLock(arg0) => {
f.debug_tuple("SessionLock").field(arg0).finish()
}
}
}
}
67 changes: 67 additions & 0 deletions runtime/src/command/platform_specific/wayland/session_lock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::{fmt, marker::PhantomData};

use iced_core::window::Id;
use iced_futures::MaybeSend;

use sctk::reexports::client::protocol::wl_output::WlOutput;

/// Session lock action
#[derive(Clone)]
pub enum Action<T> {
/// Request a session lock
Lock,
/// Destroy lock
Unlock,
/// Create lock surface for output
LockSurface {
/// unique id for surface
id: Id,
/// output
output: WlOutput,
/// phantom
_phantom: PhantomData<T>,
},
}

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::Lock => Action::Lock,
Action::Unlock => Action::Unlock,
Action::LockSurface {
id,
output,
_phantom,
} => Action::LockSurface {
id,
output,
_phantom: PhantomData,
},
}
}
}

impl<T> fmt::Debug for Action<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Action::Lock => write!(f, "Action::SessionLock::Lock"),
Action::Unlock => write!(f, "Action::SessionLock::Unlock"),
Action::LockSurface {
id,
output,
_phantom,
} => write!(
f,
"Action::SessionLock::Unlock {{ id: {:?}, output: {:?} }}",
id, output
),
}
}
}
47 changes: 47 additions & 0 deletions sctk/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,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>),
/// data session lock requests from the client
SessionLock(platform_specific::wayland::session_lock::Action<Message>),
/// request sctk to set the cursor of the active pointer
SetCursor(Interaction),
/// Application Message
Expand Down Expand Up @@ -768,6 +770,43 @@ where
}
})
}
SctkEvent::SessionLockSurfaceConfigure { id, configure } => {
let wl_surface = &id; // XXX avoid duplication elsewhere?
if let Some(id) = surface_ids.get(&id.id()) {
compositor_surfaces.entry(id.inner()).or_insert_with(|| {
let mut wrapper = SurfaceDisplayWrapper {
comp_surface: None,
backend: backend.clone(),
wl_surface: wl_surface.clone()
};
let c_surface = compositor.create_surface(&wrapper, configure.new_size.0, configure.new_size.1);
wrapper.comp_surface.replace(c_surface);
wrapper
});

let Some(state) = states.get_mut(&id.inner()) else {
continue;
};

// XXX if first configure
let user_interface = build_user_interface(
&application,
user_interface::Cache::default(),
&mut renderer,
// XXX state.logical_size
state.logical_size(),
&state.title,
&mut debug,
*id,
&mut auto_size_surfaces,
&mut ev_proxy
);
interfaces.insert(id.inner(), user_interface);

state.set_logical_size(configure.new_size.0 as f64 , configure.new_size.1 as f64);
}

}
_ => {}
}
}
Expand Down Expand Up @@ -899,6 +938,8 @@ where
SctkEvent::NewOutput { .. }
| SctkEvent::UpdateOutput { .. }
| SctkEvent::RemovedOutput(_)
| SctkEvent::SessionLocked
| SctkEvent::SessionLockFinished
);
if remove {
let event = sctk_events.remove(i);
Expand Down Expand Up @@ -2063,6 +2104,9 @@ 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::SessionLock(session_lock_action))) => {
proxy.send_event(Event::SessionLock(session_lock_action));
}
_ => {}
};
None
Expand Down Expand Up @@ -2136,5 +2180,8 @@ fn event_is_for_surface(
SctkEvent::DndOffer { surface, .. } => &surface.id() == object_id,
SctkEvent::SelectionOffer(_) => true,
SctkEvent::DataSource(_) => true,
SctkEvent::SessionLocked => false,
SctkEvent::SessionLockFinished => false,
SctkEvent::SessionLockSurfaceConfigure { .. } => false,
}
}
1 change: 1 addition & 0 deletions sctk/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
pub mod data_device;
pub mod layer_surface;
pub mod popup;
pub mod session_lock;
pub mod window;
43 changes: 43 additions & 0 deletions sctk/src/commands/session_lock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use iced_runtime::command::Command;
use iced_runtime::command::{
self,
platform_specific::{
self,
wayland::{self, popup::SctkPopupSettings},
},
};
use iced_runtime::window::Id as SurfaceId;
use sctk::reexports::client::protocol::wl_output::WlOutput;

use std::marker::PhantomData;

pub fn lock<Message>() -> Command<Message> {
Command::single(command::Action::PlatformSpecific(
platform_specific::Action::Wayland(wayland::Action::SessionLock(
wayland::session_lock::Action::Lock,
)),
))
}

pub fn unlock<Message>() -> Command<Message> {
Command::single(command::Action::PlatformSpecific(
platform_specific::Action::Wayland(wayland::Action::SessionLock(
wayland::session_lock::Action::Unlock,
)),
))
}

pub fn get_lock_surface<Message>(
id: SurfaceId,
output: WlOutput,
) -> Command<Message> {
Command::single(command::Action::PlatformSpecific(
platform_specific::Action::Wayland(wayland::Action::SessionLock(
wayland::session_lock::Action::LockSurface {
id,
output,
_phantom: PhantomData,
},
)),
))
}
Loading

0 comments on commit 218146d

Please sign in to comment.