Add pointer gestures support
This commit is contained in:
parent
e7e9b768c8
commit
c68625ff78
4 changed files with 402 additions and 304 deletions
687
src/input/mod.rs
687
src/input/mod.rs
|
|
@ -18,13 +18,19 @@ use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::Inp
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::{
|
backend::input::{
|
||||||
Axis, AxisSource, Device, DeviceCapability, InputBackend, InputEvent, KeyState,
|
Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent, GestureEndEvent,
|
||||||
PointerAxisEvent,
|
GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend, InputEvent,
|
||||||
|
KeyState, PointerAxisEvent,
|
||||||
},
|
},
|
||||||
desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType},
|
desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType},
|
||||||
input::{
|
input::{
|
||||||
keyboard::{keysyms, FilterResult, KeysymHandle, XkbConfig},
|
keyboard::{keysyms, FilterResult, KeysymHandle, XkbConfig},
|
||||||
pointer::{AxisFrame, ButtonEvent, CursorImageStatus, MotionEvent, RelativeMotionEvent},
|
pointer::{
|
||||||
|
AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent,
|
||||||
|
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
||||||
|
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
|
||||||
|
RelativeMotionEvent,
|
||||||
|
},
|
||||||
Seat, SeatState,
|
Seat, SeatState,
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -220,14 +226,15 @@ impl State {
|
||||||
use smithay::backend::input::KeyboardKeyEvent;
|
use smithay::backend::input::KeyboardKeyEvent;
|
||||||
|
|
||||||
let loop_handle = self.common.event_loop_handle.clone();
|
let loop_handle = self.common.event_loop_handle.clone();
|
||||||
let device = event.device();
|
|
||||||
|
|
||||||
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
||||||
|
let userdata = seat.user_data();
|
||||||
|
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
let workspace = self.common.shell.active_space_mut(¤t_output);
|
let workspace = self.common.shell.active_space_mut(¤t_output);
|
||||||
let shortcuts_inhibited = workspace
|
let shortcuts_inhibited = workspace
|
||||||
.focus_stack
|
.focus_stack
|
||||||
.get(seat)
|
.get(&seat)
|
||||||
.last()
|
.last()
|
||||||
.and_then(|window| {
|
.and_then(|window| {
|
||||||
window.wl_surface().and_then(|surface| {
|
window.wl_surface().and_then(|surface| {
|
||||||
|
|
@ -237,16 +244,13 @@ impl State {
|
||||||
.map(|inhibitor| inhibitor.is_active())
|
.map(|inhibitor| inhibitor.is_active())
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
let userdata = seat.user_data();
|
let keycode = event.key_code();
|
||||||
let devices = userdata.get::<Devices>().unwrap();
|
let state = event.state();
|
||||||
if devices.has_device(&device) {
|
trace!(?keycode, ?state, "key");
|
||||||
let keycode = event.key_code();
|
|
||||||
let state = event.state();
|
|
||||||
trace!(?keycode, ?state, "key");
|
|
||||||
|
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let time = Event::time_msec(&event);
|
let time = Event::time_msec(&event);
|
||||||
if let Some((action, pattern)) = seat
|
if let Some((action, pattern)) = seat
|
||||||
.get_keyboard()
|
.get_keyboard()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.input(
|
.input(
|
||||||
|
|
@ -366,7 +370,7 @@ impl State {
|
||||||
// Pass keys to debug interface, if it has focus
|
// Pass keys to debug interface, if it has focus
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
{
|
{
|
||||||
if data.common.seats().position(|x| x == seat).unwrap() == 0
|
if data.common.seats().position(|x| x == &seat).unwrap() == 0
|
||||||
&& data.common.egui.active
|
&& data.common.egui.active
|
||||||
{
|
{
|
||||||
if data.common.egui.state.wants_keyboard() {
|
if data.common.egui.state.wants_keyboard() {
|
||||||
|
|
@ -427,223 +431,224 @@ impl State {
|
||||||
)
|
)
|
||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
self.handle_action(action, seat, serial, time, pattern, None)
|
self.handle_action(action, &seat, serial, time, pattern, None)
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PointerMotion { event, .. } => {
|
InputEvent::PointerMotion { event, .. } => {
|
||||||
use smithay::backend::input::PointerMotionEvent;
|
use smithay::backend::input::PointerMotionEvent;
|
||||||
|
|
||||||
let device = event.device();
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
||||||
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
|
let current_output = seat.active_output();
|
||||||
let userdata = seat.user_data();
|
|
||||||
let devices = userdata.get::<Devices>().unwrap();
|
|
||||||
if devices.has_device(&device) {
|
|
||||||
let current_output = seat.active_output();
|
|
||||||
|
|
||||||
let mut position = seat.get_pointer().unwrap().current_location();
|
let mut position = seat.get_pointer().unwrap().current_location();
|
||||||
position += event.delta();
|
position += event.delta();
|
||||||
|
|
||||||
let output = self
|
let output = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.outputs()
|
.outputs()
|
||||||
.find(|output| output.geometry().to_f64().contains(position))
|
.find(|output| output.geometry().to_f64().contains(position))
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or(current_output.clone());
|
.unwrap_or(current_output.clone());
|
||||||
if output != current_output {
|
if output != current_output {
|
||||||
for session in sessions_for_output(&self.common, ¤t_output) {
|
for session in sessions_for_output(&self.common, ¤t_output) {
|
||||||
session.cursor_leave(seat, InputType::Pointer);
|
session.cursor_leave(&seat, InputType::Pointer);
|
||||||
}
|
|
||||||
|
|
||||||
for session in sessions_for_output(&self.common, &output) {
|
|
||||||
session.cursor_enter(seat, InputType::Pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
seat.set_active_output(&output);
|
|
||||||
}
|
}
|
||||||
let output_geometry = output.geometry();
|
|
||||||
|
|
||||||
position.x = (output_geometry.loc.x as f64)
|
|
||||||
.max(position.x)
|
|
||||||
.min((output_geometry.loc.x + output_geometry.size.w) as f64);
|
|
||||||
position.y = (output_geometry.loc.y as f64)
|
|
||||||
.max(position.y)
|
|
||||||
.min((output_geometry.loc.y + output_geometry.size.h) as f64);
|
|
||||||
|
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
|
||||||
let relative_pos = self.common.shell.map_global_to_space(position, &output);
|
|
||||||
let overview = self.common.shell.overview_mode();
|
|
||||||
let workspace = self.common.shell.workspaces.active_mut(&output);
|
|
||||||
let under = State::surface_under(
|
|
||||||
position,
|
|
||||||
relative_pos,
|
|
||||||
&output,
|
|
||||||
output_geometry,
|
|
||||||
&self.common.shell.override_redirect_windows,
|
|
||||||
overview,
|
|
||||||
workspace,
|
|
||||||
);
|
|
||||||
|
|
||||||
for session in sessions_for_output(&self.common, &output) {
|
for session in sessions_for_output(&self.common, &output) {
|
||||||
if let Some((geometry, offset)) = seat.cursor_geometry(
|
session.cursor_enter(&seat, InputType::Pointer);
|
||||||
position.to_buffer(
|
|
||||||
output.current_scale().fractional_scale(),
|
|
||||||
output.current_transform(),
|
|
||||||
&output.geometry().size.to_f64(),
|
|
||||||
),
|
|
||||||
self.common.clock.now(),
|
|
||||||
) {
|
|
||||||
session.cursor_info(seat, InputType::Pointer, geometry, offset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let ptr = seat.get_pointer().unwrap();
|
|
||||||
ptr.motion(
|
seat.set_active_output(&output);
|
||||||
self,
|
}
|
||||||
under.clone(),
|
let output_geometry = output.geometry();
|
||||||
&MotionEvent {
|
|
||||||
location: position,
|
position.x = (output_geometry.loc.x as f64)
|
||||||
serial,
|
.max(position.x)
|
||||||
time: event.time_msec(),
|
.min((output_geometry.loc.x + output_geometry.size.w) as f64);
|
||||||
},
|
position.y = (output_geometry.loc.y as f64)
|
||||||
);
|
.max(position.y)
|
||||||
ptr.relative_motion(
|
.min((output_geometry.loc.y + output_geometry.size.h) as f64);
|
||||||
self,
|
|
||||||
under,
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
&RelativeMotionEvent {
|
let relative_pos = self.common.shell.map_global_to_space(position, &output);
|
||||||
delta: event.delta(),
|
let overview = self.common.shell.overview_mode();
|
||||||
delta_unaccel: event.delta_unaccel(),
|
let workspace = self.common.shell.workspaces.active_mut(&output);
|
||||||
utime: event.time(),
|
let under = State::surface_under(
|
||||||
},
|
position,
|
||||||
);
|
relative_pos,
|
||||||
#[cfg(feature = "debug")]
|
&output,
|
||||||
if self.common.seats().position(|x| x == seat).unwrap() == 0 {
|
output_geometry,
|
||||||
let location = if let Some(output) = self.common.shell.outputs.first() {
|
&self.common.shell.override_redirect_windows,
|
||||||
self.common
|
overview,
|
||||||
.shell
|
workspace,
|
||||||
.map_global_to_space(position, output)
|
);
|
||||||
.to_i32_round()
|
|
||||||
} else {
|
for session in sessions_for_output(&self.common, &output) {
|
||||||
position.to_i32_round()
|
if let Some((geometry, offset)) = seat.cursor_geometry(
|
||||||
};
|
position.to_buffer(
|
||||||
self.common.egui.state.handle_pointer_motion(location);
|
output.current_scale().fractional_scale(),
|
||||||
|
output.current_transform(),
|
||||||
|
&output.geometry().size.to_f64(),
|
||||||
|
),
|
||||||
|
self.common.clock.now(),
|
||||||
|
) {
|
||||||
|
session.cursor_info(&seat, InputType::Pointer, geometry, offset);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
let ptr = seat.get_pointer().unwrap();
|
||||||
|
ptr.motion(
|
||||||
|
self,
|
||||||
|
under.clone(),
|
||||||
|
&MotionEvent {
|
||||||
|
location: position,
|
||||||
|
serial,
|
||||||
|
time: event.time_msec(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
ptr.relative_motion(
|
||||||
|
self,
|
||||||
|
under,
|
||||||
|
&RelativeMotionEvent {
|
||||||
|
delta: event.delta(),
|
||||||
|
delta_unaccel: event.delta_unaccel(),
|
||||||
|
utime: event.time(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
if self.common.seats().position(|x| x == &seat).unwrap() == 0 {
|
||||||
|
let location = if let Some(output) = self.common.shell.outputs.first() {
|
||||||
|
self.common
|
||||||
|
.shell
|
||||||
|
.map_global_to_space(position, output)
|
||||||
|
.to_i32_round()
|
||||||
|
} else {
|
||||||
|
position.to_i32_round()
|
||||||
|
};
|
||||||
|
self.common.egui.state.handle_pointer_motion(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PointerMotionAbsolute { event, .. } => {
|
InputEvent::PointerMotionAbsolute { event, .. } => {
|
||||||
let device = event.device();
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
||||||
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
|
let output = seat.active_output();
|
||||||
let userdata = seat.user_data();
|
let geometry = output.geometry();
|
||||||
let devices = userdata.get::<Devices>().unwrap();
|
let position = geometry.loc.to_f64()
|
||||||
if devices.has_device(&device) {
|
+ smithay::backend::input::AbsolutePositionEvent::position_transformed(
|
||||||
let output = seat.active_output();
|
&event,
|
||||||
let geometry = output.geometry();
|
geometry.size,
|
||||||
let position = geometry.loc.to_f64()
|
|
||||||
+ smithay::backend::input::AbsolutePositionEvent::position_transformed(
|
|
||||||
&event,
|
|
||||||
geometry.size,
|
|
||||||
);
|
|
||||||
let relative_pos = self.common.shell.map_global_to_space(position, &output);
|
|
||||||
let overview = self.common.shell.overview_mode();
|
|
||||||
let workspace = self.common.shell.workspaces.active_mut(&output);
|
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
|
||||||
let under = State::surface_under(
|
|
||||||
position,
|
|
||||||
relative_pos,
|
|
||||||
&output,
|
|
||||||
geometry,
|
|
||||||
&self.common.shell.override_redirect_windows,
|
|
||||||
overview,
|
|
||||||
workspace,
|
|
||||||
);
|
);
|
||||||
|
let relative_pos = self.common.shell.map_global_to_space(position, &output);
|
||||||
|
let overview = self.common.shell.overview_mode();
|
||||||
|
let workspace = self.common.shell.workspaces.active_mut(&output);
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
let under = State::surface_under(
|
||||||
|
position,
|
||||||
|
relative_pos,
|
||||||
|
&output,
|
||||||
|
geometry,
|
||||||
|
&self.common.shell.override_redirect_windows,
|
||||||
|
overview,
|
||||||
|
workspace,
|
||||||
|
);
|
||||||
|
|
||||||
for session in sessions_for_output(&self.common, &output) {
|
for session in sessions_for_output(&self.common, &output) {
|
||||||
if let Some((geometry, offset)) = seat.cursor_geometry(
|
if let Some((geometry, offset)) = seat.cursor_geometry(
|
||||||
position.to_buffer(
|
position.to_buffer(
|
||||||
output.current_scale().fractional_scale(),
|
output.current_scale().fractional_scale(),
|
||||||
output.current_transform(),
|
output.current_transform(),
|
||||||
&output.geometry().size.to_f64(),
|
&output.geometry().size.to_f64(),
|
||||||
),
|
),
|
||||||
self.common.clock.now(),
|
self.common.clock.now(),
|
||||||
) {
|
) {
|
||||||
session.cursor_info(seat, InputType::Pointer, geometry, offset);
|
session.cursor_info(&seat, InputType::Pointer, geometry, offset);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
seat.get_pointer().unwrap().motion(
|
}
|
||||||
self,
|
seat.get_pointer().unwrap().motion(
|
||||||
under,
|
self,
|
||||||
&MotionEvent {
|
under,
|
||||||
location: position,
|
&MotionEvent {
|
||||||
serial,
|
location: position,
|
||||||
time: event.time_msec(),
|
serial,
|
||||||
},
|
time: event.time_msec(),
|
||||||
);
|
},
|
||||||
#[cfg(feature = "debug")]
|
);
|
||||||
if self.common.seats().position(|x| x == seat).unwrap() == 0 {
|
#[cfg(feature = "debug")]
|
||||||
let location = if let Some(output) = self.common.shell.outputs.first() {
|
if self.common.seats().position(|x| x == &seat).unwrap() == 0 {
|
||||||
self.common
|
let location = if let Some(output) = self.common.shell.outputs.first() {
|
||||||
.shell
|
self.common
|
||||||
.map_global_to_space(position, output)
|
.shell
|
||||||
.to_i32_round()
|
.map_global_to_space(position, output)
|
||||||
} else {
|
.to_i32_round()
|
||||||
position.to_i32_round()
|
} else {
|
||||||
};
|
position.to_i32_round()
|
||||||
self.common.egui.state.handle_pointer_motion(location);
|
};
|
||||||
}
|
self.common.egui.state.handle_pointer_motion(location);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PointerButton { event, .. } => {
|
InputEvent::PointerButton { event, .. } => {
|
||||||
use smithay::backend::input::{ButtonState, PointerButtonEvent};
|
use smithay::backend::input::{ButtonState, PointerButtonEvent};
|
||||||
|
|
||||||
let device = event.device();
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
||||||
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
|
#[cfg(feature = "debug")]
|
||||||
let userdata = seat.user_data();
|
if self.common.seats().position(|x| x == &seat).unwrap() == 0
|
||||||
let devices = userdata.get::<Devices>().unwrap();
|
&& self.common.egui.active
|
||||||
if devices.has_device(&device) {
|
{
|
||||||
#[cfg(feature = "debug")]
|
if self.common.egui.state.wants_pointer() {
|
||||||
if self.common.seats().position(|x| x == seat).unwrap() == 0
|
if let Some(button) = event.button() {
|
||||||
&& self.common.egui.active
|
self.common.egui.state.handle_pointer_button(
|
||||||
{
|
button,
|
||||||
if self.common.egui.state.wants_pointer() {
|
event.state() == ButtonState::Pressed,
|
||||||
if let Some(button) = event.button() {
|
);
|
||||||
self.common.egui.state.handle_pointer_button(
|
|
||||||
button,
|
|
||||||
event.state() == ButtonState::Pressed,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let button = event.button_code();
|
let button = event.button_code();
|
||||||
if event.state() == ButtonState::Pressed {
|
if event.state() == ButtonState::Pressed {
|
||||||
// change the keyboard focus unless the pointer or keyboard is grabbed
|
// change the keyboard focus unless the pointer or keyboard is grabbed
|
||||||
// We test for any matching surface type here but always use the root
|
// We test for any matching surface type here but always use the root
|
||||||
// (in case of a window the toplevel) surface for the focus.
|
// (in case of a window the toplevel) surface for the focus.
|
||||||
// see: https://gitlab.freedesktop.org/wayland/wayland/-/issues/294
|
// see: https://gitlab.freedesktop.org/wayland/wayland/-/issues/294
|
||||||
if !seat.get_pointer().unwrap().is_grabbed()
|
if !seat.get_pointer().unwrap().is_grabbed()
|
||||||
&& !seat.get_keyboard().map(|k| k.is_grabbed()).unwrap_or(false)
|
&& !seat.get_keyboard().map(|k| k.is_grabbed()).unwrap_or(false)
|
||||||
{
|
{
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
let pos = seat.get_pointer().unwrap().current_location();
|
let pos = seat.get_pointer().unwrap().current_location();
|
||||||
let relative_pos =
|
let relative_pos = self.common.shell.map_global_to_space(pos, &output);
|
||||||
self.common.shell.map_global_to_space(pos, &output);
|
let overview = self.common.shell.overview_mode();
|
||||||
let overview = self.common.shell.overview_mode();
|
let workspace = self.common.shell.active_space_mut(&output);
|
||||||
let workspace = self.common.shell.active_space_mut(&output);
|
let mut under = None;
|
||||||
let mut under = None;
|
|
||||||
|
|
||||||
if let Some(window) = workspace.get_fullscreen(&output) {
|
if let Some(window) = workspace.get_fullscreen(&output) {
|
||||||
|
let layers = layer_map_for_output(&output);
|
||||||
|
if let Some(layer) =
|
||||||
|
layers.layer_under(WlrLayer::Overlay, relative_pos)
|
||||||
|
{
|
||||||
|
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
|
||||||
|
if layer.can_receive_keyboard_focus()
|
||||||
|
&& layer
|
||||||
|
.surface_under(
|
||||||
|
relative_pos - layer_loc.to_f64(),
|
||||||
|
WindowSurfaceType::ALL,
|
||||||
|
)
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
under = Some(layer.clone().into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
under = Some(window.clone().into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let done = {
|
||||||
let layers = layer_map_for_output(&output);
|
let layers = layer_map_for_output(&output);
|
||||||
if let Some(layer) =
|
if let Some(layer) = layers
|
||||||
layers.layer_under(WlrLayer::Overlay, relative_pos)
|
.layer_under(WlrLayer::Overlay, relative_pos)
|
||||||
|
.or_else(|| layers.layer_under(WlrLayer::Top, relative_pos))
|
||||||
{
|
{
|
||||||
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
|
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
|
||||||
if layer.can_receive_keyboard_focus()
|
if layer.can_receive_keyboard_focus()
|
||||||
|
|
@ -656,17 +661,22 @@ impl State {
|
||||||
{
|
{
|
||||||
under = Some(layer.clone().into());
|
under = Some(layer.clone().into());
|
||||||
}
|
}
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
under = Some(window.clone().into());
|
false
|
||||||
}
|
}
|
||||||
} else {
|
};
|
||||||
let done = {
|
if !done {
|
||||||
|
if let Some((target, _)) =
|
||||||
|
workspace.element_under(relative_pos, overview)
|
||||||
|
{
|
||||||
|
under = Some(target);
|
||||||
|
} else {
|
||||||
let layers = layer_map_for_output(&output);
|
let layers = layer_map_for_output(&output);
|
||||||
if let Some(layer) = layers
|
if let Some(layer) =
|
||||||
.layer_under(WlrLayer::Overlay, relative_pos)
|
layers.layer_under(WlrLayer::Bottom, pos).or_else(
|
||||||
.or_else(|| {
|
|| layers.layer_under(WlrLayer::Background, pos),
|
||||||
layers.layer_under(WlrLayer::Top, relative_pos)
|
)
|
||||||
})
|
|
||||||
{
|
{
|
||||||
let layer_loc =
|
let layer_loc =
|
||||||
layers.layer_geometry(layer).unwrap().loc;
|
layers.layer_geometry(layer).unwrap().loc;
|
||||||
|
|
@ -680,67 +690,35 @@ impl State {
|
||||||
{
|
{
|
||||||
under = Some(layer.clone().into());
|
under = Some(layer.clone().into());
|
||||||
}
|
}
|
||||||
true
|
};
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if !done {
|
|
||||||
if let Some((target, _)) =
|
|
||||||
workspace.element_under(relative_pos, overview)
|
|
||||||
{
|
|
||||||
under = Some(target);
|
|
||||||
} else {
|
|
||||||
let layers = layer_map_for_output(&output);
|
|
||||||
if let Some(layer) = layers
|
|
||||||
.layer_under(WlrLayer::Bottom, pos)
|
|
||||||
.or_else(|| {
|
|
||||||
layers.layer_under(WlrLayer::Background, pos)
|
|
||||||
})
|
|
||||||
{
|
|
||||||
let layer_loc =
|
|
||||||
layers.layer_geometry(layer).unwrap().loc;
|
|
||||||
if layer.can_receive_keyboard_focus()
|
|
||||||
&& layer
|
|
||||||
.surface_under(
|
|
||||||
relative_pos - layer_loc.to_f64(),
|
|
||||||
WindowSurfaceType::ALL,
|
|
||||||
)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
under = Some(layer.clone().into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Common::set_focus(
|
|
||||||
self,
|
|
||||||
under.and_then(|target| target.try_into().ok()).as_ref(),
|
|
||||||
seat,
|
|
||||||
Some(serial),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
Common::set_focus(
|
||||||
if let OverviewMode::Started(Trigger::Pointer(action_button), _) =
|
self,
|
||||||
self.common.shell.overview_mode()
|
under.and_then(|target| target.try_into().ok()).as_ref(),
|
||||||
{
|
&seat,
|
||||||
if action_button == button {
|
Some(serial),
|
||||||
self.common.shell.set_overview_mode(None);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if let OverviewMode::Started(Trigger::Pointer(action_button), _) =
|
||||||
|
self.common.shell.overview_mode()
|
||||||
|
{
|
||||||
|
if action_button == button {
|
||||||
|
self.common.shell.set_overview_mode(None);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
seat.get_pointer().unwrap().button(
|
};
|
||||||
self,
|
seat.get_pointer().unwrap().button(
|
||||||
&ButtonEvent {
|
self,
|
||||||
button,
|
&ButtonEvent {
|
||||||
state: event.state(),
|
button,
|
||||||
serial,
|
state: event.state(),
|
||||||
time: event.time_msec(),
|
serial,
|
||||||
},
|
time: event.time_msec(),
|
||||||
);
|
},
|
||||||
break;
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PointerAxis { event, .. } => {
|
InputEvent::PointerAxis { event, .. } => {
|
||||||
|
|
@ -753,8 +731,7 @@ impl State {
|
||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
|
|
||||||
let device = event.device();
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
|
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
if self.common.seats().position(|x| x == seat).unwrap() == 0
|
if self.common.seats().position(|x| x == seat).unwrap() == 0
|
||||||
&& self.common.egui.active
|
&& self.common.egui.active
|
||||||
|
|
@ -770,50 +747,152 @@ impl State {
|
||||||
.or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0))
|
.or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0))
|
||||||
.unwrap_or(0.0),
|
.unwrap_or(0.0),
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let userdata = seat.user_data();
|
let horizontal_amount = event.amount(Axis::Horizontal).unwrap_or_else(|| {
|
||||||
let devices = userdata.get::<Devices>().unwrap();
|
event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0
|
||||||
if devices.has_device(&device) {
|
});
|
||||||
let horizontal_amount =
|
let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| {
|
||||||
event.amount(Axis::Horizontal).unwrap_or_else(|| {
|
event.amount_discrete(Axis::Vertical).unwrap_or(0.0) * 3.0
|
||||||
event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0
|
});
|
||||||
});
|
let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal);
|
||||||
let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| {
|
let vertical_amount_discrete = event.amount_discrete(Axis::Vertical);
|
||||||
event.amount_discrete(Axis::Vertical).unwrap_or(0.0) * 3.0
|
|
||||||
});
|
|
||||||
let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal);
|
|
||||||
let vertical_amount_discrete = event.amount_discrete(Axis::Vertical);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut frame =
|
let mut frame = AxisFrame::new(event.time_msec()).source(event.source());
|
||||||
AxisFrame::new(event.time_msec()).source(event.source());
|
if horizontal_amount != 0.0 {
|
||||||
if horizontal_amount != 0.0 {
|
frame =
|
||||||
frame = frame
|
frame.value(Axis::Horizontal, scroll_factor * horizontal_amount);
|
||||||
.value(Axis::Horizontal, scroll_factor * horizontal_amount);
|
if let Some(discrete) = horizontal_amount_discrete {
|
||||||
if let Some(discrete) = horizontal_amount_discrete {
|
frame = frame.discrete(Axis::Horizontal, discrete as i32);
|
||||||
frame = frame.discrete(Axis::Horizontal, discrete as i32);
|
|
||||||
}
|
|
||||||
} else if event.source() == AxisSource::Finger {
|
|
||||||
frame = frame.stop(Axis::Horizontal);
|
|
||||||
}
|
}
|
||||||
if vertical_amount != 0.0 {
|
} else if event.source() == AxisSource::Finger {
|
||||||
frame =
|
frame = frame.stop(Axis::Horizontal);
|
||||||
frame.value(Axis::Vertical, scroll_factor * vertical_amount);
|
|
||||||
if let Some(discrete) = vertical_amount_discrete {
|
|
||||||
frame = frame.discrete(Axis::Vertical, discrete as i32);
|
|
||||||
}
|
|
||||||
} else if event.source() == AxisSource::Finger {
|
|
||||||
frame = frame.stop(Axis::Vertical);
|
|
||||||
}
|
|
||||||
seat.get_pointer().unwrap().axis(self, frame);
|
|
||||||
}
|
}
|
||||||
break;
|
if vertical_amount != 0.0 {
|
||||||
|
frame = frame.value(Axis::Vertical, scroll_factor * vertical_amount);
|
||||||
|
if let Some(discrete) = vertical_amount_discrete {
|
||||||
|
frame = frame.discrete(Axis::Vertical, discrete as i32);
|
||||||
|
}
|
||||||
|
} else if event.source() == AxisSource::Finger {
|
||||||
|
frame = frame.stop(Axis::Vertical);
|
||||||
|
}
|
||||||
|
seat.get_pointer().unwrap().axis(self, frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InputEvent::GestureSwipeBegin { event, .. } => {
|
||||||
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
pointer.gesture_swipe_begin(
|
||||||
|
self,
|
||||||
|
&GestureSwipeBeginEvent {
|
||||||
|
serial,
|
||||||
|
time: event.time_msec(),
|
||||||
|
fingers: event.fingers(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputEvent::GestureSwipeUpdate { event, .. } => {
|
||||||
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
pointer.gesture_swipe_update(
|
||||||
|
self,
|
||||||
|
&GestureSwipeUpdateEvent {
|
||||||
|
time: event.time_msec(),
|
||||||
|
delta: event.delta(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputEvent::GestureSwipeEnd { event, .. } => {
|
||||||
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
pointer.gesture_swipe_end(
|
||||||
|
self,
|
||||||
|
&GestureSwipeEndEvent {
|
||||||
|
serial,
|
||||||
|
time: event.time_msec(),
|
||||||
|
cancelled: event.cancelled(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputEvent::GesturePinchBegin { event, .. } => {
|
||||||
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
pointer.gesture_pinch_begin(
|
||||||
|
self,
|
||||||
|
&GesturePinchBeginEvent {
|
||||||
|
serial,
|
||||||
|
time: event.time_msec(),
|
||||||
|
fingers: event.fingers(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputEvent::GesturePinchUpdate { event, .. } => {
|
||||||
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
pointer.gesture_pinch_update(
|
||||||
|
self,
|
||||||
|
&GesturePinchUpdateEvent {
|
||||||
|
time: event.time_msec(),
|
||||||
|
delta: event.delta(),
|
||||||
|
scale: event.scale(),
|
||||||
|
rotation: event.rotation(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputEvent::GesturePinchEnd { event, .. } => {
|
||||||
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
pointer.gesture_pinch_end(
|
||||||
|
self,
|
||||||
|
&GesturePinchEndEvent {
|
||||||
|
serial,
|
||||||
|
time: event.time_msec(),
|
||||||
|
cancelled: event.cancelled(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputEvent::GestureHoldBegin { event, .. } => {
|
||||||
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
pointer.gesture_hold_begin(
|
||||||
|
self,
|
||||||
|
&GestureHoldBeginEvent {
|
||||||
|
serial,
|
||||||
|
time: event.time_msec(),
|
||||||
|
fingers: event.fingers(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputEvent::GestureHoldEnd { event, .. } => {
|
||||||
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
pointer.gesture_hold_end(
|
||||||
|
self,
|
||||||
|
&GestureHoldEndEvent {
|
||||||
|
serial,
|
||||||
|
time: event.time_msec(),
|
||||||
|
cancelled: event.cancelled(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => { /* TODO e.g. tablet or touch events */ }
|
_ => { /* TODO e.g. tablet or touch events */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
src/state.rs
12
src/state.rs
|
|
@ -7,6 +7,7 @@ use crate::{
|
||||||
x11::X11State,
|
x11::X11State,
|
||||||
},
|
},
|
||||||
config::{Config, OutputConfig},
|
config::{Config, OutputConfig},
|
||||||
|
input::Devices,
|
||||||
shell::{grabs::SeatMoveGrabState, Shell},
|
shell::{grabs::SeatMoveGrabState, Shell},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::protocols::{
|
wayland::protocols::{
|
||||||
|
|
@ -30,6 +31,7 @@ use smithay::utils::Rectangle;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
|
input::Device,
|
||||||
renderer::{
|
renderer::{
|
||||||
element::{
|
element::{
|
||||||
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
||||||
|
|
@ -63,6 +65,7 @@ use smithay::{
|
||||||
fractional_scale::{with_fractional_scale, FractionalScaleManagerState},
|
fractional_scale::{with_fractional_scale, FractionalScaleManagerState},
|
||||||
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
|
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
|
||||||
output::OutputManagerState,
|
output::OutputManagerState,
|
||||||
|
pointer_gestures::PointerGesturesState,
|
||||||
presentation::PresentationState,
|
presentation::PresentationState,
|
||||||
primary_selection::PrimarySelectionState,
|
primary_selection::PrimarySelectionState,
|
||||||
seat::WaylandFocus,
|
seat::WaylandFocus,
|
||||||
|
|
@ -301,6 +304,7 @@ impl State {
|
||||||
let kde_decoration_state = KdeDecorationState::new::<Self>(&dh, Mode::Client);
|
let kde_decoration_state = KdeDecorationState::new::<Self>(&dh, Mode::Client);
|
||||||
let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
|
let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
|
||||||
XWaylandKeyboardGrabState::new::<Self>(&dh);
|
XWaylandKeyboardGrabState::new::<Self>(&dh);
|
||||||
|
PointerGesturesState::new::<Self>(&dh);
|
||||||
|
|
||||||
let shell = Shell::new(&config, dh);
|
let shell = Shell::new(&config, dh);
|
||||||
|
|
||||||
|
|
@ -421,6 +425,14 @@ impl Common {
|
||||||
self.seats.iter()
|
self.seats.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn seat_with_device<D: Device>(&self, device: &D) -> Option<&Seat<State>> {
|
||||||
|
self.seats().find(|seat| {
|
||||||
|
let userdata = seat.user_data();
|
||||||
|
let devices = userdata.get::<Devices>().unwrap();
|
||||||
|
devices.has_device(device)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn last_active_seat(&self) -> &Seat<State> {
|
pub fn last_active_seat(&self) -> &Seat<State> {
|
||||||
self.last_active_seat.as_ref().expect("No seat?")
|
self.last_active_seat.as_ref().expect("No seat?")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ pub mod keyboard_shortcuts_inhibit;
|
||||||
pub mod layer_shell;
|
pub mod layer_shell;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
pub mod output_configuration;
|
pub mod output_configuration;
|
||||||
|
pub mod pointer_gestures;
|
||||||
pub mod presentation;
|
pub mod presentation;
|
||||||
pub mod primary_selection;
|
pub mod primary_selection;
|
||||||
pub mod relative_pointer;
|
pub mod relative_pointer;
|
||||||
|
|
|
||||||
6
src/wayland/handlers/pointer_gestures.rs
Normal file
6
src/wayland/handlers/pointer_gestures.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use crate::state::State;
|
||||||
|
use smithay::delegate_pointer_gestures;
|
||||||
|
|
||||||
|
delegate_pointer_gestures!(State);
|
||||||
Loading…
Add table
Add a link
Reference in a new issue