init commit
This commit is contained in:
commit
ae577cdc2c
8 changed files with 3364 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
2395
Cargo.lock
generated
Normal file
2395
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "milkyway"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.12.5"
|
||||
smithay = { version = "0.7.0", features = ["wayland-backend", "xwayland"] }
|
||||
wayland-protocols = { version = "0.32.13", features = ["wayland-server", "server"] }
|
||||
wayland-server = { version = "0.31.13", features = ["dlopen"] }
|
||||
winit = "0.30.13"
|
||||
43
src/backend/mod.rs
Normal file
43
src/backend/mod.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use ::winit::raw_window_handle::{HasWindowHandle, RawWindowHandle};
|
||||
use smithay::{
|
||||
backend::{
|
||||
renderer::{gles::GlesRenderer, RendererSuper},
|
||||
winit::WinitGraphicsBackend,
|
||||
},
|
||||
reexports::calloop::LoopHandle,
|
||||
utils::{Physical, Size},
|
||||
};
|
||||
|
||||
use crate::state::State;
|
||||
|
||||
pub mod winit;
|
||||
|
||||
pub trait Backend {
|
||||
fn get_fb(
|
||||
&mut self,
|
||||
) -> Result<
|
||||
(
|
||||
&mut GlesRenderer,
|
||||
<GlesRenderer as RendererSuper>::Framebuffer<'_>,
|
||||
),
|
||||
Box<dyn std::error::Error>,
|
||||
>;
|
||||
fn bounds(&self) -> Size<i32, Physical>;
|
||||
}
|
||||
|
||||
impl Backend for WinitGraphicsBackend<GlesRenderer> {
|
||||
fn get_fb(
|
||||
&mut self,
|
||||
) -> Result<
|
||||
(
|
||||
&mut GlesRenderer,
|
||||
<GlesRenderer as RendererSuper>::Framebuffer<'_>,
|
||||
),
|
||||
Box<dyn std::error::Error>,
|
||||
> {
|
||||
return Ok(self.bind()?);
|
||||
}
|
||||
fn bounds(&self) -> Size<i32, Physical> {
|
||||
return self.window_size();
|
||||
}
|
||||
}
|
||||
147
src/backend/winit.rs
Normal file
147
src/backend/winit.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use ::winit::platform::pump_events::PumpStatus;
|
||||
use smithay::backend::input::ButtonState;
|
||||
use smithay::reexports::calloop::EventLoop;
|
||||
use smithay::{
|
||||
backend::{
|
||||
input::{AbsolutePositionEvent, Event, InputEvent, KeyboardKeyEvent, PointerButtonEvent},
|
||||
renderer::gles::GlesRenderer,
|
||||
winit::{self, WinitEvent},
|
||||
},
|
||||
input::keyboard::FilterResult,
|
||||
reexports::wayland_server::Display,
|
||||
utils::{Rectangle, Size},
|
||||
};
|
||||
|
||||
use crate::state::State;
|
||||
|
||||
pub fn run_winit() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut display: Display<State> = Display::new()?;
|
||||
let mut event_loop = EventLoop::try_new()?;
|
||||
|
||||
let mut state = State::new(&display, &event_loop)?;
|
||||
state.setup_xwayland(&display)?;
|
||||
|
||||
let (mut backend, mut winit) = winit::init::<GlesRenderer>()?;
|
||||
|
||||
let keyboard = state
|
||||
.seat
|
||||
.add_keyboard(Default::default(), 600, 25)
|
||||
.unwrap();
|
||||
|
||||
let pointer = state.seat.add_pointer();
|
||||
|
||||
unsafe { std::env::set_var("WAYLAND_DISPLAY", "wayland-5") };
|
||||
std::process::Command::new("weston-terminal").spawn().ok();
|
||||
let damage = Rectangle::from_size(backend.window_size());
|
||||
let mut i = 0;
|
||||
|
||||
loop {
|
||||
let status = winit.dispatch_new_events(|event| match event {
|
||||
WinitEvent::Resized { .. } => {}
|
||||
WinitEvent::Input(event) => match event {
|
||||
InputEvent::Keyboard { event } => {
|
||||
keyboard.input::<(), _>(
|
||||
&mut state,
|
||||
event.key_code(),
|
||||
event.state(),
|
||||
i.into(),
|
||||
event.time_msec(),
|
||||
|_, _, _| {
|
||||
//
|
||||
FilterResult::Forward
|
||||
},
|
||||
);
|
||||
}
|
||||
InputEvent::PointerMotionAbsolute { event } => {
|
||||
let size = backend.window_size();
|
||||
let location = event.position_transformed(Size::new(size.w, size.h));
|
||||
let locationrel = event.position_transformed(Size::new(1, 1));
|
||||
let ev = smithay::input::pointer::MotionEvent {
|
||||
location,
|
||||
serial: i.into(),
|
||||
time: event.time_msec(),
|
||||
};
|
||||
state.motion_event(ev, &pointer, locationrel);
|
||||
}
|
||||
InputEvent::PointerButton { event } => {
|
||||
let ev = smithay::input::pointer::ButtonEvent {
|
||||
serial: i.into(),
|
||||
time: event.time_msec(),
|
||||
button: event.button_code(),
|
||||
state: event.state(),
|
||||
};
|
||||
|
||||
if event.state() == ButtonState::Pressed {
|
||||
if let Some(surface) = state.focused_surface() {
|
||||
{
|
||||
if let Some(ref surface) = surface.surface {
|
||||
keyboard.set_focus(
|
||||
&mut state,
|
||||
Some(surface.wl_surface().clone()),
|
||||
i.into(),
|
||||
);
|
||||
}
|
||||
if let Some(ref surface) = surface.xsurface {
|
||||
keyboard.set_focus(&mut state, surface.wl_surface(), i.into());
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut space = state.space.lock();
|
||||
space.raise_element(&surface, true);
|
||||
}
|
||||
} else {
|
||||
keyboard.set_focus(&mut state, None, i.into());
|
||||
}
|
||||
}
|
||||
|
||||
state.button_event(ev, &pointer);
|
||||
}
|
||||
|
||||
// InputEvent::PointerAxis { event } => todo!(),
|
||||
// InputEvent::DeviceAdded { device } => todo!(),
|
||||
// InputEvent::DeviceRemoved { device } => todo!(),
|
||||
// InputEvent::GestureSwipeBegin { event } => todo!(),
|
||||
// InputEvent::GestureSwipeUpdate { event } => todo!(),
|
||||
// InputEvent::GestureSwipeEnd { event } => todo!(),
|
||||
// InputEvent::GesturePinchBegin { event } => todo!(),
|
||||
// InputEvent::GesturePinchUpdate { event } => todo!(),
|
||||
// InputEvent::GesturePinchEnd { event } => todo!(),
|
||||
// InputEvent::GestureHoldBegin { event } => todo!(),
|
||||
// InputEvent::GestureHoldEnd { event } => todo!(),
|
||||
// InputEvent::TouchDown { event } => todo!(),
|
||||
// InputEvent::TouchMotion { event } => todo!(),
|
||||
// InputEvent::TouchUp { event } => todo!(),
|
||||
// InputEvent::TouchCancel { event } => todo!(),
|
||||
// InputEvent::TouchFrame { event } => todo!(),
|
||||
// InputEvent::TabletToolAxis { event } => todo!(),
|
||||
// InputEvent::TabletToolProximity { event } => todo!(),
|
||||
// InputEvent::TabletToolTip { event } => todo!(),
|
||||
// InputEvent::TabletToolButton { event } => todo!(),
|
||||
// InputEvent::SwitchToggle { event } => todo!(),
|
||||
// InputEvent::Special(_) => todo!(),
|
||||
_ => {}
|
||||
},
|
||||
_ => (),
|
||||
});
|
||||
|
||||
match status {
|
||||
PumpStatus::Continue => (),
|
||||
PumpStatus::Exit(_) => return Ok(()),
|
||||
};
|
||||
|
||||
state.render(&mut backend, &display)?;
|
||||
|
||||
display.dispatch_clients(&mut state)?;
|
||||
display.flush_clients()?;
|
||||
|
||||
// It is important that all events on the display have been dispatched and flushed to clients before
|
||||
// swapping buffers because this operation may block.
|
||||
backend.submit(Some(&[damage]))?;
|
||||
|
||||
event_loop.dispatch(Duration::from_millis(1), &mut state)?;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
9
src/main.rs
Normal file
9
src/main.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
use backend::winit::run_winit;
|
||||
|
||||
pub mod backend;
|
||||
pub mod state;
|
||||
pub mod xwayland;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
run_winit()
|
||||
}
|
||||
624
src/state.rs
Normal file
624
src/state.rs
Normal file
|
|
@ -0,0 +1,624 @@
|
|||
use parking_lot::Mutex;
|
||||
use std::{sync::Arc, time::Instant};
|
||||
|
||||
use smithay::{
|
||||
backend::{renderer::{
|
||||
element::{
|
||||
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
|
||||
AsRenderElements, Kind,
|
||||
},
|
||||
gles::GlesRenderer,
|
||||
utils::{draw_render_elements, on_commit_buffer_handler},
|
||||
Color32F, Frame, Renderer,
|
||||
}, input::ButtonState},
|
||||
delegate_compositor, delegate_data_device, delegate_seat, delegate_shm, delegate_xdg_shell,
|
||||
desktop::{space::SpaceElement, Space, Window},
|
||||
input::{
|
||||
pointer::{
|
||||
AxisFrame, ButtonEvent, Focus, GestureHoldBeginEvent, GestureHoldEndEvent,
|
||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData,
|
||||
MotionEvent, PointerGrab, PointerHandle, PointerInnerHandle, RelativeMotionEvent,
|
||||
},
|
||||
Seat, SeatHandler, SeatState,
|
||||
},
|
||||
reexports::{
|
||||
calloop::{EventLoop, LoopHandle},
|
||||
wayland_server::{protocol::wl_seat, Display},
|
||||
},
|
||||
utils::{IsAlive, Logical, Point, Rectangle, Scale, Serial, Transform},
|
||||
wayland::{
|
||||
buffer::BufferHandler,
|
||||
compositor::{
|
||||
with_surface_tree_downward, CompositorClientState, CompositorHandler, CompositorState,
|
||||
SurfaceAttributes, TraversalAction,
|
||||
},
|
||||
seat::WaylandFocus,
|
||||
selection::{
|
||||
data_device::{
|
||||
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
|
||||
},
|
||||
SelectionHandler,
|
||||
},
|
||||
shell::xdg::{
|
||||
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
|
||||
},
|
||||
shm::{ShmHandler, ShmState},
|
||||
xwayland_shell::XWaylandShellState,
|
||||
},
|
||||
xwayland::{X11Surface, XWaylandClientData, xwm::ResizeEdge},
|
||||
};
|
||||
use wayland_protocols::xdg::shell::server::xdg_toplevel;
|
||||
use wayland_server::{
|
||||
backend::{ClientData, ClientId, DisconnectReason},
|
||||
protocol::{
|
||||
wl_buffer,
|
||||
wl_surface::{self, WlSurface},
|
||||
},
|
||||
Client, ListeningSocket,
|
||||
};
|
||||
|
||||
use crate::xwayland::XWaylandState;
|
||||
|
||||
pub struct State {
|
||||
pub seat: Seat<Self>,
|
||||
|
||||
pub space: Mutex<Space<AppWrapper>>,
|
||||
clients: Mutex<Vec<Client>>,
|
||||
|
||||
pointer_location: Point<f64, Logical>,
|
||||
pointer_location_rel: Point<f64, Logical>,
|
||||
|
||||
start_time: Instant,
|
||||
listener: ListeningSocket,
|
||||
|
||||
pub event_loop_handle: LoopHandle<'static, Self>,
|
||||
pub xwayland_state: XWaylandState,
|
||||
|
||||
start_data: GrabStartData<State>,
|
||||
|
||||
compositor_state: CompositorState,
|
||||
xdg_shell_state: XdgShellState,
|
||||
shm_state: ShmState,
|
||||
seat_state: SeatState<Self>,
|
||||
data_device_state: DataDeviceState,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn new(
|
||||
display: &Display<State>,
|
||||
event_loop: &EventLoop<'static, Self>,
|
||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let dh = display.handle();
|
||||
|
||||
let compositor_state = CompositorState::new::<State>(&dh);
|
||||
let shm_state = ShmState::new::<State>(&dh, vec![]);
|
||||
let mut seat_state = SeatState::new();
|
||||
let seat = seat_state.new_wl_seat(&dh, "milkyway_seat");
|
||||
let space = Space::default();
|
||||
let listener = ListeningSocket::bind("wayland-5").unwrap();
|
||||
|
||||
let event_loop_handle = event_loop.handle();
|
||||
Ok(State {
|
||||
compositor_state,
|
||||
xdg_shell_state: XdgShellState::new::<State>(&dh),
|
||||
shm_state,
|
||||
seat_state,
|
||||
data_device_state: DataDeviceState::new::<State>(&dh),
|
||||
seat,
|
||||
start_time: Instant::now(),
|
||||
listener,
|
||||
clients: Mutex::new(vec![]),
|
||||
space: Mutex::new(space),
|
||||
pointer_location: Point::new(0.0, 0.0),
|
||||
pointer_location_rel: Point::new(0.0, 0.0),
|
||||
event_loop_handle,
|
||||
xwayland_state: XWaylandState {
|
||||
xwm: None,
|
||||
xwayland_shell_state: XWaylandShellState::new::<State>(&dh),
|
||||
},
|
||||
start_data: GrabStartData {
|
||||
focus: None,
|
||||
button: 0,
|
||||
location: Point::new(0.0, 0.0),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render<A>(
|
||||
&self,
|
||||
backend: &mut A,
|
||||
display: &Display<Self>,
|
||||
) -> Result<(), Box<dyn std::error::Error>>
|
||||
where
|
||||
A: crate::backend::Backend,
|
||||
{
|
||||
let space = self.space.lock();
|
||||
let size = backend.bounds();
|
||||
let damage = Rectangle::from_size(size);
|
||||
let (renderer, mut framebuffer) = backend.get_fb().unwrap();
|
||||
|
||||
let mut elements = space
|
||||
.elements()
|
||||
.flat_map(|element| {
|
||||
if let Some(surface) = element.surface.clone() {
|
||||
return render_elements_from_surface_tree(
|
||||
renderer,
|
||||
surface.wl_surface(),
|
||||
(0, 0),
|
||||
1.0,
|
||||
1.0,
|
||||
Kind::Unspecified,
|
||||
);
|
||||
}
|
||||
if let Some(surface) = element.xsurface.clone() {
|
||||
return surface.render_elements(
|
||||
renderer,
|
||||
Point::new(0, 0),
|
||||
Scale { x: 1.0, y: 1.0 },
|
||||
1.0,
|
||||
);
|
||||
}
|
||||
panic!()
|
||||
})
|
||||
.collect::<Vec<WaylandSurfaceRenderElement<GlesRenderer>>>();
|
||||
|
||||
elements.reverse();
|
||||
|
||||
let mut frame = renderer
|
||||
.render(&mut framebuffer, size, Transform::Flipped180)
|
||||
.unwrap();
|
||||
frame
|
||||
.clear(Color32F::new(0.1, 0.0, 0.0, 1.0), &[damage])
|
||||
.unwrap();
|
||||
|
||||
draw_render_elements(&mut frame, 1.0, &elements, &[damage]).unwrap();
|
||||
// We rely on the nested compositor to do the sync for us
|
||||
let _ = frame.finish().unwrap();
|
||||
|
||||
for surface in self.xdg_shell_state.toplevel_surfaces() {
|
||||
self.send_frames_surface_tree(surface.wl_surface());
|
||||
}
|
||||
|
||||
if let Some(stream) = self.listener.accept()? {
|
||||
let client = display
|
||||
.handle()
|
||||
.insert_client(stream, Arc::new(ClientState::default()))
|
||||
.unwrap();
|
||||
let mut clients = self.clients.lock();
|
||||
clients.push(client);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn focused_surface(&mut self) -> Option<AppWrapper> {
|
||||
let space = self.space.lock();
|
||||
// let mut surfaces = vec![];
|
||||
let mut elements = space.elements().collect::<Vec<_>>();
|
||||
elements.reverse();
|
||||
for window in elements {
|
||||
if window.is_in_input_region(&self.pointer_location) {
|
||||
return Some(window.clone());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn button_event(&mut self, ev: ButtonEvent, pointer: &PointerHandle<Self>) {
|
||||
if ev.state == ButtonState::Pressed && let Some(app) = self.focused_surface() {
|
||||
let space = self.space.lock();
|
||||
|
||||
let initial_rect = space.element_geometry(&app).unwrap();
|
||||
|
||||
println!("{:?}",initial_rect);
|
||||
};
|
||||
|
||||
pointer.button(self, &ev);
|
||||
}
|
||||
|
||||
pub fn motion_event(
|
||||
&mut self,
|
||||
ev: MotionEvent,
|
||||
pointer: &PointerHandle<Self>,
|
||||
locationrel: Point<f64, Logical>,
|
||||
) {
|
||||
self.pointer_location = ev.location;
|
||||
self.pointer_location_rel = locationrel;
|
||||
if let Some(surface) = self.focused_surface() {
|
||||
if let Some(surface) = surface.surface {
|
||||
pointer.motion(self, Some((surface.wl_surface().clone(), locationrel)), &ev);
|
||||
}
|
||||
if let Some(surface) = surface.xsurface {
|
||||
if let Some(surface) = surface.wl_surface() {
|
||||
pointer.motion(self, Some((surface, locationrel)), &ev);
|
||||
}
|
||||
}
|
||||
pointer.frame(self);
|
||||
} else {
|
||||
pointer.motion(self, None, &ev);
|
||||
pointer.frame(self);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_frames_surface_tree(&self, surface: &wl_surface::WlSurface) {
|
||||
let time = self.start_time.elapsed().as_millis() as u32;
|
||||
|
||||
with_surface_tree_downward(
|
||||
surface,
|
||||
(),
|
||||
|_, _, &()| TraversalAction::DoChildren(()),
|
||||
|_surf, states, &()| {
|
||||
// the surface may not have any user_data if it is a subsurface and has not
|
||||
// yet been committed
|
||||
for callback in states
|
||||
.cached_state
|
||||
.get::<SurfaceAttributes>()
|
||||
.current()
|
||||
.frame_callbacks
|
||||
.drain(..)
|
||||
{
|
||||
callback.done(time);
|
||||
}
|
||||
},
|
||||
|_, _, &()| true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl BufferHandler for State {
|
||||
fn buffer_destroyed(&mut self, _buffer: &wl_buffer::WlBuffer) {}
|
||||
}
|
||||
|
||||
impl XdgShellHandler for State {
|
||||
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
|
||||
&mut self.xdg_shell_state
|
||||
}
|
||||
|
||||
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||
surface.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Activated);
|
||||
});
|
||||
surface.send_configure();
|
||||
|
||||
let mut space = self.space.lock();
|
||||
|
||||
space.map_element(AppWrapper::new_wayland(surface), (0, 0), true);
|
||||
}
|
||||
|
||||
fn new_popup(&mut self, _surface: PopupSurface, _positioner: PositionerState) {
|
||||
// Handle popup creation here
|
||||
}
|
||||
|
||||
fn grab(&mut self, _surface: PopupSurface, _seat: wl_seat::WlSeat, _serial: Serial) {
|
||||
// Handle popup grab here
|
||||
}
|
||||
|
||||
fn reposition_request(
|
||||
&mut self,
|
||||
_surface: PopupSurface,
|
||||
_positioner: PositionerState,
|
||||
_token: u32,
|
||||
) {
|
||||
// Handle popup reposition here
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectionHandler for State {
|
||||
type SelectionUserData = ();
|
||||
}
|
||||
impl ClientDndGrabHandler for State {}
|
||||
impl ServerDndGrabHandler for State {}
|
||||
|
||||
impl DataDeviceHandler for State {
|
||||
fn data_device_state(&self) -> &DataDeviceState {
|
||||
&self.data_device_state
|
||||
}
|
||||
}
|
||||
|
||||
impl CompositorHandler for State {
|
||||
fn compositor_state(&mut self) -> &mut CompositorState {
|
||||
&mut self.compositor_state
|
||||
}
|
||||
|
||||
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
|
||||
if let Some(state) = client.get_data::<XWaylandClientData>() {
|
||||
return &state.compositor_state;
|
||||
}
|
||||
if let Some(state) = client.get_data::<ClientState>() {
|
||||
return &state.compositor_state;
|
||||
}
|
||||
panic!("unknown client state type?");
|
||||
}
|
||||
|
||||
fn commit(&mut self, surface: &WlSurface) {
|
||||
on_commit_buffer_handler::<Self>(surface);
|
||||
}
|
||||
}
|
||||
|
||||
impl ShmHandler for State {
|
||||
fn shm_state(&self) -> &ShmState {
|
||||
&self.shm_state
|
||||
}
|
||||
}
|
||||
|
||||
impl SeatHandler for State {
|
||||
type KeyboardFocus = WlSurface;
|
||||
type PointerFocus = WlSurface;
|
||||
type TouchFocus = WlSurface;
|
||||
|
||||
fn seat_state(&mut self) -> &mut SeatState<Self> {
|
||||
&mut self.seat_state
|
||||
}
|
||||
|
||||
fn focus_changed(&mut self, _seat: &Seat<Self>, _focused: Option<&WlSurface>) {}
|
||||
fn cursor_image(
|
||||
&mut self,
|
||||
_seat: &Seat<Self>,
|
||||
_image: smithay::input::pointer::CursorImageStatus,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MoveGrab {
|
||||
start_data: GrabStartData<State>,
|
||||
window: Window,
|
||||
initial_window_location: Point<i32, Logical>,
|
||||
}
|
||||
|
||||
impl PointerGrab<State> for MoveGrab {
|
||||
fn motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
_focus: Option<(<State as SeatHandler>::PointerFocus, Point<f64, Logical>)>,
|
||||
event: &MotionEvent,
|
||||
) {
|
||||
handle.motion(data, None, event);
|
||||
|
||||
// let delta = event.location - self.start_data.location;
|
||||
|
||||
// let mut new_width = self.initial_rect.size.w;
|
||||
// let mut new_height = self.initial_rect.size.h;
|
||||
|
||||
// if self.edges.intersects(ResizeEdge::LEFT | ResizeEdge::RIGHT) {
|
||||
// new_width = if self.edges.intersects(ResizeEdge::LEFT) {
|
||||
// (self.initial_rect.size.w as f64 - delta.x) as i32
|
||||
// } else {
|
||||
// (self.initial_rect.size.w as f64 + delta.x) as i32
|
||||
// };
|
||||
// }
|
||||
// if self.edges.intersects(ResizeEdge::TOP | ResizeEdge::BOTTOM) {
|
||||
// new_height = if self.edges.intersects(ResizeEdge::TOP) {
|
||||
// (self.initial_rect.size.h as f64 - delta.y) as i32
|
||||
// } else {
|
||||
// (self.initial_rect.size.h as f64 + delta.y) as i32
|
||||
// };
|
||||
// }
|
||||
|
||||
// // clamp to whatever min/max you enforce
|
||||
// let (min_size, max_size) = (Size::from((100, 100)), Size::from((i32::MAX, i32::MAX)));
|
||||
// new_width = new_width.clamp(min_size.w, max_size.w);
|
||||
// new_height = new_height.clamp(min_size.h, max_size.h);
|
||||
|
||||
// self.last_window_size = (new_width, new_height).into();
|
||||
|
||||
// if let Some(toplevel) = self.window.toplevel() {
|
||||
// toplevel.with_pending_state(|state| {
|
||||
// state.size = Some(self.last_window_size);
|
||||
// state.states.set(xdg_toplevel::State::Resizing);
|
||||
// });
|
||||
// toplevel.send_pending_configure();
|
||||
// }
|
||||
}
|
||||
|
||||
fn relative_motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
focus: Option<(<State as SeatHandler>::PointerFocus, Point<f64, Logical>)>,
|
||||
event: &RelativeMotionEvent,
|
||||
) {
|
||||
handle.relative_motion(data, focus, event);
|
||||
}
|
||||
|
||||
fn button(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &ButtonEvent,
|
||||
) {
|
||||
handle.button(data, event);
|
||||
}
|
||||
|
||||
fn axis(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
details: AxisFrame,
|
||||
) {
|
||||
handle.axis(data, details)
|
||||
}
|
||||
|
||||
fn frame(&mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>) {
|
||||
handle.frame(data);
|
||||
}
|
||||
|
||||
fn gesture_swipe_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeBeginEvent,
|
||||
) {
|
||||
handle.gesture_swipe_begin(data, event);
|
||||
}
|
||||
|
||||
fn gesture_swipe_update(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeUpdateEvent,
|
||||
) {
|
||||
handle.gesture_swipe_update(data, event);
|
||||
}
|
||||
|
||||
fn gesture_swipe_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureSwipeEndEvent,
|
||||
) {
|
||||
handle.gesture_swipe_end(data, event);
|
||||
}
|
||||
|
||||
fn gesture_pinch_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchBeginEvent,
|
||||
) {
|
||||
handle.gesture_pinch_begin(data, event);
|
||||
}
|
||||
|
||||
fn gesture_pinch_update(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchUpdateEvent,
|
||||
) {
|
||||
handle.gesture_pinch_update(data, event);
|
||||
}
|
||||
|
||||
fn gesture_pinch_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GesturePinchEndEvent,
|
||||
) {
|
||||
handle.gesture_pinch_end(data, event);
|
||||
}
|
||||
|
||||
fn gesture_hold_begin(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureHoldBeginEvent,
|
||||
) {
|
||||
handle.gesture_hold_begin(data, event);
|
||||
}
|
||||
|
||||
fn gesture_hold_end(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
event: &GestureHoldEndEvent,
|
||||
) {
|
||||
handle.gesture_hold_end(data, event);
|
||||
}
|
||||
|
||||
fn start_data(&self) -> &GrabStartData<State> {
|
||||
&self.start_data
|
||||
}
|
||||
|
||||
fn unset(&mut self, data: &mut State) {}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub struct AppWrapper {
|
||||
pub surface: Option<ToplevelSurface>,
|
||||
pub xsurface: Option<X11Surface>,
|
||||
pub window: Window,
|
||||
}
|
||||
|
||||
impl AppWrapper {
|
||||
pub fn new_wayland(surface: ToplevelSurface) -> Self {
|
||||
let window = Window::new_wayland_window(surface.clone());
|
||||
Self {
|
||||
surface: Some(surface),
|
||||
xsurface: None,
|
||||
window,
|
||||
}
|
||||
}
|
||||
pub fn new_x11(xsurface: X11Surface) -> Self {
|
||||
let window = Window::new_x11_window(xsurface.clone());
|
||||
Self {
|
||||
surface: None,
|
||||
xsurface: Some(xsurface),
|
||||
window,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_window(window: Window) -> Self {
|
||||
if let Some(xsurface) = window.x11_surface() {
|
||||
Self {
|
||||
surface: None,
|
||||
xsurface: Some(xsurface.clone()),
|
||||
window,
|
||||
}
|
||||
} else if let Some(surface) = window.toplevel() {
|
||||
Self {
|
||||
surface: Some(surface.clone()),
|
||||
xsurface: None,
|
||||
window,
|
||||
}
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpaceElement for AppWrapper {
|
||||
fn bbox(&self) -> Rectangle<i32, smithay::utils::Logical> {
|
||||
return SpaceElement::bbox(&self.window);
|
||||
}
|
||||
|
||||
fn is_in_input_region(
|
||||
&self,
|
||||
point: &smithay::utils::Point<f64, smithay::utils::Logical>,
|
||||
) -> bool {
|
||||
return self.window.is_in_input_region(point);
|
||||
}
|
||||
|
||||
fn set_activate(&self, activated: bool) {
|
||||
return self.window.set_activate(activated);
|
||||
}
|
||||
|
||||
fn output_enter(
|
||||
&self,
|
||||
output: &smithay::output::Output,
|
||||
overlap: Rectangle<i32, smithay::utils::Logical>,
|
||||
) {
|
||||
return self.window.output_enter(output, overlap);
|
||||
}
|
||||
|
||||
fn output_leave(&self, output: &smithay::output::Output) {
|
||||
return self.window.output_leave(output);
|
||||
}
|
||||
}
|
||||
|
||||
impl IsAlive for AppWrapper {
|
||||
fn alive(&self) -> bool {
|
||||
self.window.alive()
|
||||
}
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct ClientState {
|
||||
compositor_state: CompositorClientState,
|
||||
}
|
||||
impl ClientData for ClientState {
|
||||
fn initialized(&self, _client_id: ClientId) {
|
||||
println!("initialized");
|
||||
}
|
||||
|
||||
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {
|
||||
println!("disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
// Macros used to delegate protocol handling to types in the app state.
|
||||
delegate_xdg_shell!(State);
|
||||
delegate_compositor!(State);
|
||||
delegate_shm!(State);
|
||||
delegate_seat!(State);
|
||||
delegate_data_device!(State);
|
||||
134
src/xwayland.rs
Normal file
134
src/xwayland.rs
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
use std::process::Stdio;
|
||||
|
||||
use smithay::{
|
||||
delegate_xwayland_shell,
|
||||
reexports::calloop::EventLoop,
|
||||
utils::{Logical, Rectangle},
|
||||
wayland::xwayland_shell::{XWaylandShellHandler, XWaylandShellState},
|
||||
xwayland::{
|
||||
xwm::{Reorder, ResizeEdge, XwmId},
|
||||
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
|
||||
},
|
||||
};
|
||||
use wayland_server::Display;
|
||||
|
||||
use crate::state::{AppWrapper, State};
|
||||
|
||||
pub struct XWaylandState {
|
||||
pub xwm: Option<X11Wm>,
|
||||
pub xwayland_shell_state: XWaylandShellState,
|
||||
}
|
||||
impl XwmHandler for State {
|
||||
fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm {
|
||||
self.xwayland_state.xwm.as_mut().unwrap()
|
||||
}
|
||||
|
||||
fn new_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
||||
|
||||
fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
||||
|
||||
fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||
// grant it — the window will be mapped once you set this
|
||||
window.set_mapped(true).unwrap();
|
||||
|
||||
let mut space = self.space.lock();
|
||||
|
||||
let z_index = space.elements().len();
|
||||
space.map_element(AppWrapper::new_x11(window), (0, 0), true);
|
||||
|
||||
// insert it into your Space/window management here
|
||||
}
|
||||
|
||||
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
||||
|
||||
fn unmapped_window(&mut self, _xwm: XwmId, _window: X11Surface) {
|
||||
let mut space = self.space.lock();
|
||||
}
|
||||
|
||||
fn destroyed_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
||||
|
||||
fn configure_request(
|
||||
&mut self,
|
||||
_xwm: XwmId,
|
||||
window: X11Surface,
|
||||
x: Option<i32>,
|
||||
y: Option<i32>,
|
||||
w: Option<u32>,
|
||||
h: Option<u32>,
|
||||
_reorder: Option<Reorder>,
|
||||
) {
|
||||
// Usually you just approve the requested geometry
|
||||
let _ = window.configure(None);
|
||||
}
|
||||
|
||||
fn configure_notify(
|
||||
&mut self,
|
||||
_xwm: XwmId,
|
||||
_window: X11Surface,
|
||||
_geo: Rectangle<i32, Logical>,
|
||||
_above: Option<u32>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn resize_request(
|
||||
&mut self,
|
||||
_xwm: XwmId,
|
||||
_window: X11Surface,
|
||||
_button: u32,
|
||||
_edge: ResizeEdge,
|
||||
) {
|
||||
}
|
||||
fn move_request(&mut self, _xwm: XwmId, _window: X11Surface, _button: u32) {}
|
||||
}
|
||||
|
||||
impl XWaylandShellHandler for State {
|
||||
fn xwayland_shell_state(
|
||||
&mut self,
|
||||
) -> &mut smithay::wayland::xwayland_shell::XWaylandShellState {
|
||||
&mut self.xwayland_state.xwayland_shell_state
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn setup_xwayland(
|
||||
&mut self,
|
||||
display: &Display<State>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let dh = display.handle();
|
||||
let (xwayland, client) = XWayland::spawn(
|
||||
&dh,
|
||||
None,
|
||||
std::iter::empty::<(String, String)>(),
|
||||
true,
|
||||
Stdio::null(),
|
||||
Stdio::null(),
|
||||
|_| {},
|
||||
)?;
|
||||
|
||||
let event_loop_handle = self.event_loop_handle.clone();
|
||||
event_loop_handle.insert_source(xwayland, move |event, _, state| {
|
||||
match event {
|
||||
XWaylandEvent::Ready {
|
||||
x11_socket,
|
||||
display_number,
|
||||
} => {
|
||||
let event_loop = state.event_loop_handle.clone();
|
||||
let wm = X11Wm::start_wm(event_loop, x11_socket, client.clone())
|
||||
.expect("failed to start X11 wm");
|
||||
|
||||
state.xwayland_state.xwm = Some(wm);
|
||||
|
||||
println!("XWayland started on display :{display_number}");
|
||||
unsafe { std::env::set_var("DISPLAY", format!(":{display_number}")) };
|
||||
}
|
||||
XWaylandEvent::Error => {
|
||||
// warn!("XWayland crashed on startup");
|
||||
}
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
delegate_xwayland_shell!(State);
|
||||
Loading…
Add table
Add a link
Reference in a new issue