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 27, 2023
1 parent d0f3b08 commit 4b9cf87
Show file tree
Hide file tree
Showing 14 changed files with 479 additions and 4 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),
}
17 changes: 17 additions & 0 deletions core/src/event/wayland/session_lock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::window::Id;
use sctk::reexports::client::protocol::wl_surface::WlSurface;

/// 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,
/// Session lock surface focused
Focused(WlSurface, Id),
/// Session lock surface unfocused
Unfocused(WlSurface, Id),
}
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"
101 changes: 101 additions & 0 deletions examples/sctk_session_lock/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use iced::wayland::session_lock;
use iced::{
event::wayland::{Event as WaylandEvent, OutputEvent, SessionLockEvent},
subscription,
wayland::InitialSurface,
widget::{column, container, text},
window, Application, Color, Command, Element, Length, Subscription, Theme,
};
use iced_runtime::window::Id as SurfaceId;

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

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

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

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

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

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

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

fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
match message {
Message::WaylandEvent(evt) => {
match evt {
// TODO handle creation/removal after lock
WaylandEvent::Output(evt, output) => match evt {
OutputEvent::Created(_) => {
return session_lock::get_lock_surface(
self.next_surface_id(),
output,
);
}
OutputEvent::Removed => {}
_ => {}
},
WaylandEvent::SessionLock(evt) => match evt {
SessionLockEvent::Locked => {}
_ => {} // TODO
},
_ => {}
}
}
Message::Ignore => {}
}
Command::none()
}

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

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()
}
}
}
}
83 changes: 83 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,83 @@
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>,
},
/// Destroy lock surface
DestroyLockSurface {
/// unique id for surface

Check failure on line 26 in runtime/src/command/platform_specific/wayland/session_lock.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/runtime/src/command/platform_specific/wayland/session_lock.rs

Check failure on line 26 in runtime/src/command/platform_specific/wayland/session_lock.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/runtime/src/command/platform_specific/wayland/session_lock.rs
id: Id,
},

}

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,

Check failure on line 50 in runtime/src/command/platform_specific/wayland/session_lock.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/runtime/src/command/platform_specific/wayland/session_lock.rs

Check failure on line 50 in runtime/src/command/platform_specific/wayland/session_lock.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/runtime/src/command/platform_specific/wayland/session_lock.rs
_phantom: PhantomData,
},
Action::DestroyLockSurface {
id
} => Action::DestroyLockSurface { id }
}
}
}

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::LockSurface {{ id: {:?}, output: {:?} }}",

Check failure on line 71 in runtime/src/command/platform_specific/wayland/session_lock.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/runtime/src/command/platform_specific/wayland/session_lock.rs

Check failure on line 71 in runtime/src/command/platform_specific/wayland/session_lock.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/runtime/src/command/platform_specific/wayland/session_lock.rs
id, output
),
Action::DestroyLockSurface {
id
} => write!(
f,
"Action::SessionLock::DestroyLockSurface {{ id: {:?} }}",
id
),
}
}
}
51 changes: 50 additions & 1 deletion 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,42 @@ where
}
})
}
SctkEvent::SessionLockSurfaceConfigure { id, configure } => {
let wl_surface = &id;
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,
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 +937,8 @@ where
SctkEvent::NewOutput { .. }
| SctkEvent::UpdateOutput { .. }
| SctkEvent::RemovedOutput(_)
| SctkEvent::SessionLocked
| SctkEvent::SessionLockFinished
);
if remove {
let event = sctk_events.remove(i);
Expand Down Expand Up @@ -1229,7 +1269,7 @@ where
// Otherwise cpu goes up in the running application as well as in cosmic-comp
if let Some(surface) = state.frame.take() {
surface.frame(&queue_handle, surface.clone());
surface.commit();
//surface.commit();
}

debug.render_started();
Expand Down Expand Up @@ -1442,6 +1482,7 @@ pub enum SurfaceIdWrapper {
Window(SurfaceId),
Popup(SurfaceId),
Dnd(SurfaceId),
SessionLock(SurfaceId),
}

impl SurfaceIdWrapper {
Expand All @@ -1451,6 +1492,7 @@ impl SurfaceIdWrapper {
SurfaceIdWrapper::Window(id) => *id,
SurfaceIdWrapper::Popup(id) => *id,
SurfaceIdWrapper::Dnd(id) => *id,
SurfaceIdWrapper::SessionLock(id) => *id,
}
}
}
Expand Down Expand Up @@ -1525,6 +1567,7 @@ where
);
}
SurfaceIdWrapper::Dnd(_) => {}
SurfaceIdWrapper::SessionLock(_) => {}
};
}

Expand Down Expand Up @@ -2063,6 +2106,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 +2182,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;
Loading

0 comments on commit 4b9cf87

Please sign in to comment.