mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Added framework for different backends
This commit is contained in:
parent
caa6930cd5
commit
89d83bd1e7
11 changed files with 720 additions and 508 deletions
11
src/backend.rs
Normal file
11
src/backend.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use smithay::{output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface};
|
||||
|
||||
pub mod winit;
|
||||
|
||||
pub trait Backend: 'static {
|
||||
fn seat_name(&self) -> String;
|
||||
fn reset_buffers(&mut self, output: &Output);
|
||||
|
||||
// INFO: only for udev in anvil, maybe shouldn't be a trait fn?
|
||||
fn early_import(&mut self, surface: &WlSurface);
|
||||
}
|
572
src/backend/winit.rs
Normal file
572
src/backend/winit.rs
Normal file
|
@ -0,0 +1,572 @@
|
|||
use std::{error::Error, os::fd::AsRawFd, sync::Arc, time::Duration};
|
||||
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::dmabuf::Dmabuf,
|
||||
egl::EGLDevice,
|
||||
input::{
|
||||
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputEvent, KeyState,
|
||||
KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent,
|
||||
},
|
||||
renderer::{
|
||||
damage::OutputDamageTracker, element::surface::WaylandSurfaceRenderElement,
|
||||
gles::GlesRenderer, ImportDma,
|
||||
},
|
||||
winit::{WinitError, WinitEvent, WinitGraphicsBackend},
|
||||
},
|
||||
delegate_dmabuf,
|
||||
desktop::{space, Space, Window, WindowSurfaceType},
|
||||
input::{
|
||||
keyboard::{keysyms, FilterResult},
|
||||
pointer::{AxisFrame, ButtonEvent, CursorImageStatus, MotionEvent},
|
||||
SeatState,
|
||||
},
|
||||
output::{Output, Subpixel},
|
||||
reexports::{
|
||||
calloop::{
|
||||
generic::Generic,
|
||||
timer::{TimeoutAction, Timer},
|
||||
EventLoop, Interest, Mode, PostAction,
|
||||
},
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
|
||||
wayland_server::{protocol::wl_surface::WlSurface, Display},
|
||||
},
|
||||
utils::{Clock, Monotonic, Physical, Point, Scale, Transform, SERIAL_COUNTER},
|
||||
wayland::{
|
||||
compositor::CompositorState,
|
||||
data_device::DataDeviceState,
|
||||
dmabuf::{
|
||||
DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState,
|
||||
ImportError,
|
||||
},
|
||||
output::OutputManagerState,
|
||||
shell::xdg::XdgShellState,
|
||||
shm::ShmState,
|
||||
socket::ListeningSocketSource,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{CalloopData, ClientState, State};
|
||||
|
||||
use super::Backend;
|
||||
|
||||
pub struct WinitData {
|
||||
pub backend: WinitGraphicsBackend<GlesRenderer>,
|
||||
pub damage_tracker: OutputDamageTracker,
|
||||
pub dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
||||
pub full_redraw: u8,
|
||||
}
|
||||
|
||||
impl Backend for WinitData {
|
||||
fn seat_name(&self) -> String {
|
||||
"winit".to_string()
|
||||
}
|
||||
|
||||
fn reset_buffers(&mut self, _output: &Output) {
|
||||
self.full_redraw = 4;
|
||||
}
|
||||
|
||||
fn early_import(&mut self, _surface: &WlSurface) {}
|
||||
}
|
||||
|
||||
impl DmabufHandler for State<WinitData> {
|
||||
fn dmabuf_state(&mut self) -> &mut DmabufState {
|
||||
&mut self.backend_data.dmabuf_state.0
|
||||
}
|
||||
|
||||
fn dmabuf_imported(
|
||||
&mut self,
|
||||
global: &DmabufGlobal,
|
||||
dmabuf: Dmabuf,
|
||||
) -> Result<(), ImportError> {
|
||||
self.backend_data
|
||||
.backend
|
||||
.renderer()
|
||||
.import_dmabuf(&dmabuf, None)
|
||||
.map(|_| ())
|
||||
.map_err(|_| ImportError::Failed)
|
||||
}
|
||||
}
|
||||
delegate_dmabuf!(State<WinitData>);
|
||||
|
||||
pub fn run_winit() -> Result<(), Box<dyn Error>> {
|
||||
let mut event_loop: EventLoop<CalloopData> = EventLoop::try_new()?;
|
||||
|
||||
let mut display: Display<State<WinitData>> = Display::new()?;
|
||||
|
||||
let socket = ListeningSocketSource::new_auto()?;
|
||||
let socket_name = socket.socket_name().to_os_string();
|
||||
|
||||
let evt_loop_handle = event_loop.handle();
|
||||
|
||||
evt_loop_handle.insert_source(socket, |stream, _metadata, data| {
|
||||
data.display
|
||||
.handle()
|
||||
.insert_client(stream, Arc::new(ClientState::default()))
|
||||
.unwrap();
|
||||
})?;
|
||||
|
||||
evt_loop_handle.insert_source(
|
||||
Generic::new(
|
||||
display.backend().poll_fd().as_raw_fd(),
|
||||
Interest::READ,
|
||||
Mode::Level,
|
||||
),
|
||||
|_readiness, _metadata, data| {
|
||||
data.display.dispatch_clients(&mut data.state)?;
|
||||
Ok(PostAction::Continue)
|
||||
},
|
||||
)?;
|
||||
|
||||
let display_handle = display.handle();
|
||||
|
||||
let mut seat_state = SeatState::<State<WinitData>>::new();
|
||||
let mut seat = seat_state.new_wl_seat(&display_handle, "seat1");
|
||||
|
||||
seat.add_keyboard(Default::default(), 500, 50)?;
|
||||
seat.add_pointer();
|
||||
|
||||
let (mut winit_backend, mut winit_evt_loop) = smithay::backend::winit::init::<GlesRenderer>()?;
|
||||
|
||||
let mode = smithay::output::Mode {
|
||||
size: winit_backend.window_size().physical_size,
|
||||
refresh: 144_000,
|
||||
};
|
||||
|
||||
let physical_properties = smithay::output::PhysicalProperties {
|
||||
size: (0, 0).into(),
|
||||
subpixel: Subpixel::Unknown,
|
||||
make: "Comp make".to_string(),
|
||||
model: "Comp model".to_string(),
|
||||
};
|
||||
|
||||
let output = Output::new("27GL83A".to_string(), physical_properties);
|
||||
|
||||
output.create_global::<State<WinitData>>(&display_handle);
|
||||
|
||||
output.change_current_state(
|
||||
Some(mode),
|
||||
Some(Transform::Flipped180),
|
||||
None,
|
||||
Some((0, 0).into()),
|
||||
);
|
||||
|
||||
output.set_preferred(mode);
|
||||
|
||||
let mut damage_tracker = OutputDamageTracker::from_output(&output);
|
||||
|
||||
let render_node =
|
||||
EGLDevice::device_for_display(winit_backend.renderer().egl_context().display())
|
||||
.and_then(|device| device.try_get_render_node());
|
||||
|
||||
let dmabuf_default_feedback = match render_node {
|
||||
Ok(Some(node)) => {
|
||||
let dmabuf_formats = winit_backend
|
||||
.renderer()
|
||||
.dmabuf_formats()
|
||||
.collect::<Vec<_>>();
|
||||
let dmabuf_default_feedback = DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats)
|
||||
.build()
|
||||
.unwrap();
|
||||
Some(dmabuf_default_feedback)
|
||||
}
|
||||
Ok(None) => {
|
||||
eprintln!("failed to query render node, dmabuf will use v3"); // TODO: tracing
|
||||
None
|
||||
}
|
||||
Err(err) => {
|
||||
// TODO: tracing
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let dmabuf_state = match dmabuf_default_feedback {
|
||||
Some(default_feedback) => {
|
||||
let mut dmabuf_state = DmabufState::new();
|
||||
let dmabuf_global = dmabuf_state
|
||||
.create_global_with_default_feedback::<State<WinitData>>(
|
||||
&display_handle,
|
||||
&default_feedback,
|
||||
);
|
||||
(dmabuf_state, dmabuf_global, Some(default_feedback))
|
||||
}
|
||||
None => {
|
||||
let dmabuf_formats = winit_backend
|
||||
.renderer()
|
||||
.dmabuf_formats()
|
||||
.collect::<Vec<_>>();
|
||||
let mut dmabuf_state = DmabufState::new();
|
||||
let dmabuf_global =
|
||||
dmabuf_state.create_global::<State<WinitData>>(&display_handle, dmabuf_formats);
|
||||
(dmabuf_state, dmabuf_global, None)
|
||||
}
|
||||
};
|
||||
|
||||
let state = State {
|
||||
backend_data: WinitData {
|
||||
backend: winit_backend,
|
||||
damage_tracker,
|
||||
dmabuf_state,
|
||||
full_redraw: 0,
|
||||
},
|
||||
loop_signal: event_loop.get_signal(),
|
||||
loop_handle: event_loop.handle(),
|
||||
clock: Clock::<Monotonic>::new()?,
|
||||
compositor_state: CompositorState::new::<State<WinitData>>(&display_handle),
|
||||
data_device_state: DataDeviceState::new::<State<WinitData>>(&display_handle),
|
||||
seat_state,
|
||||
shm_state: ShmState::new::<State<WinitData>>(&display_handle, Vec::new()),
|
||||
space: Space::<Window>::default(),
|
||||
cursor_status: CursorImageStatus::Default,
|
||||
pointer_location: (0.0, 0.0).into(),
|
||||
output_manager_state: OutputManagerState::new_with_xdg_output::<State<WinitData>>(
|
||||
&display_handle,
|
||||
),
|
||||
xdg_shell_state: XdgShellState::new::<State<WinitData>>(&display_handle),
|
||||
|
||||
move_mode: false,
|
||||
};
|
||||
|
||||
let mut data = CalloopData { display, state };
|
||||
|
||||
data.state.space.map_output(&output, (0, 0));
|
||||
|
||||
std::env::set_var("WAYLAND_DISPLAY", socket_name);
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
let timer = Timer::immediate();
|
||||
|
||||
// TODO: pointer
|
||||
evt_loop_handle.insert_source(timer, move |_instant, _metadata, data| {
|
||||
let display = &mut data.display;
|
||||
let state = &mut data.state;
|
||||
|
||||
let result = winit_evt_loop.dispatch_new_events(|event| {
|
||||
match event {
|
||||
WinitEvent::Resized {
|
||||
size,
|
||||
scale_factor: _,
|
||||
} => {
|
||||
output.change_current_state(
|
||||
Some(smithay::output::Mode {
|
||||
size,
|
||||
refresh: 144_000,
|
||||
}),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
WinitEvent::Focus(_) => {}
|
||||
WinitEvent::Input(input_evt) => match input_evt {
|
||||
// TODO: extract input events
|
||||
// | into separate function
|
||||
|
||||
// InputEvent::DeviceAdded { device } => todo!(),
|
||||
// InputEvent::DeviceRemoved { device } => todo!(),
|
||||
InputEvent::Keyboard { event } => {
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let time = event.time_msec();
|
||||
let press_state = event.state();
|
||||
let mut move_mode = false;
|
||||
let action = seat.get_keyboard().unwrap().input(
|
||||
state,
|
||||
event.key_code(),
|
||||
press_state,
|
||||
serial,
|
||||
time,
|
||||
|_state, _modifiers, keysym| {
|
||||
if press_state == KeyState::Pressed {
|
||||
match keysym.modified_sym() {
|
||||
keysyms::KEY_L => return FilterResult::Intercept(1),
|
||||
keysyms::KEY_K => return FilterResult::Intercept(2),
|
||||
keysyms::KEY_J => return FilterResult::Intercept(3),
|
||||
keysyms::KEY_H => return FilterResult::Intercept(4),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if keysym.modified_sym() == keysyms::KEY_Control_L {
|
||||
match press_state {
|
||||
KeyState::Pressed => {
|
||||
move_mode = true;
|
||||
}
|
||||
KeyState::Released => {
|
||||
move_mode = false;
|
||||
}
|
||||
}
|
||||
FilterResult::Forward
|
||||
} else {
|
||||
FilterResult::Forward
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
state.move_mode = move_mode;
|
||||
|
||||
match action {
|
||||
Some(1) => {
|
||||
std::process::Command::new("alacritty").spawn().unwrap();
|
||||
}
|
||||
Some(2) => {
|
||||
std::process::Command::new("nautilus").spawn().unwrap();
|
||||
}
|
||||
Some(3) => {
|
||||
std::process::Command::new("kitty").spawn().unwrap();
|
||||
}
|
||||
Some(4) => {
|
||||
std::process::Command::new("foot").spawn().unwrap();
|
||||
}
|
||||
Some(_) => {}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
InputEvent::PointerMotion { event } => {}
|
||||
InputEvent::PointerMotionAbsolute { event } => {
|
||||
let output = state.space.outputs().next().unwrap();
|
||||
let output_geo = state.space.output_geometry(output).unwrap();
|
||||
let pointer_loc =
|
||||
event.position_transformed(output_geo.size) + output_geo.loc.to_f64();
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
|
||||
let surface_under_pointer = state
|
||||
.space
|
||||
.element_under(pointer_loc)
|
||||
.and_then(|(window, location)| {
|
||||
window
|
||||
.surface_under(
|
||||
pointer_loc - location.to_f64(),
|
||||
WindowSurfaceType::ALL,
|
||||
)
|
||||
.map(|(s, p)| (s, p + location))
|
||||
});
|
||||
|
||||
pointer.motion(
|
||||
state,
|
||||
surface_under_pointer,
|
||||
&MotionEvent {
|
||||
location: pointer_loc,
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
InputEvent::PointerButton { event } => {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
let keyboard = seat.get_keyboard().unwrap();
|
||||
|
||||
// A serial is a number sent with a event that is sent back to the
|
||||
// server by the clients in further requests. This allows the server to
|
||||
// keep track of which event caused which requests. It is an AtomicU32
|
||||
// that increments when next_serial is called.
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
|
||||
// Returns which button on the pointer was used.
|
||||
let button = event.button_code();
|
||||
|
||||
// The state, either released or pressed.
|
||||
let button_state = event.state();
|
||||
|
||||
let pointer_loc = pointer.current_location();
|
||||
|
||||
// If the button was clicked, focus on the window below if exists, else
|
||||
// unfocus on windows.
|
||||
if ButtonState::Pressed == button_state {
|
||||
if let Some((window, window_loc)) = state
|
||||
.space
|
||||
.element_under(pointer_loc)
|
||||
.map(|(w, l)| (w.clone(), l))
|
||||
{
|
||||
const BUTTON_LEFT: u32 = 0x110;
|
||||
const BUTTON_RIGHT: u32 = 0x111;
|
||||
if state.move_mode {
|
||||
if event.button_code() == BUTTON_LEFT {
|
||||
crate::xdg::request::move_request_force(
|
||||
state,
|
||||
window.toplevel(),
|
||||
&seat,
|
||||
serial,
|
||||
);
|
||||
return; // TODO: kinda ugly return here
|
||||
} else if event.button_code() == BUTTON_RIGHT {
|
||||
let window_geometry = window.geometry();
|
||||
let window_x = window_loc.x as f64;
|
||||
let window_y = window_loc.y as f64;
|
||||
let window_width = window_geometry.size.w as f64;
|
||||
let window_height = window_geometry.size.h as f64;
|
||||
let half_width = window_x + window_width / 2.0;
|
||||
let half_height = window_y + window_height / 2.0;
|
||||
let full_width = window_x + window_width;
|
||||
let full_height = window_y + window_height;
|
||||
|
||||
println!(
|
||||
"window loc: {}, {} | window size: {}, {}",
|
||||
window_x, window_y, window_width, window_height
|
||||
);
|
||||
|
||||
let edges = match pointer_loc {
|
||||
Point { x, y, .. }
|
||||
if (window_x..=half_width).contains(&x)
|
||||
&& (window_y..=half_height).contains(&y) =>
|
||||
{
|
||||
ResizeEdge::TopLeft
|
||||
}
|
||||
Point { x, y, .. }
|
||||
if (half_width..=full_width).contains(&x)
|
||||
&& (window_y..=half_height).contains(&y) =>
|
||||
{
|
||||
ResizeEdge::TopRight
|
||||
}
|
||||
Point { x, y, .. }
|
||||
if (window_x..=half_width).contains(&x)
|
||||
&& (half_height..=full_height).contains(&y) =>
|
||||
{
|
||||
ResizeEdge::BottomLeft
|
||||
}
|
||||
Point { x, y, .. }
|
||||
if (half_width..=full_width).contains(&x)
|
||||
&& (half_height..=full_height).contains(&y) =>
|
||||
{
|
||||
ResizeEdge::BottomRight
|
||||
}
|
||||
_ => ResizeEdge::None,
|
||||
};
|
||||
|
||||
crate::xdg::request::resize_request_force(
|
||||
state,
|
||||
window.toplevel(),
|
||||
&seat,
|
||||
serial,
|
||||
edges,
|
||||
BUTTON_RIGHT,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Move window to top of stack.
|
||||
state.space.raise_element(&window, true);
|
||||
|
||||
// Focus on window.
|
||||
keyboard.set_focus(
|
||||
state,
|
||||
Some(window.toplevel().wl_surface().clone()),
|
||||
serial,
|
||||
);
|
||||
state.space.elements().for_each(|window| {
|
||||
window.toplevel().send_configure();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
state.space.elements().for_each(|window| {
|
||||
window.set_activated(false);
|
||||
window.toplevel().send_configure();
|
||||
});
|
||||
keyboard.set_focus(state, None, serial);
|
||||
}
|
||||
};
|
||||
|
||||
// Send the button event to the client.
|
||||
pointer.button(
|
||||
state,
|
||||
&ButtonEvent {
|
||||
button,
|
||||
state: button_state,
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
InputEvent::PointerAxis { event } => {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
|
||||
let source = event.source();
|
||||
|
||||
let horizontal_amount =
|
||||
event.amount(Axis::Horizontal).unwrap_or_else(|| {
|
||||
event.amount_discrete(Axis::Horizontal).unwrap() * 3.0
|
||||
});
|
||||
|
||||
let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| {
|
||||
event.amount_discrete(Axis::Vertical).unwrap() * 3.0
|
||||
});
|
||||
|
||||
let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal);
|
||||
let vertical_amount_discrete = event.amount_discrete(Axis::Vertical);
|
||||
|
||||
let mut frame = AxisFrame::new(event.time_msec()).source(source);
|
||||
|
||||
if horizontal_amount != 0.0 {
|
||||
frame = frame.value(Axis::Horizontal, horizontal_amount);
|
||||
if let Some(discrete) = horizontal_amount_discrete {
|
||||
frame = frame.discrete(Axis::Horizontal, discrete as i32);
|
||||
}
|
||||
} else if 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.discrete(Axis::Vertical, discrete as i32);
|
||||
}
|
||||
} else if source == AxisSource::Finger {
|
||||
frame = frame.stop(Axis::Vertical);
|
||||
}
|
||||
|
||||
println!("axisframe: {:?}", frame);
|
||||
pointer.axis(state, frame);
|
||||
}
|
||||
// TODO: rest of the InputEvents
|
||||
_ => (),
|
||||
},
|
||||
WinitEvent::Refresh => {}
|
||||
}
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(_) => {}
|
||||
Err(WinitError::WindowClosed) => {
|
||||
state.loop_signal.stop();
|
||||
}
|
||||
};
|
||||
|
||||
state.backend_data.backend.bind().unwrap();
|
||||
|
||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||
let cursor_pos = state.pointer_location;
|
||||
let _cursor_pos_scaled: Point<i32, Physical> = cursor_pos.to_physical(scale).to_i32_round();
|
||||
|
||||
space::render_output::<_, WaylandSurfaceRenderElement<GlesRenderer>, _, _>(
|
||||
&output,
|
||||
state.backend_data.backend.renderer(),
|
||||
1.0,
|
||||
0,
|
||||
[&state.space],
|
||||
&[],
|
||||
&mut state.backend_data.damage_tracker,
|
||||
[0.5, 0.5, 0.5, 1.0],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
state.backend_data.backend.submit(None).unwrap();
|
||||
|
||||
state.space.elements().for_each(|window| {
|
||||
window.send_frame(
|
||||
&output,
|
||||
start_time.elapsed(),
|
||||
Some(Duration::ZERO),
|
||||
|_, _| Some(output.clone()),
|
||||
)
|
||||
});
|
||||
|
||||
state.space.refresh();
|
||||
|
||||
display.flush_clients().unwrap();
|
||||
|
||||
TimeoutAction::ToDuration(Duration::from_millis(6))
|
||||
})?;
|
||||
|
||||
event_loop.run(None, &mut data, |_data| {})?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -13,7 +13,7 @@ use smithay::{
|
|||
utils::{IsAlive, Logical, Point},
|
||||
};
|
||||
|
||||
use crate::State;
|
||||
use crate::{backend::Backend, State};
|
||||
|
||||
pub struct MoveSurfaceGrab<S: SeatHandler> {
|
||||
pub start_data: GrabStartData<S>,
|
||||
|
@ -21,12 +21,12 @@ pub struct MoveSurfaceGrab<S: SeatHandler> {
|
|||
pub initial_window_loc: Point<i32, Logical>,
|
||||
}
|
||||
|
||||
impl PointerGrab<State> for MoveSurfaceGrab<State> {
|
||||
impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
|
||||
fn motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
_focus: Option<(<State as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
data: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
_focus: Option<(<State<B> as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
event: &MotionEvent,
|
||||
) {
|
||||
handle.motion(data, None, event);
|
||||
|
@ -44,9 +44,9 @@ impl PointerGrab<State> for MoveSurfaceGrab<State> {
|
|||
|
||||
fn relative_motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
focus: Option<(<State as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
data: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
focus: Option<(<State<B> as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
event: &RelativeMotionEvent,
|
||||
) {
|
||||
handle.relative_motion(data, focus, event);
|
||||
|
@ -54,8 +54,8 @@ impl PointerGrab<State> for MoveSurfaceGrab<State> {
|
|||
|
||||
fn button(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
data: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
event: &ButtonEvent,
|
||||
) {
|
||||
handle.button(data, event);
|
||||
|
@ -69,14 +69,14 @@ impl PointerGrab<State> for MoveSurfaceGrab<State> {
|
|||
|
||||
fn axis(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
data: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
details: AxisFrame,
|
||||
) {
|
||||
handle.axis(data, details);
|
||||
}
|
||||
|
||||
fn start_data(&self) -> &GrabStartData<State> {
|
||||
fn start_data(&self) -> &GrabStartData<State<B>> {
|
||||
&self.start_data
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ use smithay::{
|
|||
wayland_server::protocol::wl_surface::WlSurface,
|
||||
},
|
||||
utils::{IsAlive, Logical, Point, Rectangle, Size},
|
||||
wayland::shell::xdg::SurfaceCachedState,
|
||||
wayland::{compositor, seat::WaylandFocus, shell::xdg::SurfaceCachedState},
|
||||
};
|
||||
|
||||
use crate::{window::SurfaceState, State};
|
||||
use crate::{backend::Backend, window::SurfaceState, State};
|
||||
|
||||
pub struct ResizeSurfaceGrab<S: SeatHandler> {
|
||||
start_data: GrabStartData<S>,
|
||||
|
@ -52,12 +52,12 @@ impl<S: SeatHandler> ResizeSurfaceGrab<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl PointerGrab<State> for ResizeSurfaceGrab<State> {
|
||||
impl<B: Backend> PointerGrab<State<B>> for ResizeSurfaceGrab<State<B>> {
|
||||
fn motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
_focus: Option<(<State as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
data: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
_focus: Option<(<State<B> as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
event: &smithay::input::pointer::MotionEvent,
|
||||
) {
|
||||
handle.motion(data, None, event);
|
||||
|
@ -85,13 +85,13 @@ impl PointerGrab<State> for ResizeSurfaceGrab<State> {
|
|||
new_window_height = self.initial_window_rect.size.h + delta.y;
|
||||
}
|
||||
|
||||
let (min_size, max_size) = smithay::wayland::compositor::with_states(
|
||||
self.window.toplevel().wl_surface(),
|
||||
|states| {
|
||||
let (min_size, max_size) = match self.window.wl_surface() {
|
||||
Some(wl_surface) => compositor::with_states(&wl_surface, |states| {
|
||||
let data = states.cached_state.current::<SurfaceCachedState>();
|
||||
(data.min_size, data.max_size)
|
||||
},
|
||||
);
|
||||
}),
|
||||
None => ((0, 0).into(), (0, 0).into()),
|
||||
};
|
||||
|
||||
let min_width = i32::min(1, min_size.w);
|
||||
let min_height = i32::min(1, min_size.h);
|
||||
|
@ -124,9 +124,9 @@ impl PointerGrab<State> for ResizeSurfaceGrab<State> {
|
|||
|
||||
fn relative_motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
focus: Option<(<State as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
data: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
focus: Option<(<State<B> as SeatHandler>::PointerFocus, Point<i32, Logical>)>,
|
||||
event: &smithay::input::pointer::RelativeMotionEvent,
|
||||
) {
|
||||
handle.relative_motion(data, focus, event);
|
||||
|
@ -134,8 +134,8 @@ impl PointerGrab<State> for ResizeSurfaceGrab<State> {
|
|||
|
||||
fn button(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
data: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
event: &ButtonEvent,
|
||||
) {
|
||||
handle.button(data, event);
|
||||
|
@ -162,14 +162,14 @@ impl PointerGrab<State> for ResizeSurfaceGrab<State> {
|
|||
|
||||
fn axis(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut PointerInnerHandle<'_, State>,
|
||||
data: &mut State<B>,
|
||||
handle: &mut PointerInnerHandle<'_, State<B>>,
|
||||
details: AxisFrame,
|
||||
) {
|
||||
handle.axis(data, details);
|
||||
}
|
||||
|
||||
fn start_data(&self) -> &GrabStartData<State> {
|
||||
fn start_data(&self) -> &GrabStartData<State<B>> {
|
||||
&self.start_data
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,28 +5,34 @@ use smithay::{
|
|||
desktop::Window,
|
||||
input::{pointer::CursorImageStatus, Seat, SeatHandler, SeatState},
|
||||
reexports::{
|
||||
calloop::Interest,
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
|
||||
wayland_server::{
|
||||
protocol::{wl_buffer::WlBuffer, wl_seat::WlSeat, wl_surface::WlSurface},
|
||||
Client,
|
||||
Client, Resource,
|
||||
},
|
||||
},
|
||||
utils::Serial,
|
||||
wayland::{
|
||||
buffer::BufferHandler,
|
||||
compositor::{self, CompositorClientState, CompositorHandler, CompositorState},
|
||||
compositor::{
|
||||
self, BufferAssignment, CompositorClientState, CompositorHandler, CompositorState,
|
||||
SurfaceAttributes,
|
||||
},
|
||||
data_device::{
|
||||
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
|
||||
},
|
||||
dmabuf,
|
||||
shell::xdg::{
|
||||
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
|
||||
XdgToplevelSurfaceData,
|
||||
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler,
|
||||
XdgShellState, XdgToplevelSurfaceData,
|
||||
},
|
||||
shm::{ShmHandler, ShmState},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::Backend,
|
||||
layout::{
|
||||
automatic::{MasterStack, MasterStackSide},
|
||||
Layout,
|
||||
|
@ -34,15 +40,46 @@ use crate::{
|
|||
ClientState, State,
|
||||
};
|
||||
|
||||
impl BufferHandler for State {
|
||||
impl<B: Backend> BufferHandler for State<B> {
|
||||
fn buffer_destroyed(&mut self, _buffer: &WlBuffer) {}
|
||||
}
|
||||
|
||||
impl CompositorHandler for State {
|
||||
impl<B: Backend> CompositorHandler for State<B> {
|
||||
fn compositor_state(&mut self) -> &mut CompositorState {
|
||||
&mut self.compositor_state
|
||||
}
|
||||
|
||||
fn new_surface(&mut self, surface: &WlSurface) {
|
||||
// yanked straight from anvil
|
||||
compositor::add_pre_commit_hook::<Self, _>(surface, |state, _display_handle, surface| {
|
||||
let maybe_dmabuf = compositor::with_states(surface, |surface_data| {
|
||||
surface_data
|
||||
.cached_state
|
||||
.pending::<SurfaceAttributes>()
|
||||
.buffer
|
||||
.as_ref()
|
||||
.and_then(|assignment| match assignment {
|
||||
BufferAssignment::NewBuffer(buffer) => dmabuf::get_dmabuf(buffer).ok(),
|
||||
_ => None,
|
||||
})
|
||||
});
|
||||
if let Some(dmabuf) = maybe_dmabuf {
|
||||
if let Ok((blocker, source)) = dmabuf.generate_blocker(Interest::READ) {
|
||||
let client = surface.client().unwrap();
|
||||
let res = state.loop_handle.insert_source(source, move |_, _, data| {
|
||||
data.state
|
||||
.client_compositor_state(&client)
|
||||
.blocker_cleared(&mut data.state, &data.display.handle());
|
||||
Ok(())
|
||||
});
|
||||
if res.is_ok() {
|
||||
compositor::add_blocker(surface, blocker);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn commit(&mut self, surface: &WlSurface) {
|
||||
// println!("CompositorHandler commit()");
|
||||
|
||||
|
@ -81,8 +118,12 @@ impl CompositorHandler for State {
|
|||
// println!("initial_configure_sent is {}", initial_configure_sent);
|
||||
|
||||
if !initial_configure_sent {
|
||||
// println!("initial configure");
|
||||
println!("initial configure");
|
||||
window.toplevel().send_configure();
|
||||
// println!(
|
||||
// "ensured_configured: {}",
|
||||
// window.toplevel().ensure_configured()
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,19 +134,19 @@ impl CompositorHandler for State {
|
|||
&client.get_data::<ClientState>().unwrap().compositor_state
|
||||
}
|
||||
}
|
||||
delegate_compositor!(State);
|
||||
delegate_compositor!(@<B: Backend> State<B>);
|
||||
|
||||
impl ClientDndGrabHandler for State {}
|
||||
impl ServerDndGrabHandler for State {}
|
||||
impl<B: Backend> ClientDndGrabHandler for State<B> {}
|
||||
impl<B: Backend> ServerDndGrabHandler for State<B> {}
|
||||
|
||||
impl DataDeviceHandler for State {
|
||||
impl<B: Backend> DataDeviceHandler for State<B> {
|
||||
fn data_device_state(&self) -> &DataDeviceState {
|
||||
&self.data_device_state
|
||||
}
|
||||
}
|
||||
delegate_data_device!(State);
|
||||
delegate_data_device!(@<B: Backend> State<B>);
|
||||
|
||||
impl SeatHandler for State {
|
||||
impl<B: Backend + 'static> SeatHandler for State<B> {
|
||||
type KeyboardFocus = WlSurface;
|
||||
type PointerFocus = WlSurface;
|
||||
|
||||
|
@ -119,21 +160,20 @@ impl SeatHandler for State {
|
|||
|
||||
fn focus_changed(&mut self, _seat: &Seat<Self>, _focused: Option<&Self::KeyboardFocus>) {}
|
||||
}
|
||||
delegate_seat!(State);
|
||||
delegate_seat!(@<B: Backend> State<B>);
|
||||
|
||||
impl ShmHandler for State {
|
||||
impl<B: Backend> ShmHandler for State<B> {
|
||||
fn shm_state(&self) -> &ShmState {
|
||||
&self.shm_state
|
||||
}
|
||||
}
|
||||
delegate_shm!(State);
|
||||
delegate_shm!(@<B: Backend> State<B>);
|
||||
|
||||
impl XdgShellHandler for State {
|
||||
impl<B: Backend> XdgShellHandler for State<B> {
|
||||
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
|
||||
&mut self.xdg_shell_state
|
||||
}
|
||||
|
||||
// TODO: this shouldn't call send_configure
|
||||
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||
let window = Window::new(surface);
|
||||
self.space.map_element(window, (0, 0), true);
|
||||
|
@ -145,8 +185,6 @@ impl XdgShellHandler for State {
|
|||
};
|
||||
|
||||
layout.layout_windows(self, windows);
|
||||
|
||||
// TODO: refresh all window geometries
|
||||
}
|
||||
|
||||
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
|
||||
|
@ -157,7 +195,6 @@ impl XdgShellHandler for State {
|
|||
};
|
||||
|
||||
layout.layout_windows(self, windows);
|
||||
// TODO: refresh geometries
|
||||
}
|
||||
|
||||
fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) {}
|
||||
|
@ -191,8 +228,12 @@ impl XdgShellHandler for State {
|
|||
|
||||
fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) {}
|
||||
|
||||
fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
|
||||
// println!("surface ack_configure: {:?}", configure);
|
||||
}
|
||||
|
||||
// TODO: impl the rest of the fns in XdgShellHandler
|
||||
}
|
||||
delegate_xdg_shell!(State);
|
||||
delegate_xdg_shell!(@<B: Backend> State<B>);
|
||||
|
||||
delegate_output!(State);
|
||||
delegate_output!(@<B: Backend> State<B>);
|
||||
|
|
|
@ -2,16 +2,19 @@ use std::{error::Error, fmt::Display};
|
|||
|
||||
use smithay::desktop::Window;
|
||||
|
||||
use crate::State;
|
||||
use crate::{backend::Backend, State};
|
||||
|
||||
pub mod automatic;
|
||||
pub mod manual;
|
||||
|
||||
pub trait Layout {
|
||||
fn layout_windows(&self, state: &mut State, windows: Vec<Window>);
|
||||
fn add_window(&mut self, state: &mut State, window: Window);
|
||||
fn remove_window(&mut self, state: &mut State, window: Window)
|
||||
-> Result<(), RemoveWindowError>;
|
||||
pub trait Layout<B: Backend> {
|
||||
fn layout_windows(&self, state: &mut State<B>, windows: Vec<Window>);
|
||||
fn add_window(&mut self, state: &mut State<B>, window: Window);
|
||||
fn remove_window(
|
||||
&mut self,
|
||||
state: &mut State<B>,
|
||||
window: Window,
|
||||
) -> Result<(), RemoveWindowError>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use smithay::desktop::Window;
|
||||
|
||||
use crate::State;
|
||||
use crate::{backend::Backend, State};
|
||||
|
||||
use super::{Layout, RemoveWindowError};
|
||||
|
||||
|
@ -19,8 +19,8 @@ pub enum MasterStackSide {
|
|||
Bottom,
|
||||
}
|
||||
|
||||
impl Layout for MasterStack {
|
||||
fn layout_windows(&self, state: &mut State, windows: Vec<Window>) {
|
||||
impl<B: Backend> Layout<B> for MasterStack {
|
||||
fn layout_windows(&self, state: &mut State<B>, windows: Vec<Window>) {
|
||||
match self.side {
|
||||
MasterStackSide::Left => {
|
||||
// println!("MasterStack layout_windows");
|
||||
|
@ -98,13 +98,13 @@ impl Layout for MasterStack {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_window(&mut self, state: &mut State, window: Window) {
|
||||
fn add_window(&mut self, state: &mut State<B>, window: Window) {
|
||||
self.windows.push(window);
|
||||
}
|
||||
|
||||
fn remove_window(
|
||||
&mut self,
|
||||
state: &mut State,
|
||||
state: &mut State<B>,
|
||||
window: Window,
|
||||
) -> Result<(), RemoveWindowError> {
|
||||
let pos = self
|
||||
|
|
440
src/main.rs
440
src/main.rs
|
@ -1,3 +1,4 @@
|
|||
mod backend;
|
||||
mod grab;
|
||||
mod handlers;
|
||||
mod layout;
|
||||
|
@ -8,15 +9,17 @@ mod xdg;
|
|||
|
||||
use std::{error::Error, os::fd::AsRawFd, sync::Arc, time::Duration};
|
||||
|
||||
use backend::{winit::WinitData, Backend};
|
||||
use smithay::{
|
||||
backend::{
|
||||
egl::EGLDevice,
|
||||
input::{
|
||||
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputEvent, KeyState,
|
||||
KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent,
|
||||
},
|
||||
renderer::{
|
||||
damage::OutputDamageTracker, element::surface::WaylandSurfaceRenderElement,
|
||||
gles::GlesRenderer,
|
||||
gles::GlesRenderer, ImportDma,
|
||||
},
|
||||
winit::{WinitError, WinitEvent},
|
||||
},
|
||||
|
@ -43,6 +46,7 @@ use smithay::{
|
|||
wayland::{
|
||||
compositor::{CompositorClientState, CompositorState},
|
||||
data_device::DataDeviceState,
|
||||
dmabuf::{DmabufFeedbackBuilder, DmabufState},
|
||||
output::OutputManagerState,
|
||||
shell::xdg::XdgShellState,
|
||||
shm::ShmState,
|
||||
|
@ -51,435 +55,15 @@ use smithay::{
|
|||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut event_loop: EventLoop<Data> = EventLoop::try_new()?;
|
||||
|
||||
let mut display: Display<State> = Display::new()?;
|
||||
|
||||
let socket = ListeningSocketSource::new_auto()?;
|
||||
let socket_name = socket.socket_name().to_os_string();
|
||||
|
||||
let evt_loop_handle = event_loop.handle();
|
||||
|
||||
evt_loop_handle.insert_source(socket, |stream, _metadata, data| {
|
||||
data.display
|
||||
.handle()
|
||||
.insert_client(stream, Arc::new(ClientState::default()))
|
||||
.unwrap();
|
||||
})?;
|
||||
|
||||
evt_loop_handle.insert_source(
|
||||
Generic::new(
|
||||
display.backend().poll_fd().as_raw_fd(),
|
||||
Interest::READ,
|
||||
Mode::Level,
|
||||
),
|
||||
|_readiness, _metadata, data| {
|
||||
data.display.dispatch_clients(&mut data.state)?;
|
||||
Ok(PostAction::Continue)
|
||||
},
|
||||
)?;
|
||||
|
||||
let display_handle = display.handle();
|
||||
|
||||
let mut seat_state = SeatState::<State>::new();
|
||||
let mut seat = seat_state.new_wl_seat(&display_handle, "seat1");
|
||||
|
||||
seat.add_keyboard(Default::default(), 500, 50)?;
|
||||
seat.add_pointer();
|
||||
|
||||
let state = State {
|
||||
loop_signal: event_loop.get_signal(),
|
||||
loop_handle: event_loop.handle(),
|
||||
clock: Clock::<Monotonic>::new()?,
|
||||
compositor_state: CompositorState::new::<State>(&display_handle),
|
||||
data_device_state: DataDeviceState::new::<State>(&display_handle),
|
||||
seat_state,
|
||||
shm_state: ShmState::new::<State>(&display_handle, Vec::new()),
|
||||
space: Space::<Window>::default(),
|
||||
cursor_status: CursorImageStatus::Default,
|
||||
pointer_location: (0.0, 0.0).into(),
|
||||
output_manager_state: OutputManagerState::new_with_xdg_output::<State>(&display_handle),
|
||||
xdg_shell_state: XdgShellState::new::<State>(&display_handle),
|
||||
|
||||
move_mode: false,
|
||||
};
|
||||
|
||||
let mut data = Data { display, state };
|
||||
|
||||
let (mut winit_backend, mut winit_evt_loop) = smithay::backend::winit::init::<GlesRenderer>()?;
|
||||
|
||||
let mode = smithay::output::Mode {
|
||||
size: winit_backend.window_size().physical_size,
|
||||
refresh: 60_000,
|
||||
};
|
||||
|
||||
let physical_properties = smithay::output::PhysicalProperties {
|
||||
size: (0, 0).into(),
|
||||
subpixel: Subpixel::Unknown,
|
||||
make: "Comp make".to_string(),
|
||||
model: "Comp model".to_string(),
|
||||
};
|
||||
|
||||
let output = Output::new("27GL83A".to_string(), physical_properties);
|
||||
|
||||
output.create_global::<State>(&display_handle);
|
||||
|
||||
output.change_current_state(
|
||||
Some(mode),
|
||||
Some(Transform::Flipped180),
|
||||
None,
|
||||
Some((0, 0).into()),
|
||||
);
|
||||
|
||||
output.set_preferred(mode);
|
||||
|
||||
data.state.space.map_output(&output, (0, 0));
|
||||
|
||||
std::env::set_var("WAYLAND_DISPLAY", socket_name);
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
let timer = Timer::immediate();
|
||||
|
||||
let mut damage_tracker = OutputDamageTracker::from_output(&output);
|
||||
|
||||
// TODO: pointer
|
||||
evt_loop_handle.insert_source(timer, move |_instant, _metadata, data| {
|
||||
let display = &mut data.display;
|
||||
let state = &mut data.state;
|
||||
|
||||
let result = winit_evt_loop.dispatch_new_events(|event| {
|
||||
match event {
|
||||
WinitEvent::Resized {
|
||||
size,
|
||||
scale_factor: _,
|
||||
} => {
|
||||
output.change_current_state(
|
||||
Some(smithay::output::Mode {
|
||||
size,
|
||||
refresh: 60_000,
|
||||
}),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
WinitEvent::Focus(_) => {}
|
||||
WinitEvent::Input(input_evt) => match input_evt {
|
||||
// TODO: extract input events
|
||||
// | into separate function
|
||||
|
||||
// InputEvent::DeviceAdded { device } => todo!(),
|
||||
// InputEvent::DeviceRemoved { device } => todo!(),
|
||||
InputEvent::Keyboard { event } => {
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let time = event.time_msec();
|
||||
let press_state = event.state();
|
||||
let mut move_mode = false;
|
||||
let action = seat.get_keyboard().unwrap().input(
|
||||
state,
|
||||
event.key_code(),
|
||||
press_state,
|
||||
serial,
|
||||
time,
|
||||
|_state, _modifiers, keysym| {
|
||||
if press_state == KeyState::Pressed
|
||||
&& keysym.modified_sym() == keysyms::KEY_L
|
||||
{
|
||||
println!("pressed L");
|
||||
FilterResult::Intercept(1)
|
||||
} else if press_state == KeyState::Pressed
|
||||
&& keysym.modified_sym() == keysyms::KEY_K
|
||||
{
|
||||
FilterResult::Intercept(2)
|
||||
} else if press_state == KeyState::Pressed
|
||||
&& keysym.modified_sym() == keysyms::KEY_J
|
||||
{
|
||||
FilterResult::Intercept(3)
|
||||
} else if keysym.modified_sym() == keysyms::KEY_Control_L {
|
||||
match press_state {
|
||||
KeyState::Pressed => {
|
||||
move_mode = true;
|
||||
}
|
||||
KeyState::Released => {
|
||||
move_mode = false;
|
||||
}
|
||||
}
|
||||
FilterResult::Forward
|
||||
} else {
|
||||
FilterResult::Forward
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
state.move_mode = move_mode;
|
||||
|
||||
match action {
|
||||
Some(1) => {
|
||||
std::process::Command::new("alacritty").spawn().unwrap();
|
||||
}
|
||||
Some(2) => {
|
||||
std::process::Command::new("nautilus").spawn().unwrap();
|
||||
}
|
||||
Some(3) => {
|
||||
std::process::Command::new("kitty").spawn().unwrap();
|
||||
}
|
||||
Some(_) => {}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
InputEvent::PointerMotion { event } => {}
|
||||
InputEvent::PointerMotionAbsolute { event } => {
|
||||
let output = state.space.outputs().next().unwrap();
|
||||
let output_geo = state.space.output_geometry(output).unwrap();
|
||||
let pointer_loc =
|
||||
event.position_transformed(output_geo.size) + output_geo.loc.to_f64();
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
|
||||
let surface_under_pointer = state
|
||||
.space
|
||||
.element_under(pointer_loc)
|
||||
.and_then(|(window, location)| {
|
||||
window
|
||||
.surface_under(
|
||||
pointer_loc - location.to_f64(),
|
||||
WindowSurfaceType::ALL,
|
||||
)
|
||||
.map(|(s, p)| (s, p + location))
|
||||
});
|
||||
|
||||
pointer.motion(
|
||||
state,
|
||||
surface_under_pointer,
|
||||
&MotionEvent {
|
||||
location: pointer_loc,
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
InputEvent::PointerButton { event } => {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
let keyboard = seat.get_keyboard().unwrap();
|
||||
|
||||
// A serial is a number sent with a event that is sent back to the
|
||||
// server by the clients in further requests. This allows the server to
|
||||
// keep track of which event caused which requests. It is an AtomicU32
|
||||
// that increments when next_serial is called.
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
|
||||
// Returns which button on the pointer was used.
|
||||
let button = event.button_code();
|
||||
|
||||
// The state, either released or pressed.
|
||||
let button_state = event.state();
|
||||
|
||||
let pointer_loc = pointer.current_location();
|
||||
|
||||
// If the button was clicked, focus on the window below if exists, else
|
||||
// unfocus on windows.
|
||||
if ButtonState::Pressed == button_state {
|
||||
if let Some((window, window_loc)) = state
|
||||
.space
|
||||
.element_under(pointer_loc)
|
||||
.map(|(w, l)| (w.clone(), l))
|
||||
{
|
||||
const BUTTON_LEFT: u32 = 0x110;
|
||||
const BUTTON_RIGHT: u32 = 0x111;
|
||||
if state.move_mode {
|
||||
if event.button_code() == BUTTON_LEFT {
|
||||
crate::xdg::request::move_request_force(
|
||||
state,
|
||||
window.toplevel(),
|
||||
&seat,
|
||||
serial,
|
||||
);
|
||||
return; // TODO: kinda ugly return here
|
||||
} else if event.button_code() == BUTTON_RIGHT {
|
||||
let window_geometry = window.geometry();
|
||||
let window_x = window_loc.x as f64;
|
||||
let window_y = window_loc.y as f64;
|
||||
let window_width = window_geometry.size.w as f64;
|
||||
let window_height = window_geometry.size.h as f64;
|
||||
let half_width = window_x + window_width / 2.0;
|
||||
let half_height = window_y + window_height / 2.0;
|
||||
let full_width = window_x + window_width;
|
||||
let full_height = window_y + window_height;
|
||||
|
||||
println!(
|
||||
"window loc: {}, {} | window size: {}, {}",
|
||||
window_x, window_y, window_width, window_height
|
||||
);
|
||||
|
||||
let edges = match pointer_loc {
|
||||
Point { x, y, .. }
|
||||
if (window_x..=half_width).contains(&x)
|
||||
&& (window_y..=half_height).contains(&y) =>
|
||||
{
|
||||
ResizeEdge::TopLeft
|
||||
}
|
||||
Point { x, y, .. }
|
||||
if (half_width..=full_width).contains(&x)
|
||||
&& (window_y..=half_height).contains(&y) =>
|
||||
{
|
||||
ResizeEdge::TopRight
|
||||
}
|
||||
Point { x, y, .. }
|
||||
if (window_x..=half_width).contains(&x)
|
||||
&& (half_height..=full_height).contains(&y) =>
|
||||
{
|
||||
ResizeEdge::BottomLeft
|
||||
}
|
||||
Point { x, y, .. }
|
||||
if (half_width..=full_width).contains(&x)
|
||||
&& (half_height..=full_height).contains(&y) =>
|
||||
{
|
||||
ResizeEdge::BottomRight
|
||||
}
|
||||
_ => ResizeEdge::None,
|
||||
};
|
||||
|
||||
crate::xdg::request::resize_request_force(
|
||||
state,
|
||||
window.toplevel(),
|
||||
&seat,
|
||||
serial,
|
||||
edges,
|
||||
BUTTON_RIGHT,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Move window to top of stack.
|
||||
state.space.raise_element(&window, true);
|
||||
|
||||
// Focus on window.
|
||||
keyboard.set_focus(
|
||||
state,
|
||||
Some(window.toplevel().wl_surface().clone()),
|
||||
serial,
|
||||
);
|
||||
state.space.elements().for_each(|window| {
|
||||
window.toplevel().send_configure();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
state.space.elements().for_each(|window| {
|
||||
window.set_activated(false);
|
||||
window.toplevel().send_configure();
|
||||
});
|
||||
keyboard.set_focus(state, None, serial);
|
||||
}
|
||||
};
|
||||
|
||||
// Send the button event to the client.
|
||||
pointer.button(
|
||||
state,
|
||||
&ButtonEvent {
|
||||
button,
|
||||
state: button_state,
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
InputEvent::PointerAxis { event } => {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
|
||||
let source = event.source();
|
||||
|
||||
let horizontal_amount =
|
||||
event.amount(Axis::Horizontal).unwrap_or_else(|| {
|
||||
event.amount_discrete(Axis::Horizontal).unwrap() * 3.0
|
||||
});
|
||||
|
||||
let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| {
|
||||
event.amount_discrete(Axis::Vertical).unwrap() * 3.0
|
||||
});
|
||||
|
||||
let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal);
|
||||
let vertical_amount_discrete = event.amount_discrete(Axis::Vertical);
|
||||
|
||||
let mut frame = AxisFrame::new(event.time_msec()).source(source);
|
||||
|
||||
if horizontal_amount != 0.0 {
|
||||
frame = frame.value(Axis::Horizontal, horizontal_amount);
|
||||
if let Some(discrete) = horizontal_amount_discrete {
|
||||
frame = frame.discrete(Axis::Horizontal, discrete as i32);
|
||||
}
|
||||
} else if 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.discrete(Axis::Vertical, discrete as i32);
|
||||
}
|
||||
} else if source == AxisSource::Finger {
|
||||
frame = frame.stop(Axis::Vertical);
|
||||
}
|
||||
|
||||
println!("axisframe: {:?}", frame);
|
||||
pointer.axis(state, frame);
|
||||
}
|
||||
// TODO: rest of the InputEvents
|
||||
_ => (),
|
||||
},
|
||||
WinitEvent::Refresh => {}
|
||||
}
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(_) => {}
|
||||
Err(WinitError::WindowClosed) => {
|
||||
state.loop_signal.stop();
|
||||
}
|
||||
};
|
||||
|
||||
winit_backend.bind().unwrap();
|
||||
|
||||
let scale = Scale::from(output.current_scale().fractional_scale());
|
||||
let cursor_pos = state.pointer_location;
|
||||
let _cursor_pos_scaled: Point<i32, Physical> = cursor_pos.to_physical(scale).to_i32_round();
|
||||
|
||||
space::render_output::<_, WaylandSurfaceRenderElement<GlesRenderer>, _, _>(
|
||||
&output,
|
||||
winit_backend.renderer(),
|
||||
1.0,
|
||||
0,
|
||||
[&state.space],
|
||||
&[],
|
||||
&mut damage_tracker,
|
||||
[0.1, 0.1, 0.1, 1.0],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
winit_backend.submit(None).unwrap();
|
||||
|
||||
state.space.elements().for_each(|window| {
|
||||
window.send_frame(
|
||||
&output,
|
||||
start_time.elapsed(),
|
||||
Some(Duration::ZERO),
|
||||
|_, _| Some(output.clone()),
|
||||
)
|
||||
});
|
||||
|
||||
state.space.refresh();
|
||||
|
||||
display.flush_clients().unwrap();
|
||||
|
||||
TimeoutAction::ToDuration(Duration::from_millis(16))
|
||||
})?;
|
||||
|
||||
event_loop.run(None, &mut data, |_data| {})?;
|
||||
crate::backend::winit::run_winit()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
pub struct State<B: Backend> {
|
||||
pub backend_data: B,
|
||||
pub loop_signal: LoopSignal,
|
||||
pub loop_handle: LoopHandle<'static, Data>,
|
||||
pub loop_handle: LoopHandle<'static, CalloopData>,
|
||||
pub clock: Clock<Monotonic>,
|
||||
pub compositor_state: CompositorState,
|
||||
pub data_device_state: DataDeviceState,
|
||||
|
@ -494,9 +78,9 @@ pub struct State {
|
|||
pub move_mode: bool,
|
||||
}
|
||||
|
||||
pub struct Data {
|
||||
pub display: Display<State>,
|
||||
pub state: State,
|
||||
pub struct CalloopData {
|
||||
pub display: Display<State<WinitData>>,
|
||||
pub state: State<WinitData>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
0
src/tag.rs
Normal file
0
src/tag.rs
Normal file
|
@ -2,7 +2,7 @@ use std::cell::RefCell;
|
|||
|
||||
use smithay::{reexports::wayland_server::protocol::wl_surface::WlSurface, wayland::compositor};
|
||||
|
||||
use crate::State;
|
||||
use crate::{backend::Backend, State};
|
||||
|
||||
use self::window_state::{Float, WindowState};
|
||||
|
||||
|
@ -22,7 +22,7 @@ pub trait SurfaceState: Default + 'static {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn toggle_floating(state: &mut State, wl_surface: &WlSurface) {
|
||||
pub fn toggle_floating<B: Backend>(state: &mut State<B>, wl_surface: &WlSurface) {
|
||||
WindowState::with_state(wl_surface, |window_state| {
|
||||
let window = state
|
||||
.space
|
||||
|
|
|
@ -6,14 +6,15 @@ use smithay::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
backend::Backend,
|
||||
grab::{move_grab::MoveSurfaceGrab, resize_grab::ResizeSurfaceGrab},
|
||||
State,
|
||||
};
|
||||
|
||||
pub fn move_request(
|
||||
state: &mut State,
|
||||
pub fn move_request<B: Backend>(
|
||||
state: &mut State<B>,
|
||||
surface: &ToplevelSurface,
|
||||
seat: &Seat<State>,
|
||||
seat: &Seat<State<B>>,
|
||||
serial: smithay::utils::Serial,
|
||||
) {
|
||||
println!("move_request started");
|
||||
|
@ -45,10 +46,10 @@ pub fn move_request(
|
|||
}
|
||||
|
||||
// TODO: see how this interacts with drag and drop and other grabs
|
||||
pub fn move_request_force(
|
||||
state: &mut State,
|
||||
pub fn move_request_force<B: Backend>(
|
||||
state: &mut State<B>,
|
||||
surface: &ToplevelSurface,
|
||||
seat: &Seat<State>,
|
||||
seat: &Seat<State<B>>,
|
||||
serial: smithay::utils::Serial,
|
||||
) {
|
||||
println!("move_request_force started");
|
||||
|
@ -82,10 +83,10 @@ pub fn move_request_force(
|
|||
pointer.set_grab(state, grab, serial, Focus::Clear);
|
||||
}
|
||||
|
||||
pub fn resize_request(
|
||||
state: &mut State,
|
||||
pub fn resize_request<B: Backend>(
|
||||
state: &mut State<B>,
|
||||
surface: &ToplevelSurface,
|
||||
seat: &Seat<State>,
|
||||
seat: &Seat<State<B>>,
|
||||
serial: smithay::utils::Serial,
|
||||
edges: xdg_toplevel::ResizeEdge,
|
||||
button_used: u32,
|
||||
|
@ -124,10 +125,10 @@ pub fn resize_request(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resize_request_force(
|
||||
state: &mut State,
|
||||
pub fn resize_request_force<B: Backend>(
|
||||
state: &mut State<B>,
|
||||
surface: &ToplevelSurface,
|
||||
seat: &Seat<State>,
|
||||
seat: &Seat<State<B>>,
|
||||
serial: smithay::utils::Serial,
|
||||
edges: xdg_toplevel::ResizeEdge,
|
||||
button_used: u32,
|
||||
|
|
Loading…
Reference in a new issue