use anyhow::Result;
use smithay::{
backend::{
renderer::{
element::{texture::TextureRenderElement, Element, RenderElement},
gles::GlesTexture,
glow::GlowRenderer,
Frame, Renderer,
},
winit,
},
input::{
keyboard::{FilterResult, XkbConfig},
pointer::{AxisFrame, ButtonEvent, MotionEvent},
SeatHandler, SeatState,
},
reexports::wayland_server::protocol::wl_surface::WlSurface,
utils::{Rectangle, Transform, SERIAL_COUNTER},
};
use smithay_egui::EguiState;
struct State(SeatState<State>);
impl SeatHandler for State {
type KeyboardFocus = EguiState;
type PointerFocus = EguiState;
type TouchFocus = WlSurface;
fn seat_state(&mut self) -> &mut SeatState<Self> {
&mut self.0
}
}
fn main() -> Result<()> {
tracing_subscriber::fmt().compact().init();
let (mut backend, mut input) =
winit::init::<GlowRenderer>().map_err(|_| anyhow::anyhow!("Winit failed to start"))?;
let egui = EguiState::new(Rectangle::from_size(backend.window_size().to_logical(1)));
let mut demo_ui = egui_demo_lib::DemoWindows::default();
let mut seat_state = SeatState::new();
let mut seat = seat_state.new_seat("seat-0");
let mut state = State(seat_state);
let keyboard = seat.add_keyboard(XkbConfig::default(), 200, 25)?;
keyboard.set_focus(&mut state, Some(egui.clone()), SERIAL_COUNTER.next_serial());
let pointer = seat.add_pointer();
loop {
input.dispatch_new_events(|event| {
use smithay::backend::{
input::{
AbsolutePositionEvent, Axis, AxisSource, Event, InputEvent, KeyboardKeyEvent,
PointerAxisEvent, PointerButtonEvent,
},
winit::WinitEvent::*,
};
match event {
Input(event) => match event {
InputEvent::DeviceAdded { device } => egui.handle_device_added(&device),
InputEvent::DeviceRemoved { device } => egui.handle_device_added(&device),
InputEvent::Keyboard { event } => keyboard
.input(
&mut state,
event.key_code(),
event.state(),
SERIAL_COUNTER.next_serial(),
event.time_msec(),
|_data, _modifiers, _handle| FilterResult::Forward,
)
.unwrap_or(()),
InputEvent::PointerMotionAbsolute { event } => {
let pos = event.position();
pointer.motion(
&mut state,
Some((egui.clone(), (0., 0.).into())),
&MotionEvent {
location: (pos.x, pos.y).into(),
serial: SERIAL_COUNTER.next_serial(),
time: event.time_msec(),
},
);
}
InputEvent::PointerButton { event } => pointer.button(
&mut state,
&ButtonEvent {
button: event.button_code(),
state: event.state().into(),
serial: SERIAL_COUNTER.next_serial(),
time: event.time_msec(),
},
),
InputEvent::PointerAxis { event } => {
let horizontal_amount =
event.amount(Axis::Horizontal).unwrap_or_else(|| {
event.amount_v120(Axis::Horizontal).unwrap_or(0.0) * 15.0 / 120.
});
let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| {
event.amount_v120(Axis::Vertical).unwrap_or(0.0) * 15.0 / 120.
});
let horizontal_amount_discrete = event.amount_v120(Axis::Horizontal);
let vertical_amount_discrete = event.amount_v120(Axis::Vertical);
{
let mut frame =
AxisFrame::new(event.time_msec()).source(event.source());
if horizontal_amount != 0.0 {
frame = frame.value(Axis::Horizontal, horizontal_amount);
if let Some(discrete) = horizontal_amount_discrete {
frame = frame.v120(Axis::Horizontal, discrete as i32);
}
} else if event.source() == AxisSource::Finger {
frame = frame.stop(Axis::Horizontal);
}
if vertical_amount != 0.0 {
frame = frame.value(Axis::Vertical, vertical_amount);
if let Some(discrete) = vertical_amount_discrete {
frame = frame.v120(Axis::Vertical, discrete as i32);
}
} else if event.source() == AxisSource::Finger {
frame = frame.stop(Axis::Vertical);
}
pointer.axis(&mut state, frame);
}
}
_ => {}
},
_ => {}
}
});
let size = backend.window_size();
let egui_frame: TextureRenderElement<GlesTexture> = egui
.render(
|ctx| demo_ui.ui(ctx),
backend.renderer(),
Rectangle::from_size(size.to_logical(1)),
1.0,
1.0,
)
.expect("Failed to render egui");
let (renderer, mut fb) = backend.bind()?;
{
let mut frame = renderer.render(&mut fb, size, Transform::Flipped180)?;
frame.clear([1.0, 1.0, 1.0, 1.0].into(), &[Rectangle::from_size(size)])?;
RenderElement::<GlowRenderer>::draw(
&egui_frame,
&mut frame,
egui_frame.src(),
egui_frame.geometry(1.0.into()),
&[Rectangle::from_size(size)],
&[],
)?;
}
std::mem::drop(fb);
backend.submit(None)?;
}
}