aboutsummaryrefslogtreecommitdiff
path: root/src/state.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.rs')
-rw-r--r--src/state.rs164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/state.rs b/src/state.rs
new file mode 100644
index 00000000..a0405b77
--- /dev/null
+++ b/src/state.rs
@@ -0,0 +1,164 @@
+use std::{ffi::OsString, os::unix::io::AsRawFd, sync::Arc};
+
+use smithay::{
+ desktop::{Space, Window, WindowSurfaceType},
+ input::{pointer::PointerHandle, Seat, SeatState},
+ reexports::{
+ calloop::{generic::Generic, EventLoop, Interest, LoopSignal, Mode, PostAction},
+ wayland_server::{
+ backend::{ClientData, ClientId, DisconnectReason},
+ protocol::wl_surface::WlSurface,
+ Display,
+ },
+ },
+ utils::{Logical, Point},
+ wayland::{
+ compositor::{CompositorClientState, CompositorState},
+ data_device::DataDeviceState,
+ output::OutputManagerState,
+ shell::xdg::XdgShellState,
+ shm::ShmState,
+ socket::ListeningSocketSource,
+ },
+};
+
+use crate::CalloopData;
+
+pub struct Smallvil {
+ pub start_time: std::time::Instant,
+ pub socket_name: OsString,
+
+ pub space: Space<Window>,
+ pub loop_signal: LoopSignal,
+
+ // Smithay State
+ pub compositor_state: CompositorState,
+ pub xdg_shell_state: XdgShellState,
+ pub shm_state: ShmState,
+ pub output_manager_state: OutputManagerState,
+ pub seat_state: SeatState<Smallvil>,
+ pub data_device_state: DataDeviceState,
+
+ pub seat: Seat<Self>,
+}
+
+impl Smallvil {
+ pub fn new(event_loop: &mut EventLoop<CalloopData>, display: &mut Display<Self>) -> Self {
+ let start_time = std::time::Instant::now();
+
+ let dh = display.handle();
+
+ let compositor_state = CompositorState::new::<Self>(&dh);
+ let xdg_shell_state = XdgShellState::new::<Self>(&dh);
+ let shm_state = ShmState::new::<Self>(&dh, vec![]);
+ let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&dh);
+ let mut seat_state = SeatState::new();
+ let data_device_state = DataDeviceState::new::<Self>(&dh);
+
+ // A seat is a group of keyboards, pointer and touch devices.
+ // A seat typically has a pointer and maintains a keyboard focus and a pointer focus.
+ let mut seat: Seat<Self> = seat_state.new_wl_seat(&dh, "winit");
+
+ // Notify clients that we have a keyboard, for the sake of the example we assume that keyboard is always present.
+ // You may want to track keyboard hot-plug in real compositor.
+ seat.add_keyboard(Default::default(), 200, 200).unwrap();
+
+ // Notify clients that we have a pointer (mouse)
+ // Here we assume that there is always pointer plugged in
+ seat.add_pointer();
+
+ // A space represents a two-dimensional plane. Windows and Outputs can be mapped onto it.
+ //
+ // Windows get a position and stacking order through mapping.
+ // Outputs become views of a part of the Space and can be rendered via Space::render_output.
+ let space = Space::default();
+
+ let socket_name = Self::init_wayland_listener(display, event_loop);
+
+ // Get the loop signal, used to stop the event loop
+ let loop_signal = event_loop.get_signal();
+
+ Self {
+ start_time,
+
+ space,
+ loop_signal,
+ socket_name,
+
+ compositor_state,
+ xdg_shell_state,
+ shm_state,
+ output_manager_state,
+ seat_state,
+ data_device_state,
+ seat,
+ }
+ }
+
+ fn init_wayland_listener(
+ display: &mut Display<Smallvil>,
+ event_loop: &mut EventLoop<CalloopData>,
+ ) -> OsString {
+ // Creates a new listening socket, automatically choosing the next available `wayland` socket name.
+ let listening_socket = ListeningSocketSource::new_auto().unwrap();
+
+ // Get the name of the listening socket.
+ // Clients will connect to this socket.
+ let socket_name = listening_socket.socket_name().to_os_string();
+
+ let handle = event_loop.handle();
+
+ event_loop
+ .handle()
+ .insert_source(listening_socket, move |client_stream, _, state| {
+ // Inside the callback, you should insert the client into the display.
+ //
+ // You may also associate some data with the client when inserting the client.
+ state
+ .display
+ .handle()
+ .insert_client(client_stream, Arc::new(ClientState::default()))
+ .unwrap();
+ })
+ .expect("Failed to init the wayland event source.");
+
+ // You also need to add the display itself to the event loop, so that client events will be processed by wayland-server.
+ handle
+ .insert_source(
+ Generic::new(
+ display.backend().poll_fd().as_raw_fd(),
+ Interest::READ,
+ Mode::Level,
+ ),
+ |_, _, state| {
+ state.display.dispatch_clients(&mut state.state).unwrap();
+ Ok(PostAction::Continue)
+ },
+ )
+ .unwrap();
+
+ socket_name
+ }
+
+ pub fn surface_under_pointer(
+ &self,
+ pointer: &PointerHandle<Self>,
+ ) -> Option<(WlSurface, Point<i32, Logical>)> {
+ let pos = pointer.current_location();
+ self.space.element_under(pos).and_then(|(window, location)| {
+ window
+ .surface_under(pos - location.to_f64(), WindowSurfaceType::ALL)
+ .map(|(s, p)| (s, p + location))
+ })
+ }
+}
+
+#[derive(Default)]
+pub struct ClientState {
+ pub compositor_state: CompositorClientState,
+}
+
+impl ClientData for ClientState {
+ fn initialized(&self, _client_id: ClientId) {}
+ fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {}
+}