Skip to content

Commit

Permalink
WIP subsurface
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 committed Dec 5, 2023
1 parent 33b2fd9 commit 56b63cc
Show file tree
Hide file tree
Showing 11 changed files with 540 additions and 5 deletions.
13 changes: 13 additions & 0 deletions examples/sctk_subsurface/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "sctk_subsurface"
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" }
iced_sctk = { path = "../../sctk" }
env_logger = "0.10"
futures-channel = "0.3.29"
calloop = "0.12.3"
108 changes: 108 additions & 0 deletions examples/sctk_subsurface/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Shows a subsurface with a 1x1 px red buffer, stretch to window size

use iced::{
event::wayland::Event as WaylandEvent, wayland::InitialSurface,
widget::text, window, Application, Command, Element, Length, Subscription,
Theme,
};
use sctk::reexports::client::{
protocol::wl_buffer::WlBuffer, Connection, Proxy,
};

mod wayland;

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

#[derive(Debug, Clone, Default)]
struct SubsurfaceApp {
connection: Option<Connection>,
red_buffer: Option<WlBuffer>,
}

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

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

fn new(_flags: ()) -> (SubsurfaceApp, Command<Self::Message>) {
(
SubsurfaceApp {
..SubsurfaceApp::default()
},
Command::none(),
)
}

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

fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
match message {
Message::WaylandEvent(evt) => match evt {
WaylandEvent::Output(_evt, output) => {
if self.connection.is_none() {
if let Some(backend) = output.backend().upgrade() {
self.connection =
Some(Connection::from_backend(backend));
}
}
}
_ => {}
},
Message::Wayland(evt) => match evt {
wayland::Event::RedBuffer(buffer) => {
self.red_buffer = Some(buffer);
}
},
Message::Ignore => {}
}
Command::none()
}

fn view(&self, _id: window::Id) -> Element<Self::Message> {
if let Some(buffer) = &self.red_buffer {
iced_sctk::subsurface_widget::Subsurface::new(1, 1, buffer)
.width(Length::Fill)
.height(Length::Fill)
.into()
} else {
text("No subsurface").into()
}
}

fn subscription(&self) -> Subscription<Self::Message> {
let mut subscriptions =
vec![iced::subscription::events_with(|evt, _| {
if let iced::Event::PlatformSpecific(
iced::event::PlatformSpecific::Wayland(evt),
) = evt
{
Some(Message::WaylandEvent(evt))
} else {
None
}
})];
if let Some(connection) = &self.connection {
subscriptions
.push(wayland::subscription(connection).map(Message::Wayland));
}
Subscription::batch(subscriptions)
}

fn close_requested(&self, _id: window::Id) -> Self::Message {
Message::Ignore
}
}
86 changes: 86 additions & 0 deletions examples/sctk_subsurface/src/wayland.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use futures_channel::mpsc;
use iced::futures::{FutureExt, SinkExt};
use sctk::{
reexports::{
calloop_wayland_source::WaylandSource,
client::{
delegate_noop,
globals::registry_queue_init,
protocol::{wl_buffer::WlBuffer, wl_shm},
Connection,
},
},
registry::{ProvidesRegistryState, RegistryState},
shm::{raw::RawPool, Shm, ShmHandler},
};
use std::thread;

#[derive(Debug, Clone)]
pub enum Event {
RedBuffer(WlBuffer),
}

struct AppData {
registry_state: RegistryState,
shm_state: Shm,
}

impl ProvidesRegistryState for AppData {
fn registry(&mut self) -> &mut RegistryState {
&mut self.registry_state
}

sctk::registry_handlers!();
}

impl ShmHandler for AppData {
fn shm_state(&mut self) -> &mut Shm {
&mut self.shm_state
}
}

pub fn subscription(connection: &Connection) -> iced::Subscription<Event> {
let connection = connection.clone();
iced::subscription::run_with_id(
"wayland-sub",
async { start(connection).await }.flatten_stream(),
)
}

async fn start(conn: Connection) -> mpsc::Receiver<Event> {
let (mut sender, receiver) = mpsc::channel(20);

let (globals, event_queue) = registry_queue_init(&conn).unwrap();
let qh = event_queue.handle();

let mut app_data = AppData {
registry_state: RegistryState::new(&globals),
shm_state: Shm::bind(&globals, &qh).unwrap(),
};

let mut pool = RawPool::new(4, &app_data.shm_state).unwrap();
let buffer =
pool.create_buffer(0, 1, 1, 4, wl_shm::Format::Xrgb8888, (), &qh);
let data = pool.mmap();
data[0] = 0;
data[1] = 0;
data[2] = 255;
data[3] = 255;
let _ = sender.send(Event::RedBuffer(buffer)).await;

thread::spawn(move || {
let mut event_loop = calloop::EventLoop::try_new().unwrap();
WaylandSource::new(conn, event_queue)
.insert(event_loop.handle())
.unwrap();
loop {
event_loop.dispatch(None, &mut app_data).unwrap();
}
});

receiver
}

delegate_noop!(AppData: ignore WlBuffer);
sctk::delegate_registry!(AppData);
sctk::delegate_shm!(AppData);
35 changes: 35 additions & 0 deletions sctk/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ use raw_window_handle::{
};
use std::mem::ManuallyDrop;

use crate::subsurface_widget::{SubsurfaceInstance, SubsurfaceState};

pub enum Event<Message> {
/// A normal sctk event
SctkEvent(IcedSctkEvent<Message>),
Expand Down Expand Up @@ -364,6 +366,8 @@ where
let mut interfaces = ManuallyDrop::new(HashMap::new());
let mut simple_clipboard = Clipboard::unconnected();

let mut subsurface_state = None::<SubsurfaceState<A::Message>>;

{
run_command(
&application,
Expand Down Expand Up @@ -1373,6 +1377,11 @@ where
state.viewport_changed = false;
}

// Subsurface list should always be empty before `view`
assert!(
crate::subsurface_widget::take_subsurfaces().is_empty()
);

debug.draw_started();
let new_mouse_interaction = user_interface.draw(
&mut renderer,
Expand All @@ -1385,6 +1394,17 @@ where
state.cursor(),
);

// Update subsurfaces based on what view requested.
let subsurfaces =
crate::subsurface_widget::take_subsurfaces();
if let Some(subsurface_state) = subsurface_state.as_ref() {
subsurface_state.update_subsurfaces(
&wrapper.wl_surface,
&mut state.subsurfaces,
&subsurfaces,
);
}

debug.draw_finished();
if new_mouse_interaction != mouse_interaction {
mouse_interaction = new_mouse_interaction;
Expand Down Expand Up @@ -1481,6 +1501,19 @@ where
}
}
}
IcedSctkEvent::Subcompositor {
compositor,
subcompositor,
viewporter,
qh,
} => {
subsurface_state = Some(SubsurfaceState {
wl_compositor: compositor,
wl_subcompositor: subcompositor,
wp_viewporter: viewporter,
qh,
});
}
}
}

Expand Down Expand Up @@ -1612,6 +1645,7 @@ where
first: bool,
wp_viewport: Option<WpViewport>,
interface_state: user_interface::State,
subsurfaces: Vec<SubsurfaceInstance>,
}

impl<A: Application> State<A>
Expand Down Expand Up @@ -1645,6 +1679,7 @@ where
first: true,
wp_viewport: None,
interface_state: user_interface::State::Outdated,
subsurfaces: Vec::new(),
}
}

Expand Down
38 changes: 38 additions & 0 deletions sctk/src/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use sctk::{
activation::{ActivationState, RequestData},
compositor::CompositorState,
data_device_manager::DataDeviceManagerState,
globals::GlobalData,
output::OutputState,
reexports::{
calloop::{self, EventLoop, PostAction},
Expand Down Expand Up @@ -298,6 +299,43 @@ where
&mut control_flow,
);

// XXX don't re-bind?
let compositor = self
.state
.registry_state
.bind_one(&self.state.queue_handle, 1..=6, GlobalData)
.unwrap();
let subcompositor = self.state.registry_state.bind_one(
&self.state.queue_handle,
1..=1,
GlobalData,
);
let viewporter = self.state.registry_state.bind_one(
&self.state.queue_handle,
1..=1,
GlobalData,
);
if let Ok(subcompositor) = subcompositor {
if let Ok(viewporter) = viewporter {
callback(
IcedSctkEvent::Subcompositor {
compositor,
subcompositor,
viewporter,
qh: self.state.queue_handle.clone(),
},
&self.state,
&mut control_flow,
);
} else {
tracing::warn!(
"No `wp_viewporter`. Subsurfaces not supported."
);
}
} else {
tracing::warn!("No `wl_subcompositor`. Subsurfaces not supported.");
}

let mut sctk_event_sink_back_buffer = Vec::new();
let mut compositor_event_back_buffer = Vec::new();
let mut frame_event_back_buffer = Vec::new();
Expand Down
4 changes: 4 additions & 0 deletions sctk/src/event_loop/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ use sctk::{
reexports::{
calloop::{LoopHandle, RegistrationToken},
client::{
delegate_noop,
protocol::{
wl_keyboard::WlKeyboard,
wl_output::WlOutput,
wl_seat::WlSeat,
wl_subsurface::WlSubsurface,
wl_surface::{self, WlSurface},
wl_touch::WlTouch,
},
Expand Down Expand Up @@ -842,3 +844,5 @@ where
}
}
}

delegate_noop!(@<T: 'static + Debug> SctkState<T>: ignore WlSubsurface);
1 change: 1 addition & 0 deletions sctk/src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod output;
pub mod seat;
pub mod session_lock;
pub mod shell;
pub mod subcompositor;
pub mod wp_fractional_scaling;
pub mod wp_viewporter;

Expand Down
5 changes: 5 additions & 0 deletions sctk/src/handlers/subcompositor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use crate::handlers::SctkState;
use sctk::delegate_subcompositor;
use std::fmt::Debug;

delegate_subcompositor!(@<T: 'static + Debug> SctkState<T>);
1 change: 1 addition & 0 deletions sctk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod handlers;
pub mod result;
pub mod sctk_event;
pub mod settings;
pub mod subsurface_widget;
#[cfg(feature = "system")]
pub mod system;
pub mod util;
Expand Down
Loading

0 comments on commit 56b63cc

Please sign in to comment.