parent
41e865c8d3
commit
0b94ae1eb8
8 changed files with 239 additions and 65 deletions
|
|
@ -350,11 +350,6 @@ impl<S: X11Selection> Dispatch<WlPointer, Entity> for InnerServerState<S> {
|
|||
_: &DisplayHandle,
|
||||
_: &mut wayland_server::DataInit<'_, Self>,
|
||||
) {
|
||||
let c_pointer = state
|
||||
.world
|
||||
.get::<&client::wl_pointer::WlPointer>(*entity)
|
||||
.unwrap();
|
||||
|
||||
match request {
|
||||
Request::<WlPointer>::SetCursor {
|
||||
serial,
|
||||
|
|
@ -362,6 +357,11 @@ impl<S: X11Selection> Dispatch<WlPointer, Entity> for InnerServerState<S> {
|
|||
hotspot_y,
|
||||
surface,
|
||||
} => {
|
||||
let c_pointer = state
|
||||
.world
|
||||
.get::<&client::wl_pointer::WlPointer>(*entity)
|
||||
.unwrap();
|
||||
|
||||
let c_surface = surface.and_then(|s| {
|
||||
let e = s.data().copied()?;
|
||||
Some(
|
||||
|
|
@ -374,9 +374,11 @@ impl<S: X11Selection> Dispatch<WlPointer, Entity> for InnerServerState<S> {
|
|||
c_pointer.set_cursor(serial, c_surface.as_deref(), hotspot_x, hotspot_y);
|
||||
}
|
||||
Request::<WlPointer>::Release => {
|
||||
c_pointer.release();
|
||||
drop(c_pointer);
|
||||
let _ = state.world.despawn(*entity);
|
||||
let (client, _) = state
|
||||
.world
|
||||
.remove::<(client::wl_pointer::WlPointer, WlPointer)>(*entity)
|
||||
.unwrap();
|
||||
client.release();
|
||||
}
|
||||
_ => warn!("unhandled cursor request: {request:?}"),
|
||||
}
|
||||
|
|
@ -395,12 +397,11 @@ impl<S: X11Selection> Dispatch<WlKeyboard, Entity> for InnerServerState<S> {
|
|||
) {
|
||||
match request {
|
||||
Request::<WlKeyboard>::Release => {
|
||||
state
|
||||
let (client, _) = state
|
||||
.world
|
||||
.get::<&client::wl_keyboard::WlKeyboard>(*entity)
|
||||
.unwrap()
|
||||
.release();
|
||||
state.world.despawn(*entity).unwrap();
|
||||
.remove::<(client::wl_keyboard::WlKeyboard, WlKeyboard)>(*entity)
|
||||
.unwrap();
|
||||
client.release();
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
|
@ -443,16 +444,15 @@ impl<S: X11Selection> Dispatch<WlSeat, Entity> for InnerServerState<S> {
|
|||
) {
|
||||
match request {
|
||||
Request::<WlSeat>::GetPointer { id } => {
|
||||
let new_entity = state.world.reserve_entity();
|
||||
let client = {
|
||||
state
|
||||
.world
|
||||
.get::<&client::wl_seat::WlSeat>(*entity)
|
||||
.unwrap()
|
||||
.get_pointer(&state.qh, new_entity)
|
||||
.get_pointer(&state.qh, *entity)
|
||||
};
|
||||
let server = data_init.init(id, new_entity);
|
||||
state.world.spawn_at(new_entity, (client, server));
|
||||
let server = data_init.init(id, *entity);
|
||||
state.world.insert(*entity, (client, server)).unwrap();
|
||||
}
|
||||
Request::<WlSeat>::GetKeyboard { id } => {
|
||||
let client = {
|
||||
|
|
|
|||
|
|
@ -435,6 +435,8 @@ impl Event for client::wl_seat::Event {
|
|||
}
|
||||
|
||||
struct PendingEnter(client::wl_pointer::Event);
|
||||
struct CurrentSurface(Entity);
|
||||
pub struct LastClickSerial(pub client::wl_seat::WlSeat, pub u32);
|
||||
|
||||
impl Event for client::wl_pointer::Event {
|
||||
fn handle<C: XConnection>(self, target: Entity, state: &mut ServerState<C>) {
|
||||
|
|
@ -459,7 +461,8 @@ impl Event for client::wl_pointer::Event {
|
|||
let mut cmd = CommandBuffer::new();
|
||||
let pending_enter = state.world.remove_one::<PendingEnter>(target).ok();
|
||||
let server = state.world.get::<&WlPointer>(target).unwrap();
|
||||
let mut query = surface.data().copied().and_then(|e| {
|
||||
let surface_entity = surface.data().copied();
|
||||
let mut query = surface_entity.and_then(|e| {
|
||||
state
|
||||
.world
|
||||
.query_one::<(&WlSurface, &SurfaceRole, &SurfaceScaleFactor, &x::Window)>(e)
|
||||
|
|
@ -481,6 +484,7 @@ impl Event for client::wl_pointer::Event {
|
|||
if !surface_is_popup {
|
||||
state.last_hovered = Some(*window);
|
||||
}
|
||||
cmd.insert(target, (CurrentSurface(surface_entity.unwrap()),));
|
||||
};
|
||||
|
||||
if !surface_is_popup {
|
||||
|
|
@ -512,11 +516,11 @@ impl Event for client::wl_pointer::Event {
|
|||
}
|
||||
client::wl_pointer::Event::Leave { serial, surface } => {
|
||||
let _ = state.world.remove_one::<PendingEnter>(target);
|
||||
let _ = state.world.remove_one::<CurrentSurface>(target);
|
||||
if !surface.is_alive() {
|
||||
return;
|
||||
}
|
||||
debug!("leaving surface ({serial})");
|
||||
let _ = state.world.remove_one::<PendingEnter>(target);
|
||||
if let Some(surface) = surface
|
||||
.data()
|
||||
.copied()
|
||||
|
|
@ -584,17 +588,39 @@ impl Event for client::wl_pointer::Event {
|
|||
}
|
||||
}
|
||||
}
|
||||
client::wl_pointer::Event::Button {
|
||||
serial,
|
||||
time,
|
||||
button,
|
||||
state: button_state,
|
||||
} => {
|
||||
let mut cmd = CommandBuffer::new();
|
||||
let (server, seat, CurrentSurface(surface)) = state
|
||||
.world
|
||||
.query_one_mut::<(&WlPointer, &client::wl_seat::WlSeat, &CurrentSurface)>(
|
||||
target,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// from linux/input-event-codes.h
|
||||
mod button_codes {
|
||||
pub const LEFT: u32 = 0x110;
|
||||
}
|
||||
|
||||
if button_state == WEnum::Value(client::wl_pointer::ButtonState::Pressed)
|
||||
&& button == button_codes::LEFT
|
||||
{
|
||||
cmd.insert(*surface, (LastClickSerial(seat.clone(), serial),));
|
||||
}
|
||||
|
||||
server.button(serial, time, button, convert_wenum(button_state));
|
||||
cmd.run_on(&mut state.world);
|
||||
}
|
||||
_ => {
|
||||
let server = state.world.get::<&WlPointer>(target).unwrap();
|
||||
simple_event_shunt! {
|
||||
server, self => [
|
||||
Frame,
|
||||
Button {
|
||||
serial,
|
||||
time,
|
||||
button,
|
||||
|state| convert_wenum(state)
|
||||
},
|
||||
Axis {
|
||||
time,
|
||||
|axis| convert_wenum(axis),
|
||||
|
|
|
|||
|
|
@ -1091,6 +1091,31 @@ impl<S: X11Selection + 'static> InnerServerState<S> {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn move_window(&mut self, window: x::Window) {
|
||||
let Some(data) = self
|
||||
.windows
|
||||
.get(&window)
|
||||
.copied()
|
||||
.and_then(|e| self.world.entity(e).ok())
|
||||
else {
|
||||
warn!("Requested move of unknown window {window:?}");
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(last_click_data) = data.get::<&LastClickSerial>() else {
|
||||
warn!("Requested move of window {window:?} but we don't have a click serial for it");
|
||||
return;
|
||||
};
|
||||
|
||||
let role = data.get::<&SurfaceRole>();
|
||||
let Some(SurfaceRole::Toplevel(Some(data))) = role.as_deref() else {
|
||||
warn!("Requested move of non toplevel {window:?} ({role:?})");
|
||||
return;
|
||||
};
|
||||
|
||||
data.toplevel._move(&last_click_data.0, last_click_data.1);
|
||||
}
|
||||
|
||||
pub fn destroy_window(&mut self, window: x::Window) {
|
||||
if let Some(id) = self.windows.remove(&window) {
|
||||
self.world.remove::<(x::Window, WindowData)>(id).unwrap();
|
||||
|
|
|
|||
|
|
@ -509,6 +509,28 @@ impl XState {
|
|||
x if x == self.atoms.active_win => {
|
||||
server_state.activate_window(e.window());
|
||||
}
|
||||
x if x == self.atoms.moveresize => {
|
||||
let x::ClientMessageData::Data32(data) = e.data() else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let (_x_root, _y_root) = (data[0], data[1]);
|
||||
let Ok(direction) = MoveResizeDirection::try_from(data[2]) else {
|
||||
warn!("unknown direction for _NET_WM_MOVERESIZE: {}", data[2]);
|
||||
continue;
|
||||
};
|
||||
let button = data[3];
|
||||
// XXX: This can technically be driven by keyboard events and other mouse buttons as well,
|
||||
// but I haven't found an application that does this yet. We'll cross that bridge when we get to it.
|
||||
if button != 1 {
|
||||
warn!("Attempted move/resize of {:?} with non left click button ({button})", e.window());
|
||||
continue;
|
||||
}
|
||||
|
||||
if matches!(direction, MoveResizeDirection::Move) {
|
||||
server_state.move_window(e.window());
|
||||
}
|
||||
}
|
||||
t => warn!("unrecognized message: {t:?}"),
|
||||
},
|
||||
xcb::Event::X(x::Event::MappingNotify(_)) => {}
|
||||
|
|
@ -933,6 +955,7 @@ xcb::atoms_struct! {
|
|||
xsettings => b"_XSETTINGS_S0" only_if_exists = false,
|
||||
xsettings_settings => b"_XSETTINGS_SETTINGS" only_if_exists = false,
|
||||
primary => b"PRIMARY" only_if_exists = false,
|
||||
moveresize => b"_NET_WM_MOVERESIZE" only_if_exists = false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1076,24 +1099,13 @@ mod motif {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, num_enum::TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum Decorations {
|
||||
Client = 0,
|
||||
Server = 1,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for Decorations {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: u32) -> Result<Self, ()> {
|
||||
match value {
|
||||
0 => Ok(Self::Client),
|
||||
1 => Ok(Self::Server),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Decorations> for zxdg_toplevel_decoration_v1::Mode {
|
||||
fn from(value: Decorations) -> Self {
|
||||
match value {
|
||||
|
|
@ -1104,42 +1116,37 @@ mod motif {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, num_enum::TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum SetState {
|
||||
Remove,
|
||||
Add,
|
||||
Toggle,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for SetState {
|
||||
type Error = ();
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(Self::Remove),
|
||||
1 => Ok(Self::Add),
|
||||
2 => Ok(Self::Toggle),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum WmState {
|
||||
Withdrawn = 0,
|
||||
Normal = 1,
|
||||
Iconic = 3,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for WmState {
|
||||
type Error = ();
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(Self::Withdrawn),
|
||||
1 => Ok(Self::Normal),
|
||||
3 => Ok(Self::Iconic),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Copy, Clone, num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum MoveResizeDirection {
|
||||
SizeTopLeft,
|
||||
SizeTop,
|
||||
SizeTopRight,
|
||||
SizeRight,
|
||||
SizeBottomRight,
|
||||
SizeBottom,
|
||||
SizeBottomLeft,
|
||||
SizeLeft,
|
||||
Move,
|
||||
SizeKeyboard,
|
||||
MoveKeyboard,
|
||||
Cancel,
|
||||
}
|
||||
|
||||
pub struct RealConnection {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue