Merge tag 'epoch-1.8.0' into local/yoda-main
Epoch 1.8.0 # Conflicts: # Cargo.lock
This commit is contained in:
commit
a69f659983
50 changed files with 3533 additions and 1713 deletions
1354
Cargo.lock
generated
1354
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -177,4 +177,5 @@ dnd = { path = "../window_clipboard/dnd" }
|
||||||
mime = { path = "../window_clipboard/mime" }
|
mime = { path = "../window_clipboard/mime" }
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
smithay = { git = "https://github.com/smithay/smithay.git", rev = "5fb12b8" }
|
smithay = { git = "https://github.com/smithay/smithay.git", rev = "e3d461a" }
|
||||||
|
smithay-egui = { git = "https://github.com/Smithay/smithay-egui.git", rev = "6511552" }
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,13 @@ impl Default for AppearanceConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum DecorationPreference {
|
||||||
|
#[default]
|
||||||
|
ClientSide,
|
||||||
|
ServerSide,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, CosmicConfigEntry)]
|
#[derive(Clone, Debug, PartialEq, CosmicConfigEntry)]
|
||||||
#[version = 1]
|
#[version = 1]
|
||||||
pub struct CosmicCompConfig {
|
pub struct CosmicCompConfig {
|
||||||
|
|
@ -104,6 +111,7 @@ pub struct CosmicCompConfig {
|
||||||
/// Briefly magnify the cursor when the pointer is shaken, to help locate it
|
/// Briefly magnify the cursor when the pointer is shaken, to help locate it
|
||||||
pub cursor_shake_to_find: bool,
|
pub cursor_shake_to_find: bool,
|
||||||
pub activation_policy: ActivationPolicy,
|
pub activation_policy: ActivationPolicy,
|
||||||
|
pub decoration_preference: DecorationPreference,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CosmicCompConfig {
|
impl Default for CosmicCompConfig {
|
||||||
|
|
@ -143,6 +151,7 @@ impl Default for CosmicCompConfig {
|
||||||
cursor_hide_timeout: None,
|
cursor_hide_timeout: None,
|
||||||
cursor_shake_to_find: true,
|
cursor_shake_to_find: true,
|
||||||
activation_policy: ActivationPolicy::default(),
|
activation_policy: ActivationPolicy::default(),
|
||||||
|
decoration_preference: DecorationPreference::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
0
resources/i18n/fil/cosmic_comp.ftl
Normal file
0
resources/i18n/fil/cosmic_comp.ftl
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
a11y-zoom-move-continuously = La vista bolega de contunh amb lo ponchador
|
||||||
|
a11y-zoom-move-onedge = La lista bolega quand lo ponchador atenh un caire
|
||||||
|
a11y-zoom-move-centered = La vista bolega per gardar lo ponchador al centre
|
||||||
|
a11y-zoom-settings = Paramètres de la lópia...
|
||||||
|
unknown-keybinding = <unset>
|
||||||
|
window-menu-tiled = Fenèstras bandejanta
|
||||||
|
window-menu-screenshot = Prendre una captura d’ecran
|
||||||
|
window-menu-resize = Redimensionar
|
||||||
|
window-menu-move-prev-workspace = Desplaçar a l’espaci de trabalh precedent
|
||||||
|
window-menu-move-next-workspace = Desplaçar a l'espaci de trabalh seguent
|
||||||
|
window-menu-stack = Crear una pila de fenèstras
|
||||||
|
window-menu-unstack-all = Desapilar totas las fenèstras
|
||||||
|
window-menu-unstack = Desapilar la fenèstra
|
||||||
|
window-menu-sticky = Fenèstra adesiva
|
||||||
|
window-menu-close = Tampar
|
||||||
|
window-menu-close-all = Tampar totas las fenèstras
|
||||||
|
window-menu-resize-edge-top = Amont
|
||||||
|
window-menu-resize-edge-left = Esquèrra
|
||||||
|
window-menu-resize-edge-right = Drecha
|
||||||
|
window-menu-resize-edge-bottom = Aval
|
||||||
|
|
@ -693,7 +693,7 @@ impl Device {
|
||||||
)
|
)
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to optain file descriptor for drm device: {}",
|
"Failed to obtain file descriptor for drm device: {}",
|
||||||
path.display()
|
path.display()
|
||||||
)
|
)
|
||||||
})?,
|
})?,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,11 @@ use smithay::{
|
||||||
calloop::{Dispatcher, EventLoop, LoopHandle},
|
calloop::{Dispatcher, EventLoop, LoopHandle},
|
||||||
drm::{
|
drm::{
|
||||||
Device as _,
|
Device as _,
|
||||||
control::{Device as _, connector::Interface, crtc},
|
control::{
|
||||||
|
Device as _,
|
||||||
|
connector::{Interface, State as ConnectorState},
|
||||||
|
crtc,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
input::{self, Libinput},
|
input::{self, Libinput},
|
||||||
wayland_protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1::TrancheFlags,
|
wayland_protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1::TrancheFlags,
|
||||||
|
|
@ -250,13 +254,18 @@ fn determine_primary_gpu(
|
||||||
|
|
||||||
// try to find builtin display
|
// try to find builtin display
|
||||||
for dev in drm_devices.values() {
|
for dev in drm_devices.values() {
|
||||||
if dev.inner.surfaces.values().any(|s| {
|
let drm = dev.drm.device();
|
||||||
if let Ok(conn_info) = dev.drm.device().get_connector(s.connector, false) {
|
let res_handles = drm.resource_handles()?;
|
||||||
|
let connectors = res_handles.connectors();
|
||||||
|
if connectors.iter().any(|conn| {
|
||||||
|
let Ok(conn_info) = drm.get_connector(*conn, false) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
let i = conn_info.interface();
|
let i = conn_info.interface();
|
||||||
i == Interface::EmbeddedDisplayPort || i == Interface::LVDS || i == Interface::DSI
|
conn_info.state() == ConnectorState::Connected
|
||||||
} else {
|
&& (i == Interface::EmbeddedDisplayPort
|
||||||
false
|
|| i == Interface::LVDS
|
||||||
}
|
|| i == Interface::DSI)
|
||||||
}) {
|
}) {
|
||||||
return Ok(Some(dev.inner.render_node));
|
return Ok(Some(dev.inner.render_node));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,10 +286,10 @@ impl IndicatorShader {
|
||||||
Uniform::new(
|
Uniform::new(
|
||||||
"radius",
|
"radius",
|
||||||
[
|
[
|
||||||
outer_radius[3] as f32,
|
|
||||||
outer_radius[1] as f32,
|
|
||||||
outer_radius[0] as f32,
|
outer_radius[0] as f32,
|
||||||
|
outer_radius[1] as f32,
|
||||||
outer_radius[2] as f32,
|
outer_radius[2] as f32,
|
||||||
|
outer_radius[3] as f32,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Uniform::new("scale", scale as f32),
|
Uniform::new("scale", scale as f32),
|
||||||
|
|
@ -899,8 +899,7 @@ where
|
||||||
let geometry = geometry.to_local(output).as_logical();
|
let geometry = geometry.to_local(output).as_logical();
|
||||||
|
|
||||||
let padded = with_states(layer.wl_surface(), |states| {
|
let padded = with_states(layer.wl_surface(), |states| {
|
||||||
surface_padding(states, geometry.size)
|
surface_padding(states).and_then(|padding| pad_rect(geometry, &padding))
|
||||||
.and_then(|padding| pad_rect(geometry, &padding))
|
|
||||||
})
|
})
|
||||||
.unwrap_or(geometry);
|
.unwrap_or(geometry);
|
||||||
let radii = with_states(layer.wl_surface(), |states| {
|
let radii = with_states(layer.wl_surface(), |states| {
|
||||||
|
|
|
||||||
|
|
@ -86,12 +86,6 @@ impl ShadowShader {
|
||||||
let offset = [0., 5.];
|
let offset = [0., 5.];
|
||||||
let color = [0., 0., 0., if dark_mode { 0.45 } else { 0.35 }];
|
let color = [0., 0., 0., if dark_mode { 0.45 } else { 0.35 }];
|
||||||
let radius = radius.map(|r| ceil(r as f64));
|
let radius = radius.map(|r| ceil(r as f64));
|
||||||
let radius = [
|
|
||||||
radius[3], // top_left
|
|
||||||
radius[1], // top_right
|
|
||||||
radius[0], // bottom_right
|
|
||||||
radius[2], // bottom_left
|
|
||||||
];
|
|
||||||
|
|
||||||
let width = softness;
|
let width = softness;
|
||||||
let sigma = width / 2.;
|
let sigma = width / 2.;
|
||||||
|
|
|
||||||
|
|
@ -247,10 +247,10 @@ impl BlurElement {
|
||||||
Uniform::new(
|
Uniform::new(
|
||||||
"corner_radius",
|
"corner_radius",
|
||||||
[
|
[
|
||||||
radii[3] as f32,
|
|
||||||
radii[1] as f32,
|
|
||||||
radii[0] as f32,
|
radii[0] as f32,
|
||||||
|
radii[1] as f32,
|
||||||
radii[2] as f32,
|
radii[2] as f32,
|
||||||
|
radii[3] as f32,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Uniform::new(
|
Uniform::new(
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,10 @@ where
|
||||||
Uniform::new(
|
Uniform::new(
|
||||||
"corner_radius",
|
"corner_radius",
|
||||||
[
|
[
|
||||||
radius[3] as f32,
|
|
||||||
radius[1] as f32,
|
|
||||||
radius[0] as f32,
|
radius[0] as f32,
|
||||||
|
radius[1] as f32,
|
||||||
radius[2] as f32,
|
radius[2] as f32,
|
||||||
|
radius[3] as f32,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Uniform::new(
|
Uniform::new(
|
||||||
|
|
@ -145,10 +145,10 @@ where
|
||||||
geo: Rectangle<f64, Logical>,
|
geo: Rectangle<f64, Logical>,
|
||||||
radius: [u8; 4],
|
radius: [u8; 4],
|
||||||
) -> [Rectangle<f64, Logical>; 4] {
|
) -> [Rectangle<f64, Logical>; 4] {
|
||||||
let top_left = radius[3] as f64;
|
let top_left = radius[0] as f64;
|
||||||
let top_right = radius[1] as f64;
|
let top_right = radius[1] as f64;
|
||||||
let bottom_right = radius[0] as f64;
|
let bottom_right = radius[2] as f64;
|
||||||
let bottom_left = radius[2] as f64;
|
let bottom_left = radius[3] as f64;
|
||||||
|
|
||||||
[
|
[
|
||||||
Rectangle::new(geo.loc, Size::from((top_left, top_left))),
|
Rectangle::new(geo.loc, Size::from((top_left, top_left))),
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,11 @@ use cosmic_config::{ConfigGet, CosmicConfigEntry};
|
||||||
use cosmic_settings_config::window_rules::ApplicationException;
|
use cosmic_settings_config::window_rules::ApplicationException;
|
||||||
use cosmic_settings_config::{Shortcuts, shortcuts, window_rules};
|
use cosmic_settings_config::{Shortcuts, shortcuts, window_rules};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smithay::utils::{Clock, Monotonic};
|
|
||||||
use smithay::wayland::xdg_activation::XdgActivationState;
|
use smithay::wayland::xdg_activation::XdgActivationState;
|
||||||
|
use smithay::{
|
||||||
|
backend::input::InputTime,
|
||||||
|
utils::{Clock, Monotonic},
|
||||||
|
};
|
||||||
pub use smithay::{
|
pub use smithay::{
|
||||||
backend::input::{self as smithay_input, KeyState},
|
backend::input::{self as smithay_input, KeyState},
|
||||||
input::keyboard::{Keysym, ModifiersState, keysyms as KeySyms},
|
input::keyboard::{Keysym, ModifiersState, keysyms as KeySyms},
|
||||||
|
|
@ -46,8 +49,8 @@ mod types;
|
||||||
use cosmic::config::CosmicTk;
|
use cosmic::config::CosmicTk;
|
||||||
pub use cosmic_comp_config::EdidProduct;
|
pub use cosmic_comp_config::EdidProduct;
|
||||||
use cosmic_comp_config::{
|
use cosmic_comp_config::{
|
||||||
ActivationPolicy, AppearanceConfig, CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig,
|
ActivationPolicy, AppearanceConfig, CosmicCompConfig, DecorationPreference, KeyboardConfig,
|
||||||
XwaylandDescaling, XwaylandEavesdropping, ZoomConfig,
|
TileBehavior, XkbConfig, XwaylandDescaling, XwaylandEavesdropping, ZoomConfig,
|
||||||
input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride},
|
input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride},
|
||||||
output::comp::{
|
output::comp::{
|
||||||
OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef, load_outputs,
|
OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef, load_outputs,
|
||||||
|
|
@ -538,7 +541,13 @@ impl Config {
|
||||||
primary.config_mut().xwayland_primary = true;
|
primary.config_mut().xwayland_primary = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for output in outputs.iter().filter(|o| o.mirroring().is_none()) {
|
// sort by connector name for a deterministic layout independent of hotplug order
|
||||||
|
let mut sorted_outputs = outputs
|
||||||
|
.iter()
|
||||||
|
.filter(|o| o.mirroring().is_none())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
sorted_outputs.sort_by_key(|o| o.name());
|
||||||
|
for output in sorted_outputs {
|
||||||
{
|
{
|
||||||
let mut config = output.config_mut();
|
let mut config = output.config_mut();
|
||||||
config.position = (w, 0);
|
config.position = (w, 0);
|
||||||
|
|
@ -770,13 +779,12 @@ pub fn change_modifier_state(
|
||||||
const X11_KEYCODE_OFFSET: u32 = 8;
|
const X11_KEYCODE_OFFSET: u32 = 8;
|
||||||
|
|
||||||
let mut input = |key_state, scan_code| {
|
let mut input = |key_state, scan_code| {
|
||||||
let time = state.common.clock.now().as_millis();
|
|
||||||
let _ = keyboard.input(
|
let _ = keyboard.input(
|
||||||
state,
|
state,
|
||||||
smithay_input::Keycode::new(scan_code + X11_KEYCODE_OFFSET),
|
smithay_input::Keycode::new(scan_code + X11_KEYCODE_OFFSET),
|
||||||
key_state,
|
key_state,
|
||||||
SERIAL_COUNTER.next_serial(),
|
SERIAL_COUNTER.next_serial(),
|
||||||
time,
|
InputTime::now(),
|
||||||
|_, _, _| smithay::input::keyboard::FilterResult::<()>::Forward,
|
|_, _, _| smithay::input::keyboard::FilterResult::<()>::Forward,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
@ -840,7 +848,9 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
|
||||||
}
|
}
|
||||||
if !state.common.ei_seats.is_empty() {
|
if !state.common.ei_seats.is_empty() {
|
||||||
let seat = state.common.shell.read().seats.last_active().clone();
|
let seat = state.common.shell.read().seats.last_active().clone();
|
||||||
state.broadcast_ei_keyboard_modifiers(&seat);
|
if let Some(keyboard) = seat.get_keyboard() {
|
||||||
|
state.broadcast_ei_keyboard_modifiers(&keyboard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state.common.config.cosmic_conf.xkb_config = value;
|
state.common.config.cosmic_conf.xkb_config = value;
|
||||||
}
|
}
|
||||||
|
|
@ -998,6 +1008,13 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
|
||||||
state.common.config.cosmic_conf.activation_policy = new;
|
state.common.config.cosmic_conf.activation_policy = new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"decoration_preference" => {
|
||||||
|
let new = get_config::<DecorationPreference>(&config, "decoration_preference");
|
||||||
|
if new != state.common.config.cosmic_conf.decoration_preference {
|
||||||
|
state.common.config.cosmic_conf.decoration_preference = new;
|
||||||
|
state.update_decorations();
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ use cosmic_config::ConfigSet;
|
||||||
use cosmic_settings_config::shortcuts;
|
use cosmic_settings_config::shortcuts;
|
||||||
use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection};
|
use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
backend::input::InputTime,
|
||||||
input::{Seat, pointer::MotionEvent},
|
input::{Seat, pointer::MotionEvent},
|
||||||
utils::{Point, Serial},
|
utils::{Point, Serial},
|
||||||
};
|
};
|
||||||
|
|
@ -45,7 +46,7 @@ impl State {
|
||||||
backend_id: &InputBackendId,
|
backend_id: &InputBackendId,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
pattern: shortcuts::Binding,
|
pattern: shortcuts::Binding,
|
||||||
direction: Option<Direction>,
|
direction: Option<Direction>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -150,7 +151,7 @@ impl State {
|
||||||
backend_id: &InputBackendId,
|
backend_id: &InputBackendId,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
pattern: shortcuts::Binding,
|
pattern: shortcuts::Binding,
|
||||||
direction: Option<Direction>,
|
direction: Option<Direction>,
|
||||||
propagate: bool,
|
propagate: bool,
|
||||||
|
|
|
||||||
310
src/input/mod.rs
310
src/input/mod.rs
|
|
@ -9,7 +9,10 @@ use crate::{
|
||||||
cosmic_modifiers_from_smithay,
|
cosmic_modifiers_from_smithay,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input::gestures::{GestureState, SwipeAction},
|
input::{
|
||||||
|
gestures::{GestureState, SwipeAction},
|
||||||
|
tablet_emu::PointerEmulationGrab,
|
||||||
|
},
|
||||||
shell::{
|
shell::{
|
||||||
SeatExt, Trigger,
|
SeatExt, Trigger,
|
||||||
focus::{
|
focus::{
|
||||||
|
|
@ -42,19 +45,21 @@ use smithay::{
|
||||||
backend::input::{
|
backend::input::{
|
||||||
AbsolutePositionEvent, Axis, AxisRelativeDirection, AxisSource, Device, DeviceCapability,
|
AbsolutePositionEvent, Axis, AxisRelativeDirection, AxisSource, Device, DeviceCapability,
|
||||||
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _,
|
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _,
|
||||||
GestureSwipeUpdateEvent as _, InputBackend, InputEvent, KeyState, PointerAxisEvent,
|
GestureSwipeUpdateEvent as _, InputBackend, InputEvent, InputTime, KeyState,
|
||||||
ProximityState, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent,
|
PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent,
|
||||||
TabletToolTipEvent, TabletToolTipState, TouchEvent,
|
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
|
||||||
},
|
},
|
||||||
desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree},
|
desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree},
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
|
keyboard::KeyboardHandle,
|
||||||
keyboard::{FilterResult, KeyboardSource, KeysymHandle, ModifiersState},
|
keyboard::{FilterResult, KeyboardSource, KeysymHandle, ModifiersState},
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame, ButtonEvent as PointerButtonEvent, Focus, GestureHoldBeginEvent,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
|
GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent,
|
||||||
PointerGrab, PointerHandle, RelativeMotionEvent,
|
GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, PointerGrab, PointerHandle,
|
||||||
|
RelativeMotionEvent,
|
||||||
},
|
},
|
||||||
tablet::{TabletDescriptor, TabletSeatTrait, tool},
|
tablet::{TabletDescriptor, TabletSeatTrait, tool},
|
||||||
touch::{DownEvent, MotionEvent as TouchMotionEvent, UpEvent},
|
touch::{DownEvent, MotionEvent as TouchMotionEvent, UpEvent},
|
||||||
|
|
@ -87,6 +92,7 @@ use std::{
|
||||||
|
|
||||||
pub mod actions;
|
pub mod actions;
|
||||||
pub mod gestures;
|
pub mod gestures;
|
||||||
|
pub mod tablet_emu;
|
||||||
|
|
||||||
/// Identifies the input backend instance an event came from, used to disambiguate device ids
|
/// Identifies the input backend instance an event came from, used to disambiguate device ids
|
||||||
/// (which are only unique within a single backend instance, see
|
/// (which are only unique within a single backend instance, see
|
||||||
|
|
@ -271,7 +277,7 @@ impl State {
|
||||||
trace!(?keycode, ?state, "key");
|
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(&event);
|
||||||
let keyboard = seat.get_keyboard().unwrap();
|
let keyboard = seat.get_keyboard().unwrap();
|
||||||
let previous_modifiers = keyboard.modifier_state();
|
let previous_modifiers = keyboard.modifier_state();
|
||||||
if let Some((action, pattern)) = keyboard
|
if let Some((action, pattern)) = keyboard
|
||||||
|
|
@ -325,7 +331,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
InputEvent::PointerMotion { event, .. } => {
|
InputEvent::PointerMotion { event, .. } => {
|
||||||
use smithay::backend::input::PointerMotionEvent;
|
use smithay::backend::input::PointerMotionEvent as _;
|
||||||
|
|
||||||
let shell = self.common.shell.write();
|
let shell = self.common.shell.write();
|
||||||
if let Some(seat) = shell
|
if let Some(seat) = shell
|
||||||
|
|
@ -338,6 +344,9 @@ impl State {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
||||||
if self.common.config.cosmic_conf.cursor_shake_to_find
|
if self.common.config.cosmic_conf.cursor_shake_to_find
|
||||||
|
&& seat
|
||||||
|
.get_pointer()
|
||||||
|
.is_some_and(|pointer| !pointer.is_grabbed())
|
||||||
&& let Some(cursor_state) =
|
&& let Some(cursor_state) =
|
||||||
seat.user_data()
|
seat.user_data()
|
||||||
.get::<crate::backend::render::cursor::CursorState>()
|
.get::<crate::backend::render::cursor::CursorState>()
|
||||||
|
|
@ -397,7 +406,7 @@ impl State {
|
||||||
&RelativeMotionEvent {
|
&RelativeMotionEvent {
|
||||||
delta: event.delta(),
|
delta: event.delta(),
|
||||||
delta_unaccel: event.delta_unaccel(),
|
delta_unaccel: event.delta_unaccel(),
|
||||||
utime: event.time(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -635,10 +644,10 @@ impl State {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
self,
|
self,
|
||||||
under,
|
under,
|
||||||
&MotionEvent {
|
&PointerMotionEvent {
|
||||||
location: position.as_logical(),
|
location: position.as_logical(),
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
ptr.frame(self);
|
ptr.frame(self);
|
||||||
|
|
@ -750,23 +759,33 @@ impl State {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
self,
|
self,
|
||||||
under,
|
under,
|
||||||
&MotionEvent {
|
&PointerMotionEvent {
|
||||||
location: position.as_logical(),
|
location: position.as_logical(),
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
ptr.frame(self);
|
ptr.frame(self);
|
||||||
|
|
||||||
|
let mut shell = self.common.shell.write();
|
||||||
// Keep the seat's active output following the pointer. Click-to-
|
// Keep the seat's active output following the pointer. Click-to-
|
||||||
// focus (PointerButton) resolves its target via
|
// focus (PointerButton) resolves its target via
|
||||||
// `seat.active_output()`
|
// `seat.active_output()`
|
||||||
let previous_output = seat.active_output();
|
let previous_output = seat.active_output();
|
||||||
if previous_output != output {
|
if previous_output != output {
|
||||||
|
for session in cursor_sessions_for_output(&shell, &previous_output) {
|
||||||
|
session.set_cursor_pos(None);
|
||||||
|
}
|
||||||
seat.set_active_output(&output);
|
seat.set_active_output(&output);
|
||||||
}
|
}
|
||||||
|
|
||||||
let shell = self.common.shell.read();
|
shell.update_pointer_position(position.to_local(&output), &output);
|
||||||
|
shell.update_focal_point(
|
||||||
|
&seat,
|
||||||
|
position,
|
||||||
|
self.common.config.cosmic_conf.accessibility_zoom.view_moves,
|
||||||
|
);
|
||||||
|
|
||||||
update_output_image_copy_cursor_position(
|
update_output_image_copy_cursor_position(
|
||||||
&shell,
|
&shell,
|
||||||
&self.common.clock,
|
&self.common.clock,
|
||||||
|
|
@ -777,9 +796,8 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PointerButton { event, .. } => {
|
InputEvent::PointerButton { event, .. } => {
|
||||||
use smithay::backend::input::{ButtonState, PointerButtonEvent};
|
use smithay::backend::input::{ButtonState, PointerButtonEvent as _};
|
||||||
|
|
||||||
//
|
|
||||||
let Some(seat) = self
|
let Some(seat) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
@ -853,7 +871,7 @@ impl State {
|
||||||
&& !shortcuts_inhibited
|
&& !shortcuts_inhibited
|
||||||
{
|
{
|
||||||
let seat_clone = seat.clone();
|
let seat_clone = seat.clone();
|
||||||
let mouse_button = PointerButtonEvent::button(&event);
|
let mouse_button = event.button();
|
||||||
|
|
||||||
let mut supress_button = || {
|
let mut supress_button = || {
|
||||||
// If the logo is held then the pointer event is
|
// If the logo is held then the pointer event is
|
||||||
|
|
@ -1005,7 +1023,7 @@ impl State {
|
||||||
button,
|
button,
|
||||||
event.state(),
|
event.state(),
|
||||||
serial,
|
serial,
|
||||||
event.time_msec(),
|
event.time(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1013,16 +1031,16 @@ impl State {
|
||||||
if pass_event {
|
if pass_event {
|
||||||
ptr.button(
|
ptr.button(
|
||||||
self,
|
self,
|
||||||
&ButtonEvent {
|
&PointerButtonEvent {
|
||||||
button,
|
button,
|
||||||
state: event.state(),
|
state: event.state(),
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
ptr.frame(self);
|
ptr.frame(self);
|
||||||
} else if event.state() == ButtonState::Released {
|
} else if event.state() == ButtonState::Released {
|
||||||
ptr.unset_grab(self, serial, event.time_msec())
|
ptr.unset_grab(self, serial, event.time())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PointerAxis { event, .. } => {
|
InputEvent::PointerAxis { event, .. } => {
|
||||||
|
|
@ -1073,7 +1091,7 @@ impl State {
|
||||||
self.update_zoom(&seat, change, event.source() == AxisSource::Wheel);
|
self.update_zoom(&seat, change, event.source() == AxisSource::Wheel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut frame = AxisFrame::new(event.time_msec()).source(event.source());
|
let mut frame = AxisFrame::new(event.time()).source(event.source());
|
||||||
let horizontal_amount = event
|
let horizontal_amount = event
|
||||||
.amount(Axis::Horizontal)
|
.amount(Axis::Horizontal)
|
||||||
.or_else(|| Some(event.amount_v120(Axis::Horizontal)? * 15.0 / 120.));
|
.or_else(|| Some(event.amount_v120(Axis::Horizontal)? * 15.0 / 120.));
|
||||||
|
|
@ -1142,7 +1160,7 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&GestureSwipeBeginEvent {
|
&GestureSwipeBeginEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
fingers: event.fingers(),
|
fingers: event.fingers(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1163,7 +1181,7 @@ impl State {
|
||||||
if let Some(ref mut gesture_state) = self.common.gesture_state {
|
if let Some(ref mut gesture_state) = self.common.gesture_state {
|
||||||
let first_update = gesture_state.update(
|
let first_update = gesture_state.update(
|
||||||
event.delta(),
|
event.delta(),
|
||||||
Duration::from_millis(event.time_msec() as u64),
|
Duration::from_millis(event.time().millis() as u64),
|
||||||
);
|
);
|
||||||
// Decide on action if first update
|
// Decide on action if first update
|
||||||
if first_update {
|
if first_update {
|
||||||
|
|
@ -1239,7 +1257,7 @@ impl State {
|
||||||
pointer.gesture_swipe_update(
|
pointer.gesture_swipe_update(
|
||||||
self,
|
self,
|
||||||
&GestureSwipeUpdateEvent {
|
&GestureSwipeUpdateEvent {
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
delta: event.delta(),
|
delta: event.delta(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1288,7 +1306,7 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&GestureSwipeEndEvent {
|
&GestureSwipeEndEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
cancelled: event.cancelled(),
|
cancelled: event.cancelled(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1311,7 +1329,7 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&GesturePinchBeginEvent {
|
&GesturePinchBeginEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
fingers: event.fingers(),
|
fingers: event.fingers(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1331,7 +1349,7 @@ impl State {
|
||||||
pointer.gesture_pinch_update(
|
pointer.gesture_pinch_update(
|
||||||
self,
|
self,
|
||||||
&GesturePinchUpdateEvent {
|
&GesturePinchUpdateEvent {
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
delta: event.delta(),
|
delta: event.delta(),
|
||||||
scale: event.scale(),
|
scale: event.scale(),
|
||||||
rotation: event.rotation(),
|
rotation: event.rotation(),
|
||||||
|
|
@ -1355,7 +1373,7 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&GesturePinchEndEvent {
|
&GesturePinchEndEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
cancelled: event.cancelled(),
|
cancelled: event.cancelled(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1377,7 +1395,7 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&GestureHoldBeginEvent {
|
&GestureHoldBeginEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
fingers: event.fingers(),
|
fingers: event.fingers(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1399,7 +1417,7 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&GestureHoldEndEvent {
|
&GestureHoldEndEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
cancelled: event.cancelled(),
|
cancelled: event.cancelled(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1456,7 +1474,7 @@ impl State {
|
||||||
slot: event.slot(),
|
slot: event.slot(),
|
||||||
location: position.as_logical(),
|
location: position.as_logical(),
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1505,7 +1523,7 @@ impl State {
|
||||||
&TouchMotionEvent {
|
&TouchMotionEvent {
|
||||||
slot: event.slot(),
|
slot: event.slot(),
|
||||||
location: position.as_logical(),
|
location: position.as_logical(),
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1531,7 +1549,7 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&UpEvent {
|
&UpEvent {
|
||||||
slot: event.slot(),
|
slot: event.slot(),
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
serial,
|
serial,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -1582,6 +1600,7 @@ impl State {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let current_output = seat.active_output();
|
||||||
let position =
|
let position =
|
||||||
transform_output_mapped_position(&output, &event, shell.zoom_state());
|
transform_output_mapped_position(&output, &event, shell.zoom_state());
|
||||||
let under = State::surface_under(position, &output, &shell)
|
let under = State::surface_under(position, &output, &shell)
|
||||||
|
|
@ -1590,21 +1609,33 @@ impl State {
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
|
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.motion(
|
pointer.set_location(position.as_logical());
|
||||||
self,
|
|
||||||
under.clone(),
|
|
||||||
&MotionEvent {
|
|
||||||
location: position.as_logical(),
|
|
||||||
serial: SERIAL_COUNTER.next_serial(),
|
|
||||||
time: self.common.clock.now().as_millis(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let tablet_seat = seat.tablet_seat();
|
let tablet_seat = seat.tablet_seat();
|
||||||
|
|
||||||
let tool = tablet_seat.get_tool(&event.tool());
|
let tool = tablet_seat.get_tool(&event.tool());
|
||||||
|
|
||||||
if let Some(tool) = tool {
|
if let Some(tool) = tool {
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
if !tool.is_grabbed()
|
||||||
|
&& under
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|(target, _)| !target.supports_tool(&tool))
|
||||||
|
{
|
||||||
|
let start_data = tool::GrabStartData {
|
||||||
|
focus: under.clone(),
|
||||||
|
trigger: tool::GrabTrigger::Proximity,
|
||||||
|
location: position.as_logical(),
|
||||||
|
};
|
||||||
|
tool.set_grab(
|
||||||
|
self,
|
||||||
|
PointerEmulationGrab::new(start_data, seat.clone()),
|
||||||
|
event.time(),
|
||||||
|
serial,
|
||||||
|
Focus::Keep,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let frame = tool::AxisFrame {
|
let frame = tool::AxisFrame {
|
||||||
pressure: event.pressure_has_changed().then(|| event.pressure()),
|
pressure: event.pressure_has_changed().then(|| event.pressure()),
|
||||||
distance: event.distance_has_changed().then(|| event.distance()),
|
distance: event.distance_has_changed().then(|| event.distance()),
|
||||||
|
|
@ -1622,17 +1653,39 @@ impl State {
|
||||||
|
|
||||||
tool.motion(
|
tool.motion(
|
||||||
self,
|
self,
|
||||||
under
|
under,
|
||||||
.and_then(|(f, loc)| f.wl_surface().map(|s| (s.into_owned(), loc))),
|
|
||||||
&tool::MotionEvent {
|
&tool::MotionEvent {
|
||||||
location: position.as_logical(),
|
location: position.as_logical(),
|
||||||
serial: SERIAL_COUNTER.next_serial(),
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
tool.frame(self, event.time_msec());
|
tool.frame(self, event.time());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut shell = self.common.shell.write();
|
||||||
|
shell.update_pointer_position(position.to_local(&output), &output);
|
||||||
|
shell.update_focal_point(
|
||||||
|
&seat,
|
||||||
|
position,
|
||||||
|
self.common.config.cosmic_conf.accessibility_zoom.view_moves,
|
||||||
|
);
|
||||||
|
|
||||||
|
if output != current_output {
|
||||||
|
for session in cursor_sessions_for_output(&shell, ¤t_output) {
|
||||||
|
session.set_cursor_pos(None);
|
||||||
|
}
|
||||||
|
seat.set_active_output(&output);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_output_image_copy_cursor_position(
|
||||||
|
&shell,
|
||||||
|
&self.common.clock,
|
||||||
|
&output,
|
||||||
|
&seat,
|
||||||
|
position,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TabletToolProximity { event, .. } => {
|
InputEvent::TabletToolProximity { event, .. } => {
|
||||||
|
|
@ -1651,6 +1704,7 @@ impl State {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let current_output = seat.active_output();
|
||||||
let position =
|
let position =
|
||||||
transform_output_mapped_position(&output, &event, shell.zoom_state());
|
transform_output_mapped_position(&output, &event, shell.zoom_state());
|
||||||
let under = State::surface_under(position, &output, &shell)
|
let under = State::surface_under(position, &output, &shell)
|
||||||
|
|
@ -1659,15 +1713,7 @@ impl State {
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
|
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.motion(
|
pointer.set_location(position.as_logical());
|
||||||
self,
|
|
||||||
under.clone(),
|
|
||||||
&MotionEvent {
|
|
||||||
location: position.as_logical(),
|
|
||||||
serial: SERIAL_COUNTER.next_serial(),
|
|
||||||
time: self.common.clock.now().as_millis(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let tablet_seat = seat.tablet_seat();
|
let tablet_seat = seat.tablet_seat();
|
||||||
|
|
||||||
|
|
@ -1680,6 +1726,25 @@ impl State {
|
||||||
if let Some(tablet) = tablet {
|
if let Some(tablet) = tablet {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
|
||||||
|
if !tool.is_grabbed()
|
||||||
|
&& under
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|(target, _)| !target.supports_tool(&tool))
|
||||||
|
{
|
||||||
|
let start_data = tool::GrabStartData {
|
||||||
|
focus: under.clone(),
|
||||||
|
trigger: tool::GrabTrigger::Proximity,
|
||||||
|
location: position.as_logical(),
|
||||||
|
};
|
||||||
|
tool.set_grab(
|
||||||
|
self,
|
||||||
|
PointerEmulationGrab::new(start_data, seat.clone()),
|
||||||
|
event.time(),
|
||||||
|
serial,
|
||||||
|
Focus::Keep,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let frame = tool::AxisFrame {
|
let frame = tool::AxisFrame {
|
||||||
pressure: event.pressure_has_changed().then(|| event.pressure()),
|
pressure: event.pressure_has_changed().then(|| event.pressure()),
|
||||||
distance: event.distance_has_changed().then(|| event.distance()),
|
distance: event.distance_has_changed().then(|| event.distance()),
|
||||||
|
|
@ -1695,9 +1760,6 @@ impl State {
|
||||||
|
|
||||||
match event.state() {
|
match event.state() {
|
||||||
ProximityState::In => {
|
ProximityState::In => {
|
||||||
let under = under.and_then(|(f, loc)| {
|
|
||||||
f.wl_surface().map(|s| (s.into_owned(), loc))
|
|
||||||
});
|
|
||||||
tool.proximity_in(
|
tool.proximity_in(
|
||||||
self,
|
self,
|
||||||
under,
|
under,
|
||||||
|
|
@ -1705,25 +1767,75 @@ impl State {
|
||||||
&tool::ProximityInEvent {
|
&tool::ProximityInEvent {
|
||||||
location: position.as_logical(),
|
location: position.as_logical(),
|
||||||
axis: Some(frame),
|
axis: Some(frame),
|
||||||
serial: SERIAL_COUNTER.next_serial(),
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
ProximityState::Out => tool.proximity_out(
|
ProximityState::Out => {
|
||||||
|
tool.proximity_out(
|
||||||
self,
|
self,
|
||||||
&tool::ProximityOutEvent {
|
&tool::ProximityOutEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
|
if let Some(pointer) = seat.get_pointer() {
|
||||||
|
pointer.motion(
|
||||||
|
self,
|
||||||
|
None,
|
||||||
|
&PointerMotionEvent {
|
||||||
|
location: position.as_logical(),
|
||||||
|
serial,
|
||||||
|
time: event.time(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tool.frame(self, event.time_msec());
|
tool.frame(self, event.time());
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.state() == ProximityState::In {
|
||||||
|
let mut shell = self.common.shell.write();
|
||||||
|
shell.update_pointer_position(position.to_local(&output), &output);
|
||||||
|
shell.update_focal_point(
|
||||||
|
&seat,
|
||||||
|
position,
|
||||||
|
self.common.config.cosmic_conf.accessibility_zoom.view_moves,
|
||||||
|
);
|
||||||
|
|
||||||
|
if output != current_output {
|
||||||
|
for session in cursor_sessions_for_output(&shell, ¤t_output) {
|
||||||
|
session.set_cursor_pos(None);
|
||||||
|
}
|
||||||
|
seat.set_active_output(&output);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_output_image_copy_cursor_position(
|
||||||
|
&shell,
|
||||||
|
&self.common.clock,
|
||||||
|
&output,
|
||||||
|
&seat,
|
||||||
|
position,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TabletToolTip { event, .. } => {
|
InputEvent::TabletToolTip { event, .. } => {
|
||||||
|
{
|
||||||
|
let mut shell = self.common.shell.write();
|
||||||
|
if let Some(Trigger::Tool(desc, trigger)) =
|
||||||
|
shell.overview_mode().0.active_trigger()
|
||||||
|
&& event.tool() == *desc
|
||||||
|
&& matches!(*trigger, tool::GrabTrigger::Tip)
|
||||||
|
&& event.tip_state() == TabletToolTipState::Up
|
||||||
|
{
|
||||||
|
shell.set_overview_mode(None, self.common.event_loop_handle.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let maybe_seat = self
|
let maybe_seat = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
@ -1734,6 +1846,21 @@ impl State {
|
||||||
if let Some(seat) = maybe_seat {
|
if let Some(seat) = maybe_seat {
|
||||||
self.common.idle_notifier_state.notify_activity(&seat);
|
self.common.idle_notifier_state.notify_activity(&seat);
|
||||||
notify_cursor_activity(self, &seat);
|
notify_cursor_activity(self, &seat);
|
||||||
|
|
||||||
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
|
let output = seat.active_output();
|
||||||
|
let shell = self.common.shell.write();
|
||||||
|
let position =
|
||||||
|
transform_output_mapped_position(&output, &event, shell.zoom_state());
|
||||||
|
let under = State::element_under(position, &output, &shell, &seat);
|
||||||
|
drop(shell);
|
||||||
|
|
||||||
|
if event.tip_state() == TabletToolTipState::Down
|
||||||
|
&& let Some(target) = under.as_ref()
|
||||||
|
{
|
||||||
|
Shell::set_focus(self, Some(target), &seat, Some(serial), false);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
match event.tip_state() {
|
match event.tip_state() {
|
||||||
|
|
@ -1742,7 +1869,7 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&tool::DownEvent {
|
&tool::DownEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1751,13 +1878,13 @@ impl State {
|
||||||
self,
|
self,
|
||||||
&tool::UpEvent {
|
&tool::UpEvent {
|
||||||
serial,
|
serial,
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tool.frame(self, event.time_msec());
|
tool.frame(self, event.time());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1779,11 +1906,11 @@ impl State {
|
||||||
button: event.button(),
|
button: event.button(),
|
||||||
state: event.button_state(),
|
state: event.button_state(),
|
||||||
serial: SERIAL_COUNTER.next_serial(),
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
time: event.time_msec(),
|
time: event.time(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
tool.frame(self, event.time_msec());
|
tool.frame(self, event.time());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1886,7 +2013,7 @@ impl State {
|
||||||
let Some(pointer) = seat.get_pointer() else {
|
let Some(pointer) = seat.get_pointer() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let time = self.common.clock.now().as_millis();
|
let time = InputTime::now();
|
||||||
for button in buttons {
|
for button in buttons {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
pointer.button(
|
pointer.button(
|
||||||
|
|
@ -1904,13 +2031,7 @@ impl State {
|
||||||
|
|
||||||
/// Mirror the seat's current modifier state to every libei sender with a keyboard via
|
/// Mirror the seat's current modifier state to every libei sender with a keyboard via
|
||||||
/// `ei_keyboard.modifiers`
|
/// `ei_keyboard.modifiers`
|
||||||
pub(crate) fn broadcast_ei_keyboard_modifiers(&self, seat: &Seat<State>) {
|
pub(crate) fn broadcast_ei_keyboard_modifiers(&self, keyboard: &KeyboardHandle<State>) {
|
||||||
if self.common.ei_seats.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let Some(keyboard) = seat.get_keyboard() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let s = keyboard.modifier_state().serialized;
|
let s = keyboard.modifier_state().serialized;
|
||||||
for ei_seat in self.common.ei_seats.values() {
|
for ei_seat in self.common.ei_seats.values() {
|
||||||
ei_seat.keyboard_modifiers(s.depressed, s.locked, s.latched, s.layout_effective);
|
ei_seat.keyboard_modifiers(s.depressed, s.locked, s.latched, s.layout_effective);
|
||||||
|
|
@ -1948,14 +2069,14 @@ impl State {
|
||||||
modifiers: &ModifiersState,
|
modifiers: &ModifiersState,
|
||||||
handle: KeysymHandle<'_>,
|
handle: KeysymHandle<'_>,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
keycode: Keycode,
|
keycode: Keycode,
|
||||||
key_state: KeyState,
|
key_state: KeyState,
|
||||||
previous_modifiers: ModifiersState,
|
previous_modifiers: ModifiersState,
|
||||||
) -> FilterResult<Option<(Action, shortcuts::Binding)>> {
|
) -> FilterResult<Option<(Action, shortcuts::Binding)>> {
|
||||||
if previous_modifiers != *modifiers {
|
if previous_modifiers != *modifiers {
|
||||||
seat.set_last_modifier_change(backend_id, serial);
|
seat.set_last_modifier_change(backend_id, serial);
|
||||||
self.broadcast_ei_keyboard_modifiers(seat);
|
self.broadcast_ei_keyboard_modifiers(&seat.get_keyboard().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_focus = seat.get_keyboard().unwrap().current_focus();
|
let current_focus = seat.get_keyboard().unwrap().current_focus();
|
||||||
|
|
@ -2008,7 +2129,7 @@ impl State {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let time = self.common.clock.now().as_millis();
|
let time = InputTime::now();
|
||||||
let previous_modifiers = keyboard.modifier_state();
|
let previous_modifiers = keyboard.modifier_state();
|
||||||
let result = keyboard
|
let result = keyboard
|
||||||
.input_from_source(
|
.input_from_source(
|
||||||
|
|
@ -2157,7 +2278,7 @@ impl State {
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
keycode: Keycode,
|
keycode: Keycode,
|
||||||
key_state: KeyState,
|
key_state: KeyState,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) -> FilterResult<Option<(Action, shortcuts::Binding)>> {
|
) -> FilterResult<Option<(Action, shortcuts::Binding)>> {
|
||||||
// Pre-compute for layout-agnostic shortcut matching
|
// Pre-compute for layout-agnostic shortcut matching
|
||||||
let raw_syms = handle.raw_syms();
|
let raw_syms = handle.raw_syms();
|
||||||
|
|
@ -2322,7 +2443,9 @@ impl State {
|
||||||
&backend_id_clone,
|
&backend_id_clone,
|
||||||
&seat_clone,
|
&seat_clone,
|
||||||
serial,
|
serial,
|
||||||
time.overflowing_add(duration as u32).0,
|
InputTime::from_millis(
|
||||||
|
time.millis().overflowing_add(duration as u32).0,
|
||||||
|
),
|
||||||
key_pattern_clone.clone(),
|
key_pattern_clone.clone(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
@ -2374,7 +2497,7 @@ impl State {
|
||||||
self.common.event_loop_handle.insert_idle(move |state| {
|
self.common.event_loop_handle.insert_idle(move |state| {
|
||||||
if let Some(keyboard) = seat.get_keyboard() {
|
if let Some(keyboard) = seat.get_keyboard() {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let time = state.common.clock.now().as_millis();
|
let time = InputTime::now();
|
||||||
keyboard.input(
|
keyboard.input(
|
||||||
state,
|
state,
|
||||||
key_code,
|
key_code,
|
||||||
|
|
@ -2900,6 +3023,7 @@ impl State {
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
pointer: &PointerHandle<Self>,
|
pointer: &PointerHandle<Self>,
|
||||||
mut location: Point<f64, Logical>,
|
mut location: Point<f64, Logical>,
|
||||||
|
constraint: Option<&PointerConstraint>,
|
||||||
) {
|
) {
|
||||||
let Some(client) = surface.client() else {
|
let Some(client) = surface.client() else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -2924,7 +3048,6 @@ impl State {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
with_pointer_constraint(surface, pointer, |constraint| {
|
|
||||||
if let Some(constraint) = constraint
|
if let Some(constraint) = constraint
|
||||||
&& let Some(region) = constraint.region()
|
&& let Some(region) = constraint.region()
|
||||||
{
|
{
|
||||||
|
|
@ -2932,7 +3055,6 @@ impl State {
|
||||||
return region.contains(point_in_surface);
|
return region.contains(point_in_surface);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let workspace_origin = output.geometry().loc.to_f64();
|
let workspace_origin = output.geometry().loc.to_f64();
|
||||||
|
|
@ -2956,23 +3078,23 @@ impl State {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let under = State::surface_under(point, &output, &self.common.shell.write())
|
let under = State::surface_under(point, &output, &self.common.shell.write())
|
||||||
.map(|(target, pos)| (target, pos.as_logical()));
|
.map(|(target, pos)| (target, pos.as_logical()));
|
||||||
let time = self.common.clock.now();
|
let time = InputTime::now();
|
||||||
pointer.relative_motion(
|
pointer.relative_motion(
|
||||||
self,
|
self,
|
||||||
under.clone(),
|
under.clone(),
|
||||||
&RelativeMotionEvent {
|
&RelativeMotionEvent {
|
||||||
delta: (0., 0.).into(),
|
delta: (0., 0.).into(),
|
||||||
delta_unaccel: (0., 0.).into(),
|
delta_unaccel: (0., 0.).into(),
|
||||||
utime: time.as_micros(),
|
time,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
pointer.motion(
|
pointer.motion(
|
||||||
self,
|
self,
|
||||||
under,
|
under,
|
||||||
&MotionEvent {
|
&PointerMotionEvent {
|
||||||
location: point.as_logical(),
|
location: point.as_logical(),
|
||||||
serial,
|
serial,
|
||||||
time: time.as_millis(),
|
time,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
pointer.frame(self);
|
pointer.frame(self);
|
||||||
|
|
|
||||||
256
src/input/tablet_emu.rs
Normal file
256
src/input/tablet_emu.rs
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
//! Pointer Emulating TabletTool grab.
|
||||||
|
|
||||||
|
use crate::{shell::focus::target::PointerFocusTarget, state::State};
|
||||||
|
use smithay::{
|
||||||
|
backend::input::{ButtonState, InputTime, MouseButton},
|
||||||
|
input::{
|
||||||
|
Seat, pointer,
|
||||||
|
tablet::{
|
||||||
|
self,
|
||||||
|
tool::{
|
||||||
|
AxisFrame, ButtonEvent, DownEvent, GrabStartData, ProximityInEvent,
|
||||||
|
ProximityOutEvent, TabletToolGrab, TabletToolInnerHandle, UpEvent,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
utils::{Logical, Point, SERIAL_COUNTER},
|
||||||
|
};
|
||||||
|
|
||||||
|
// from https://gitlab.freedesktop.org/libinput/libinput/-/blob/main/include/linux/linux/input-event-codes.h
|
||||||
|
const BTN_STYLUS: u32 = 0x14b;
|
||||||
|
const BTN_STYLUS_2: u32 = 0x14c;
|
||||||
|
const BTN_LEFT: u32 = 0x110;
|
||||||
|
const BTN_RIGHT: u32 = 0x111;
|
||||||
|
const BTN_MIDDLE: u32 = 0x112;
|
||||||
|
const BTN_FORWARD: u32 = 0x115;
|
||||||
|
const BTN_BACK: u32 = 0x116;
|
||||||
|
|
||||||
|
pub struct PointerEmulationGrab {
|
||||||
|
start_data: GrabStartData<State>,
|
||||||
|
seat: Seat<State>,
|
||||||
|
|
||||||
|
above_source: bool,
|
||||||
|
tip_down: bool,
|
||||||
|
button_down: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerEmulationGrab {
|
||||||
|
pub fn new(start_data: GrabStartData<State>, seat: Seat<State>) -> Self {
|
||||||
|
Self {
|
||||||
|
start_data,
|
||||||
|
seat,
|
||||||
|
|
||||||
|
above_source: true,
|
||||||
|
tip_down: false,
|
||||||
|
button_down: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button_to_mouse(&self, button: u32) -> Option<MouseButton> {
|
||||||
|
// FIXME: This should be configurable.
|
||||||
|
if button == BTN_STYLUS {
|
||||||
|
Some(MouseButton::Right)
|
||||||
|
} else if button == BTN_STYLUS_2 {
|
||||||
|
Some(MouseButton::Middle)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pointer_button(&self, data: &mut State, button: MouseButton, state: ButtonState) {
|
||||||
|
if let Some(pointer) = self.seat.get_pointer() {
|
||||||
|
let button = match button {
|
||||||
|
MouseButton::Left => BTN_LEFT,
|
||||||
|
MouseButton::Right => BTN_RIGHT,
|
||||||
|
MouseButton::Middle => BTN_MIDDLE,
|
||||||
|
MouseButton::Back => BTN_BACK,
|
||||||
|
MouseButton::Forward => BTN_FORWARD,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
pointer.button(
|
||||||
|
data,
|
||||||
|
&pointer::ButtonEvent {
|
||||||
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
|
button,
|
||||||
|
state,
|
||||||
|
time: InputTime::now(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
pointer.frame(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Type = tablet::tool::MotionEvent;
|
||||||
|
|
||||||
|
impl TabletToolGrab<State> for PointerEmulationGrab {
|
||||||
|
fn proximity_in(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
|
event: &ProximityInEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_in(data, focus.clone(), event);
|
||||||
|
|
||||||
|
if !self.above_source && !self.tip_down && self.button_down.is_empty() {
|
||||||
|
handle.unset_grab(
|
||||||
|
self,
|
||||||
|
data,
|
||||||
|
SERIAL_COUNTER.next_serial(),
|
||||||
|
InputTime::now(),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
} else if let Some(pointer) = self.seat.get_pointer() {
|
||||||
|
pointer.motion(
|
||||||
|
data,
|
||||||
|
focus,
|
||||||
|
&pointer::MotionEvent {
|
||||||
|
location: event.location,
|
||||||
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
|
time: InputTime::now(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
pointer.frame(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ProximityOutEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_out(data, event);
|
||||||
|
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &DownEvent,
|
||||||
|
) {
|
||||||
|
handle.down(data, event);
|
||||||
|
self.tip_down = true;
|
||||||
|
|
||||||
|
self.pointer_button(data, MouseButton::Left, ButtonState::Pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &UpEvent,
|
||||||
|
) {
|
||||||
|
handle.up(data, event);
|
||||||
|
|
||||||
|
self.pointer_button(data, MouseButton::Left, ButtonState::Released);
|
||||||
|
self.tip_down = false;
|
||||||
|
|
||||||
|
if !self.above_source && !self.tip_down && self.button_down.is_empty() {
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
|
event: &Type,
|
||||||
|
) {
|
||||||
|
self.above_source = focus.as_ref().map(|(target, _)| target)
|
||||||
|
== self.start_data.focus.as_ref().map(|(target, _)| target);
|
||||||
|
handle.motion(data, self.start_data.focus.clone(), event);
|
||||||
|
|
||||||
|
if !self.above_source && !self.tip_down && self.button_down.is_empty() {
|
||||||
|
handle.unset_grab(
|
||||||
|
self,
|
||||||
|
data,
|
||||||
|
SERIAL_COUNTER.next_serial(),
|
||||||
|
InputTime::now(),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
} else if let Some(pointer) = self.seat.get_pointer() {
|
||||||
|
pointer.motion(
|
||||||
|
data,
|
||||||
|
focus,
|
||||||
|
&pointer::MotionEvent {
|
||||||
|
location: event.location,
|
||||||
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
|
time: InputTime::now(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
pointer.frame(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ButtonEvent,
|
||||||
|
) {
|
||||||
|
handle.button(data, event);
|
||||||
|
|
||||||
|
self.button_down.retain(|b| b != &event.button);
|
||||||
|
if matches!(event.state, ButtonState::Pressed) {
|
||||||
|
self.button_down.push(event.button);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(button) = self.button_to_mouse(event.button) {
|
||||||
|
self.pointer_button(data, button, event.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.above_source && !self.tip_down && self.button_down.is_empty() {
|
||||||
|
handle.unset_grab(
|
||||||
|
self,
|
||||||
|
data,
|
||||||
|
SERIAL_COUNTER.next_serial(),
|
||||||
|
InputTime::now(),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
frame: AxisFrame,
|
||||||
|
) {
|
||||||
|
handle.axis(data, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
handle.frame(data, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(&mut self, data: &mut State) {
|
||||||
|
if self.tip_down {
|
||||||
|
self.pointer_button(data, MouseButton::Left, ButtonState::Released);
|
||||||
|
}
|
||||||
|
|
||||||
|
let buttons = std::mem::take(&mut self.button_down);
|
||||||
|
for button in buttons.into_iter() {
|
||||||
|
if let Some(button) = self.button_to_mouse(button) {
|
||||||
|
self.pointer_button(data, button, ButtonState::Released);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_data(&self) -> &GrabStartData<State> {
|
||||||
|
&self.start_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -124,7 +124,9 @@ pub fn setup_ei(
|
||||||
data.update_ei_input_method();
|
data.update_ei_input_method();
|
||||||
// Notify the remaining libei clients of the now-cleared modifier state
|
// Notify the remaining libei clients of the now-cleared modifier state
|
||||||
let seat = data.common.shell.read().seats.last_active().clone();
|
let seat = data.common.shell.read().seats.last_active().clone();
|
||||||
data.broadcast_ei_keyboard_modifiers(&seat);
|
if let Some(keyboard) = seat.get_keyboard() {
|
||||||
|
data.broadcast_ei_keyboard_modifiers(&keyboard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EiInputEvent::Event(event) => {
|
EiInputEvent::Event(event) => {
|
||||||
use smithay::backend::input::{InputEvent, KeyboardKeyEvent};
|
use smithay::backend::input::{InputEvent, KeyboardKeyEvent};
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use id_tree::NodeId;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
input::KeyState,
|
input::{InputTime, KeyState},
|
||||||
renderer::{
|
renderer::{
|
||||||
element::{
|
element::{
|
||||||
Element, Kind, RenderElement, UnderlyingStorage,
|
Element, Kind, RenderElement, UnderlyingStorage,
|
||||||
|
|
@ -1012,7 +1012,7 @@ impl KeyboardTarget<State> for CosmicMapped {
|
||||||
key: KeysymHandle<'_>,
|
key: KeysymHandle<'_>,
|
||||||
state: KeyState,
|
state: KeyState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Stack(s) => {
|
CosmicMappedInternal::Stack(s) => {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
shell::{
|
shell::{
|
||||||
element::{CosmicMappedKey, CosmicMappedKeyInner},
|
element::{CosmicMappedKey, CosmicMappedKeyInner},
|
||||||
focus::target::PointerFocusTarget,
|
focus::target::PointerFocusTarget,
|
||||||
grabs::{ReleaseMode, ResizeEdge},
|
grabs::{GrabType, ReleaseMode, ResizeEdge},
|
||||||
layout::tiling::NodeDesc,
|
layout::tiling::NodeDesc,
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
|
|
@ -38,7 +38,7 @@ use shortcuts::action::{Direction, FocusDirection};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
input::KeyState,
|
input::{InputTime, KeyState, TabletToolDescriptor},
|
||||||
renderer::{
|
renderer::{
|
||||||
ImportAll, ImportMem, Renderer,
|
ImportAll, ImportMem, Renderer,
|
||||||
element::{Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage},
|
element::{Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage},
|
||||||
|
|
@ -52,14 +52,23 @@ use smithay::{
|
||||||
Seat,
|
Seat,
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorImageStatus,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent,
|
||||||
PointerTarget, RelativeMotionEvent,
|
PointerTarget, RelativeMotionEvent,
|
||||||
},
|
},
|
||||||
|
tablet::{
|
||||||
|
Tablet, TabletSeatTrait,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent,
|
||||||
|
DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolTarget,
|
||||||
|
UpEvent as ToolUpEvent,
|
||||||
|
},
|
||||||
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent,
|
DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent,
|
||||||
TouchTarget, UpEvent,
|
OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -112,6 +121,7 @@ pub struct CosmicStackInternal {
|
||||||
previous_keyboard: AtomicUsize,
|
previous_keyboard: AtomicUsize,
|
||||||
pointer_entered: AtomicU8,
|
pointer_entered: AtomicU8,
|
||||||
touch_serial: AtomicU32,
|
touch_serial: AtomicU32,
|
||||||
|
tablet_serial: AtomicU32,
|
||||||
reenter: AtomicBool,
|
reenter: AtomicBool,
|
||||||
potential_drag: Mutex<Option<usize>>,
|
potential_drag: Mutex<Option<usize>>,
|
||||||
override_alive: AtomicBool,
|
override_alive: AtomicBool,
|
||||||
|
|
@ -171,6 +181,7 @@ impl CosmicStack {
|
||||||
previous_keyboard: AtomicUsize::new(0),
|
previous_keyboard: AtomicUsize::new(0),
|
||||||
pointer_entered: AtomicU8::new(0),
|
pointer_entered: AtomicU8::new(0),
|
||||||
touch_serial: AtomicU32::new(0),
|
touch_serial: AtomicU32::new(0),
|
||||||
|
tablet_serial: AtomicU32::new(0),
|
||||||
reenter: AtomicBool::new(false),
|
reenter: AtomicBool::new(false),
|
||||||
potential_drag: Mutex::new(None),
|
potential_drag: Mutex::new(None),
|
||||||
override_alive: AtomicBool::new(true),
|
override_alive: AtomicBool::new(true),
|
||||||
|
|
@ -831,7 +842,7 @@ impl CosmicStack {
|
||||||
)));
|
)));
|
||||||
};
|
};
|
||||||
|
|
||||||
let radii = radii.map(|[a, _, c, _]| [a, 0, c, 0]);
|
let radii = radii.map(|[_, _, c, d]| [0, 0, c, d]);
|
||||||
windows[active].push_render_elements(
|
windows[active].push_render_elements(
|
||||||
renderer,
|
renderer,
|
||||||
window_loc,
|
window_loc,
|
||||||
|
|
@ -909,12 +920,19 @@ impl CosmicStack {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
if let Some((grab, focus)) = res {
|
if let Some((grab, focus)) = res {
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
seat.get_pointer()
|
}
|
||||||
|
GrabType::Pointer => seat
|
||||||
|
.get_pointer()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(state, grab, serial, focus);
|
.set_grab(state, grab, serial, focus),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -997,17 +1015,17 @@ impl CosmicStack {
|
||||||
.corner_radius(geometry_size)
|
.corner_radius(geometry_size)
|
||||||
.unwrap_or([default_radius; 4]);
|
.unwrap_or([default_radius; 4]);
|
||||||
|
|
||||||
|
corners[0] = 0;
|
||||||
corners[1] = 0;
|
corners[1] = 0;
|
||||||
corners[3] = 0;
|
|
||||||
|
|
||||||
corners
|
corners
|
||||||
} else {
|
} else {
|
||||||
let mut corners = active_window.corner_radius(geometry_size).unwrap_or(radii);
|
let mut corners = active_window.corner_radius(geometry_size).unwrap_or(radii);
|
||||||
|
|
||||||
corners[0] = radii[0].max(corners[0]);
|
corners[0] = radii[0];
|
||||||
corners[1] = radii[1];
|
corners[1] = radii[1];
|
||||||
corners[2] = radii[2].max(corners[2]);
|
corners[2] = radii[2].max(corners[2]);
|
||||||
corners[3] = radii[3];
|
corners[3] = radii[3].max(corners[3]);
|
||||||
|
|
||||||
corners
|
corners
|
||||||
}
|
}
|
||||||
|
|
@ -1089,12 +1107,19 @@ impl Program for CosmicStackInternal {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
if let Some((grab, focus)) = res {
|
if let Some((grab, focus)) = res {
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
seat.get_pointer()
|
}
|
||||||
|
GrabType::Pointer => seat
|
||||||
|
.get_pointer()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(state, grab, serial, focus);
|
.set_grab(state, grab, serial, focus),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1547,7 +1572,7 @@ impl KeyboardTarget<State> for CosmicStack {
|
||||||
key: KeysymHandle<'_>,
|
key: KeysymHandle<'_>,
|
||||||
state: KeyState,
|
state: KeyState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
|
|
@ -1587,7 +1612,7 @@ impl KeyboardTarget<State> for CosmicStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerTarget<State> for CosmicStack {
|
impl PointerTarget<State> for CosmicStack {
|
||||||
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &PointerMotionEvent) {
|
||||||
let mut event = event.clone();
|
let mut event = event.clone();
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
||||||
|
|
@ -1615,7 +1640,7 @@ impl PointerTarget<State> for CosmicStack {
|
||||||
PointerTarget::enter(&self.0, seat, data, &event)
|
PointerTarget::enter(&self.0, seat, data, &event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &PointerMotionEvent) {
|
||||||
let mut event = event.clone();
|
let mut event = event.clone();
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
let active = p.active.load(Ordering::SeqCst);
|
let active = p.active.load(Ordering::SeqCst);
|
||||||
|
|
@ -1658,7 +1683,7 @@ impl PointerTarget<State> for CosmicStack {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &PointerButtonEvent) {
|
||||||
match self.0.with_program(|p| p.current_focus()) {
|
match self.0.with_program(|p| p.current_focus()) {
|
||||||
Some(Focus::Header) => PointerTarget::button(&self.0, seat, data, event),
|
Some(Focus::Header) => PointerTarget::button(&self.0, seat, data, event),
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
|
|
@ -1689,22 +1714,20 @@ impl PointerTarget<State> for CosmicStack {
|
||||||
state.common.config.cosmic_conf.edge_snap_threshold,
|
state.common.config.cosmic_conf.edge_snap_threshold,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
if let Some((grab, focus)) = res {
|
if let Some((grab, focus)) = res
|
||||||
if grab.is_touch_grab() {
|
&& let GrabType::Pointer = grab.grab_type()
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
{
|
||||||
} else {
|
|
||||||
seat.get_pointer()
|
seat.get_pointer()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(state, grab, serial, focus);
|
.set_grab(state, grab, serial, focus);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: PointerAxisFrame) {
|
||||||
if let Some(Focus::Header) = self.0.with_program(|p| p.current_focus()) {
|
if let Some(Focus::Header) = self.0.with_program(|p| p.current_focus()) {
|
||||||
PointerTarget::axis(&self.0, seat, data, frame)
|
PointerTarget::axis(&self.0, seat, data, frame)
|
||||||
}
|
}
|
||||||
|
|
@ -1716,7 +1739,7 @@ impl PointerTarget<State> for CosmicStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: InputTime) {
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
let mut cursor_state = seat
|
let mut cursor_state = seat
|
||||||
.user_data()
|
.user_data()
|
||||||
|
|
@ -1752,15 +1775,13 @@ impl PointerTarget<State> for CosmicStack {
|
||||||
&state.common.event_loop_handle,
|
&state.common.event_loop_handle,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
if let Some((grab, focus)) = res {
|
if let Some((grab, focus)) = res
|
||||||
if grab.is_touch_grab() {
|
&& let GrabType::Pointer = grab.grab_type()
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
{
|
||||||
} else {
|
|
||||||
seat.get_pointer()
|
seat.get_pointer()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(state, grab, serial, focus);
|
.set_grab(state, grab, serial, focus);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1832,7 +1853,7 @@ impl PointerTarget<State> for CosmicStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TouchTarget<State> for CosmicStack {
|
impl TouchTarget<State> for CosmicStack {
|
||||||
fn down(&self, seat: &Seat<State>, data: &mut State, event: &DownEvent) {
|
fn down(&self, seat: &Seat<State>, data: &mut State, event: &TouchDownEvent) {
|
||||||
let mut event = event.clone();
|
let mut event = event.clone();
|
||||||
let active_window_geo = self.0.with_program(|p| {
|
let active_window_geo = self.0.with_program(|p| {
|
||||||
p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry()
|
p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry()
|
||||||
|
|
@ -1843,7 +1864,7 @@ impl TouchTarget<State> for CosmicStack {
|
||||||
TouchTarget::down(&self.0, seat, data, &event)
|
TouchTarget::down(&self.0, seat, data, &event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&self, seat: &Seat<State>, data: &mut State, event: &UpEvent) {
|
fn up(&self, seat: &Seat<State>, data: &mut State, event: &TouchUpEvent) {
|
||||||
TouchTarget::up(&self.0, seat, data, event)
|
TouchTarget::up(&self.0, seat, data, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1891,6 +1912,185 @@ impl TouchTarget<State> for CosmicStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolTarget<State> for CosmicStack {
|
||||||
|
fn proximity_in(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
tablet: &Tablet,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::proximity_in(&self.0, seat, data, tool_descriptor, tablet, serial)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
) {
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
let mut cursor_state = seat
|
||||||
|
.user_data()
|
||||||
|
.get::<CursorState>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
cursor_state.unset_shape();
|
||||||
|
let _previous = p.swap_focus(None);
|
||||||
|
});
|
||||||
|
TabletToolTarget::proximity_out(&self.0, seat, data, tool_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolDownEvent,
|
||||||
|
) {
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
p.tablet_serial
|
||||||
|
.store(event.serial.into(), Ordering::Release)
|
||||||
|
});
|
||||||
|
match self.0.with_program(|p| p.current_focus()) {
|
||||||
|
Some(Focus::Header) => {
|
||||||
|
TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
Some(x) => {
|
||||||
|
let serial = self
|
||||||
|
.0
|
||||||
|
.with_program(|p| p.tablet_serial.load(Ordering::Acquire))
|
||||||
|
.into();
|
||||||
|
let seat = seat.clone();
|
||||||
|
let Some(surface) = self.0.with_program(|p| {
|
||||||
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
||||||
|
window.wl_surface().map(Cow::into_owned)
|
||||||
|
}) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.0.loop_handle().insert_idle(move |state| {
|
||||||
|
let res = state.common.shell.write().resize_request(
|
||||||
|
&surface,
|
||||||
|
&seat,
|
||||||
|
serial,
|
||||||
|
match x {
|
||||||
|
Focus::ResizeTop => ResizeEdge::TOP,
|
||||||
|
Focus::ResizeTopLeft => ResizeEdge::TOP_LEFT,
|
||||||
|
Focus::ResizeTopRight => ResizeEdge::TOP_RIGHT,
|
||||||
|
Focus::ResizeBottom => ResizeEdge::BOTTOM,
|
||||||
|
Focus::ResizeBottomLeft => ResizeEdge::BOTTOM_LEFT,
|
||||||
|
Focus::ResizeBottomRight => ResizeEdge::BOTTOM_RIGHT,
|
||||||
|
Focus::ResizeLeft => ResizeEdge::LEFT,
|
||||||
|
Focus::ResizeRight => ResizeEdge::RIGHT,
|
||||||
|
Focus::Header => unreachable!(),
|
||||||
|
},
|
||||||
|
state.common.config.cosmic_conf.edge_snap_threshold,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
if let Some((grab, focus)) = res
|
||||||
|
&& let GrabType::TabletTool = grab.grab_type()
|
||||||
|
{
|
||||||
|
seat.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolUpEvent,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::up(&self.0, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolMotionEvent,
|
||||||
|
) {
|
||||||
|
let mut event = event.clone();
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
let active = p.active.load(Ordering::SeqCst);
|
||||||
|
let active_window = &p.windows.lock().unwrap()[active];
|
||||||
|
let Some(next) = Focus::under(active_window, TAB_HEIGHT, event.location) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let _previous = p.swap_focus(Some(next));
|
||||||
|
|
||||||
|
let mut cursor_state = seat
|
||||||
|
.user_data()
|
||||||
|
.get::<CursorState>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
cursor_state.set_shape(next.cursor_shape());
|
||||||
|
seat.set_cursor_image_status(CursorImageStatus::default_named());
|
||||||
|
});
|
||||||
|
|
||||||
|
let active_window_geo = self.0.with_program(|p| {
|
||||||
|
p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry()
|
||||||
|
});
|
||||||
|
event.location -= active_window_geo.loc.to_f64();
|
||||||
|
|
||||||
|
TabletToolTarget::motion(&self.0, seat, data, tool_descriptor, &event);
|
||||||
|
if event.location.y < 0.0
|
||||||
|
|| event.location.y > TAB_HEIGHT as f64
|
||||||
|
|| event.location.x < 64.0
|
||||||
|
|| event.location.x > (active_window_geo.size.w as f64 - 64.0)
|
||||||
|
{
|
||||||
|
self.start_drag(
|
||||||
|
data,
|
||||||
|
seat,
|
||||||
|
self.0
|
||||||
|
.with_program(|p| p.tablet_serial.load(Ordering::Acquire))
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
frame: ToolAxisFrame,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::axis(&self.0, seat, data, tool_descriptor, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolButtonEvent,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::button(&self.0, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::frame(&self.0, seat, data, tool_descriptor, time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum CosmicStackRenderElement<R: Renderer + ImportAll + ImportMem> {
|
pub enum CosmicStackRenderElement<R: Renderer + ImportAll + ImportMem> {
|
||||||
Header(IcedRenderElement<R>),
|
Header(IcedRenderElement<R>),
|
||||||
Shadow(PixelShaderElement),
|
Shadow(PixelShaderElement),
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use cosmic::{
|
||||||
layout::{Layout, Limits, Node},
|
layout::{Layout, Limits, Node},
|
||||||
mouse, overlay, renderer,
|
mouse, overlay, renderer,
|
||||||
text::{Ellipsize, EllipsizeHeightLimit, Shaping, Wrapping},
|
text::{Ellipsize, EllipsizeHeightLimit, Shaping, Wrapping},
|
||||||
|
touch,
|
||||||
widget::{Id, Widget, operation::Operation, tree::Tree},
|
widget::{Id, Widget, operation::Operation, tree::Tree},
|
||||||
},
|
},
|
||||||
widget::{self, container::draw_background, rule::FillMode, scrollable::AbsoluteOffset},
|
widget::{self, container::draw_background, rule::FillMode, scrollable::AbsoluteOffset},
|
||||||
|
|
@ -370,6 +371,7 @@ where
|
||||||
if matches!(
|
if matches!(
|
||||||
event,
|
event,
|
||||||
event::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
|
event::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
|
||||||
|
| event::Event::Touch(touch::Event::FingerPressed { .. })
|
||||||
) && let Some(message) = self.press_message.clone()
|
) && let Some(message) = self.press_message.clone()
|
||||||
{
|
{
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
|
|
@ -388,6 +390,7 @@ where
|
||||||
if matches!(
|
if matches!(
|
||||||
event,
|
event,
|
||||||
event::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
event::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
||||||
|
| event::Event::Touch(touch::Event::FingerLifted { .. })
|
||||||
) {
|
) {
|
||||||
shell.publish(Message::activate(self.idx));
|
shell.publish(Message::activate(self.idx));
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ use keyframe::{
|
||||||
functions::{EaseInOutCubic, EaseOutCubic},
|
functions::{EaseInOutCubic, EaseOutCubic},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -757,12 +757,10 @@ where
|
||||||
state.last_state = Some(current_state.clone());
|
state.last_state = Some(current_state.clone());
|
||||||
}
|
}
|
||||||
let last_state = state.last_state.as_mut().unwrap();
|
let last_state = state.last_state.as_mut().unwrap();
|
||||||
let unknown_keys = current_state
|
let unknown_keys = current_state.len() != last_state.len()
|
||||||
|
|| current_state
|
||||||
.keys()
|
.keys()
|
||||||
.collect::<HashSet<_>>()
|
.any(|key| !last_state.contains_key(key));
|
||||||
.symmetric_difference(&last_state.keys().collect::<HashSet<_>>())
|
|
||||||
.next()
|
|
||||||
.is_some();
|
|
||||||
|
|
||||||
enum Difference {
|
enum Difference {
|
||||||
NewOrRemoved,
|
NewOrRemoved,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ use std::{
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
|
input::InputTime,
|
||||||
renderer::{
|
renderer::{
|
||||||
ImportAll, Renderer, buffer_has_alpha,
|
ImportAll, Renderer, buffer_has_alpha,
|
||||||
element::{Kind, RenderElementStates, surface::KindEvaluation},
|
element::{Kind, RenderElementStates, surface::KindEvaluation},
|
||||||
|
|
@ -1084,7 +1085,7 @@ impl KeyboardTarget<State> for CosmicSurface {
|
||||||
key: KeysymHandle<'_>,
|
key: KeysymHandle<'_>,
|
||||||
state: smithay::backend::input::KeyState,
|
state: smithay::backend::input::KeyState,
|
||||||
serial: smithay::utils::Serial,
|
serial: smithay::utils::Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
match self.0.underlying_surface() {
|
match self.0.underlying_surface() {
|
||||||
WindowSurface::Wayland(toplevel) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
shell::{
|
shell::{
|
||||||
element::{CosmicMappedKey, CosmicMappedKeyInner},
|
element::{CosmicMappedKey, CosmicMappedKeyInner},
|
||||||
focus::target::PointerFocusTarget,
|
focus::target::PointerFocusTarget,
|
||||||
grabs::{ReleaseMode, ResizeEdge},
|
grabs::{GrabType, ReleaseMode, ResizeEdge},
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -21,7 +21,7 @@ use cosmic_comp_config::AppearanceConfig;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
input::KeyState,
|
input::{InputTime, KeyState, TabletToolDescriptor},
|
||||||
renderer::{
|
renderer::{
|
||||||
ImportAll, ImportMem, Renderer,
|
ImportAll, ImportMem, Renderer,
|
||||||
element::{Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage},
|
element::{Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage},
|
||||||
|
|
@ -35,14 +35,23 @@ use smithay::{
|
||||||
Seat,
|
Seat,
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, CursorIcon, CursorImageStatus, GestureHoldBeginEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorIcon,
|
||||||
GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent,
|
CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
GestureSwipeUpdateEvent, MotionEvent, PointerTarget, RelativeMotionEvent,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent,
|
||||||
|
PointerTarget, RelativeMotionEvent,
|
||||||
|
},
|
||||||
|
tablet::{
|
||||||
|
Tablet, TabletSeatTrait,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent,
|
||||||
|
DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolTarget,
|
||||||
|
UpEvent as ToolUpEvent,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent,
|
DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent,
|
||||||
TouchTarget, UpEvent,
|
OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -429,12 +438,12 @@ impl CosmicWindow {
|
||||||
.map(|x| (x * scale as f32).round() as u8);
|
.map(|x| (x * scale as f32).round() as u8);
|
||||||
if has_ssd && !clip {
|
if has_ssd && !clip {
|
||||||
// bottom corners
|
// bottom corners
|
||||||
radii[0] = 0;
|
|
||||||
radii[2] = 0;
|
radii[2] = 0;
|
||||||
|
radii[3] = 0;
|
||||||
if is_tiled {
|
if is_tiled {
|
||||||
// top corners
|
// top corners
|
||||||
|
radii[0] = 0;
|
||||||
radii[1] = 0;
|
radii[1] = 0;
|
||||||
radii[3] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -501,12 +510,12 @@ impl CosmicWindow {
|
||||||
&& !is_maximized;
|
&& !is_maximized;
|
||||||
if has_ssd && !clip {
|
if has_ssd && !clip {
|
||||||
// bottom corners
|
// bottom corners
|
||||||
radii[0] = 0;
|
|
||||||
radii[2] = 0;
|
radii[2] = 0;
|
||||||
|
radii[3] = 0;
|
||||||
if is_tiled {
|
if is_tiled {
|
||||||
// top corners
|
// top corners
|
||||||
|
radii[0] = 0;
|
||||||
radii[1] = 0;
|
radii[1] = 0;
|
||||||
radii[3] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -551,8 +560,8 @@ impl CosmicWindow {
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
let mut radii = radii;
|
let mut radii = radii;
|
||||||
if has_ssd {
|
if has_ssd {
|
||||||
|
radii[0] = 0;
|
||||||
radii[1] = 0;
|
radii[1] = 0;
|
||||||
radii[3] = 0;
|
|
||||||
}
|
}
|
||||||
let theme = p.theme.lock().unwrap();
|
let theme = p.theme.lock().unwrap();
|
||||||
let frosted = if theme.cosmic().frosted_windows {
|
let frosted = if theme.cosmic().frosted_windows {
|
||||||
|
|
@ -576,8 +585,8 @@ impl CosmicWindow {
|
||||||
});
|
});
|
||||||
|
|
||||||
if has_ssd {
|
if has_ssd {
|
||||||
radii[0] = 0;
|
|
||||||
radii[2] = 0;
|
radii[2] = 0;
|
||||||
|
radii[3] = 0;
|
||||||
let ssd_loc = location
|
let ssd_loc = location
|
||||||
+ self
|
+ self
|
||||||
.0
|
.0
|
||||||
|
|
@ -682,26 +691,26 @@ impl CosmicWindow {
|
||||||
(has_ssd, true) => {
|
(has_ssd, true) => {
|
||||||
let mut corners = p.window.corner_radius(geometry_size).unwrap_or(radii);
|
let mut corners = p.window.corner_radius(geometry_size).unwrap_or(radii);
|
||||||
|
|
||||||
corners[0] = radii[0].max(corners[0]);
|
corners[0] = if has_ssd {
|
||||||
|
radii[0]
|
||||||
|
} else {
|
||||||
|
radii[0].max(corners[0])
|
||||||
|
};
|
||||||
corners[1] = if has_ssd {
|
corners[1] = if has_ssd {
|
||||||
radii[1]
|
radii[1]
|
||||||
} else {
|
} else {
|
||||||
radii[1].max(corners[1])
|
radii[1].max(corners[1])
|
||||||
};
|
};
|
||||||
corners[2] = radii[2].max(corners[2]);
|
corners[2] = radii[2].max(corners[2]);
|
||||||
corners[3] = if has_ssd {
|
corners[3] = radii[3].max(corners[3]);
|
||||||
radii[3]
|
|
||||||
} else {
|
|
||||||
radii[3].max(corners[3])
|
|
||||||
};
|
|
||||||
|
|
||||||
corners
|
corners
|
||||||
}
|
}
|
||||||
(true, false) => p
|
(true, false) => p
|
||||||
.window
|
.window
|
||||||
.corner_radius(geometry_size)
|
.corner_radius(geometry_size)
|
||||||
.map(|[a, _, c, _]| [a, radii[1], c, radii[3]])
|
.map(|[_, _, c, d]| [radii[0], radii[1], c, d])
|
||||||
.unwrap_or([default_radius, radii[1], default_radius, radii[3]]),
|
.unwrap_or([radii[0], radii[1], default_radius, default_radius]),
|
||||||
(false, false) => p
|
(false, false) => p
|
||||||
.window
|
.window
|
||||||
.corner_radius(geometry_size)
|
.corner_radius(geometry_size)
|
||||||
|
|
@ -746,12 +755,19 @@ impl Program for CosmicWindowInternal {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
if let Some((grab, focus)) = res {
|
if let Some((grab, focus)) = res {
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
seat.get_pointer()
|
}
|
||||||
|
GrabType::Pointer => seat
|
||||||
|
.get_pointer()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(state, grab, serial, focus);
|
.set_grab(state, grab, serial, focus),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -981,7 +997,7 @@ impl KeyboardTarget<State> for CosmicWindow {
|
||||||
key: KeysymHandle<'_>,
|
key: KeysymHandle<'_>,
|
||||||
state: KeyState,
|
state: KeyState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
self.0
|
self.0
|
||||||
.with_program(|p| KeyboardTarget::key(&p.window, seat, data, key, state, serial, time))
|
.with_program(|p| KeyboardTarget::key(&p.window, seat, data, key, state, serial, time))
|
||||||
|
|
@ -999,7 +1015,7 @@ impl KeyboardTarget<State> for CosmicWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerTarget<State> for CosmicWindow {
|
impl PointerTarget<State> for CosmicWindow {
|
||||||
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &PointerMotionEvent) {
|
||||||
let mut event = event.clone();
|
let mut event = event.clone();
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
let has_ssd = p.has_ssd(false);
|
let has_ssd = p.has_ssd(false);
|
||||||
|
|
@ -1012,8 +1028,7 @@ impl PointerTarget<State> for CosmicWindow {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let old_focus = p.swap_focus(Some(next));
|
let _ = p.swap_focus(Some(next));
|
||||||
assert_eq!(old_focus, None);
|
|
||||||
|
|
||||||
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
|
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
|
||||||
cursor_state.lock().unwrap().set_shape(next.cursor_shape());
|
cursor_state.lock().unwrap().set_shape(next.cursor_shape());
|
||||||
|
|
@ -1025,7 +1040,7 @@ impl PointerTarget<State> for CosmicWindow {
|
||||||
PointerTarget::enter(&self.0, seat, data, &event)
|
PointerTarget::enter(&self.0, seat, data, &event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &PointerMotionEvent) {
|
||||||
let mut event = event.clone();
|
let mut event = event.clone();
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
let has_ssd = p.has_ssd(false);
|
let has_ssd = p.has_ssd(false);
|
||||||
|
|
@ -1057,7 +1072,7 @@ impl PointerTarget<State> for CosmicWindow {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &PointerButtonEvent) {
|
||||||
match self.0.with_program(|p| p.current_focus()) {
|
match self.0.with_program(|p| p.current_focus()) {
|
||||||
Some(Focus::Header) => PointerTarget::button(&self.0, seat, data, event),
|
Some(Focus::Header) => PointerTarget::button(&self.0, seat, data, event),
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
|
|
@ -1093,14 +1108,12 @@ impl PointerTarget<State> for CosmicWindow {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some((grab, focus)) = res {
|
if let Some((grab, focus)) = res
|
||||||
if grab.is_touch_grab() {
|
&& let GrabType::Pointer = grab.grab_type()
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
{
|
||||||
} else {
|
|
||||||
seat.get_pointer()
|
seat.get_pointer()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(state, grab, serial, focus);
|
.set_grab(state, grab, serial, focus)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1108,7 +1121,7 @@ impl PointerTarget<State> for CosmicWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: PointerAxisFrame) {
|
||||||
if let Some(Focus::Header) = self.0.with_program(|p| p.current_focus()) {
|
if let Some(Focus::Header) = self.0.with_program(|p| p.current_focus()) {
|
||||||
PointerTarget::axis(&self.0, seat, data, frame)
|
PointerTarget::axis(&self.0, seat, data, frame)
|
||||||
}
|
}
|
||||||
|
|
@ -1120,7 +1133,7 @@ impl PointerTarget<State> for CosmicWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: InputTime) {
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
|
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
|
||||||
cursor_state.lock().unwrap().unset_shape();
|
cursor_state.lock().unwrap().unset_shape();
|
||||||
|
|
@ -1195,7 +1208,7 @@ impl PointerTarget<State> for CosmicWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TouchTarget<State> for CosmicWindow {
|
impl TouchTarget<State> for CosmicWindow {
|
||||||
fn down(&self, seat: &Seat<State>, data: &mut State, event: &DownEvent) {
|
fn down(&self, seat: &Seat<State>, data: &mut State, event: &TouchDownEvent) {
|
||||||
let mut event = event.clone();
|
let mut event = event.clone();
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
event.location -= p.window.geometry().loc.to_f64();
|
event.location -= p.window.geometry().loc.to_f64();
|
||||||
|
|
@ -1203,7 +1216,7 @@ impl TouchTarget<State> for CosmicWindow {
|
||||||
TouchTarget::down(&self.0, seat, data, &event)
|
TouchTarget::down(&self.0, seat, data, &event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&self, seat: &Seat<State>, data: &mut State, event: &UpEvent) {
|
fn up(&self, seat: &Seat<State>, data: &mut State, event: &TouchUpEvent) {
|
||||||
TouchTarget::up(&self.0, seat, data, event)
|
TouchTarget::up(&self.0, seat, data, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1234,6 +1247,155 @@ impl TouchTarget<State> for CosmicWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolTarget<State> for CosmicWindow {
|
||||||
|
fn proximity_in(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
tablet: &Tablet,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::proximity_in(&self.0, seat, data, tool_descriptor, tablet, serial)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
) {
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
|
||||||
|
cursor_state.lock().unwrap().unset_shape();
|
||||||
|
let _previous = p.swap_focus(None);
|
||||||
|
});
|
||||||
|
TabletToolTarget::proximity_out(&self.0, seat, data, tool_descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolDownEvent,
|
||||||
|
) {
|
||||||
|
match self.0.with_program(|p| p.current_focus()) {
|
||||||
|
Some(Focus::Header) => {
|
||||||
|
TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
Some(x) => {
|
||||||
|
let serial = event.serial;
|
||||||
|
let seat = seat.clone();
|
||||||
|
let Some(surface) = self.wl_surface().map(Cow::into_owned) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.0.loop_handle().insert_idle(move |state| {
|
||||||
|
let res = state.common.shell.write().resize_request(
|
||||||
|
&surface,
|
||||||
|
&seat,
|
||||||
|
serial,
|
||||||
|
match x {
|
||||||
|
Focus::ResizeTop => ResizeEdge::TOP,
|
||||||
|
Focus::ResizeTopLeft => ResizeEdge::TOP_LEFT,
|
||||||
|
Focus::ResizeTopRight => ResizeEdge::TOP_RIGHT,
|
||||||
|
Focus::ResizeBottom => ResizeEdge::BOTTOM,
|
||||||
|
Focus::ResizeBottomLeft => ResizeEdge::BOTTOM_LEFT,
|
||||||
|
Focus::ResizeBottomRight => ResizeEdge::BOTTOM_RIGHT,
|
||||||
|
Focus::ResizeLeft => ResizeEdge::LEFT,
|
||||||
|
Focus::ResizeRight => ResizeEdge::RIGHT,
|
||||||
|
Focus::Header => unreachable!(),
|
||||||
|
},
|
||||||
|
state.common.config.cosmic_conf.edge_snap_threshold,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some((grab, focus)) = res
|
||||||
|
&& let GrabType::TabletTool = grab.grab_type()
|
||||||
|
{
|
||||||
|
seat.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolUpEvent,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::up(&self.0, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolMotionEvent,
|
||||||
|
) {
|
||||||
|
let mut event = event.clone();
|
||||||
|
self.0.with_program(|p| {
|
||||||
|
let has_ssd = p.has_ssd(false);
|
||||||
|
if has_ssd || p.has_tiled_state() {
|
||||||
|
let Some(next) = Focus::under(
|
||||||
|
&p.window,
|
||||||
|
if has_ssd { SSD_HEIGHT } else { 0 },
|
||||||
|
event.location,
|
||||||
|
) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let _previous = p.swap_focus(Some(next));
|
||||||
|
|
||||||
|
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
|
||||||
|
cursor_state.lock().unwrap().set_shape(next.cursor_shape());
|
||||||
|
seat.set_cursor_image_status(CursorImageStatus::default_named());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
event.location -= self.0.with_program(|p| p.window.geometry().loc.to_f64());
|
||||||
|
TabletToolTarget::motion(&self.0, seat, data, tool_descriptor, &event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
frame: ToolAxisFrame,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::axis(&self.0, seat, data, tool_descriptor, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolButtonEvent,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::button(&self.0, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
TabletToolTarget::frame(&self.0, seat, data, tool_descriptor, time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WaylandFocus for CosmicWindow {
|
impl WaylandFocus for CosmicWindow {
|
||||||
fn wl_surface(&self) -> Option<Cow<'_, WlSurface>> {
|
fn wl_surface(&self) -> Option<Cow<'_, WlSurface>> {
|
||||||
self.0.with_program(|p| {
|
self.0.with_program(|p| {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
backend::input::InputTime,
|
||||||
desktop::{PopupUngrabStrategy, layer_map_for_output},
|
desktop::{PopupUngrabStrategy, layer_map_for_output},
|
||||||
input::{Seat, pointer::MotionEvent},
|
input::{Seat, pointer::MotionEvent},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -419,7 +420,7 @@ fn update_focus_state(
|
||||||
&MotionEvent {
|
&MotionEvent {
|
||||||
location: new_pos.as_logical(),
|
location: new_pos.as_logical(),
|
||||||
serial: SERIAL_COUNTER.next_serial(),
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
time: 0,
|
time: InputTime::now(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -768,7 +769,7 @@ fn update_pointer_focus(state: &mut State, seat: &Seat<State>) {
|
||||||
&MotionEvent {
|
&MotionEvent {
|
||||||
location: pointer.current_location(),
|
location: pointer.current_location(),
|
||||||
serial: SERIAL_COUNTER.next_serial(),
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
time: state.common.clock.now().as_millis(),
|
time: InputTime::now(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,21 +16,30 @@ use crate::{
|
||||||
};
|
};
|
||||||
use id_tree::NodeId;
|
use id_tree::NodeId;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::KeyState,
|
backend::input::{InputTime, KeyState, TabletToolDescriptor},
|
||||||
desktop::{LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, space::SpaceElement},
|
desktop::{LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, space::SpaceElement},
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
dnd::{DndFocus, OfferData, Source},
|
dnd::{DndFocus, OfferData, Source},
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent,
|
||||||
|
PointerTarget, RelativeMotionEvent,
|
||||||
|
},
|
||||||
|
tablet::{
|
||||||
|
Tablet,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent,
|
||||||
|
DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolHandle,
|
||||||
|
TabletToolTarget, UpEvent as ToolUpEvent,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent,
|
DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent,
|
||||||
TouchTarget, UpEvent,
|
OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reexports::wayland_server::{
|
reexports::wayland_server::{
|
||||||
|
|
@ -164,6 +173,17 @@ impl PointerFocusTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inner_tablet_tool_target(&self) -> &dyn TabletToolTarget<State> {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface { surface, .. } => surface,
|
||||||
|
PointerFocusTarget::X11Surface { surface, .. } => surface,
|
||||||
|
PointerFocusTarget::StackUI(u) => u,
|
||||||
|
PointerFocusTarget::WindowUI(u) => u,
|
||||||
|
PointerFocusTarget::ResizeFork(f) => f,
|
||||||
|
PointerFocusTarget::ZoomUI(e) => e,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn under_surface<P: Into<Point<f64, Logical>>>(
|
pub fn under_surface<P: Into<Point<f64, Logical>>>(
|
||||||
surface: &CosmicSurface,
|
surface: &CosmicSurface,
|
||||||
point: P,
|
point: P,
|
||||||
|
|
@ -272,9 +292,10 @@ impl PointerFocusTarget {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let cursor_hotspot = if let Some(CursorGeometry { hotspot, .. }) =
|
let cursor_hotspot = if let Some(CursorGeometry { hotspot, .. }) = seat.cursor_geometry(
|
||||||
seat.cursor_geometry((0.0, 0.0), Duration::from_millis(event.time as u64).into())
|
(0.0, 0.0),
|
||||||
{
|
Duration::from_millis(event.time.millis() as u64).into(),
|
||||||
|
) {
|
||||||
hotspot
|
hotspot
|
||||||
} else {
|
} else {
|
||||||
Point::from((0, 0))
|
Point::from((0, 0))
|
||||||
|
|
@ -285,6 +306,16 @@ impl PointerFocusTarget {
|
||||||
session.set_cursor_hotspot(cursor_hotspot);
|
session.set_cursor_hotspot(cursor_hotspot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn supports_tool(&self, tool_handle: &TabletToolHandle<State>) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::WlSurface { surface, .. } if surface.client().is_some() => tool_handle
|
||||||
|
.client_tools(&surface.client().unwrap())
|
||||||
|
.next()
|
||||||
|
.is_some(),
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardFocusTarget {
|
impl KeyboardFocusTarget {
|
||||||
|
|
@ -408,16 +439,16 @@ impl PointerTarget<State> for PointerFocusTarget {
|
||||||
self.inner_pointer_target()
|
self.inner_pointer_target()
|
||||||
.relative_motion(seat, data, event);
|
.relative_motion(seat, data, event);
|
||||||
}
|
}
|
||||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &PointerButtonEvent) {
|
||||||
self.inner_pointer_target().button(seat, data, event);
|
self.inner_pointer_target().button(seat, data, event);
|
||||||
}
|
}
|
||||||
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: PointerAxisFrame) {
|
||||||
self.inner_pointer_target().axis(seat, data, frame);
|
self.inner_pointer_target().axis(seat, data, frame);
|
||||||
}
|
}
|
||||||
fn frame(&self, seat: &Seat<State>, data: &mut State) {
|
fn frame(&self, seat: &Seat<State>, data: &mut State) {
|
||||||
self.inner_pointer_target().frame(seat, data);
|
self.inner_pointer_target().frame(seat, data);
|
||||||
}
|
}
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: InputTime) {
|
||||||
let toplevel = self.toplevel(&data.common.shell.read());
|
let toplevel = self.toplevel(&data.common.shell.read());
|
||||||
if let Some(element) = toplevel {
|
if let Some(element) = toplevel {
|
||||||
for session in element.cursor_sessions() {
|
for session in element.cursor_sessions() {
|
||||||
|
|
@ -497,12 +528,102 @@ impl PointerTarget<State> for PointerFocusTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolTarget<State> for PointerFocusTarget {
|
||||||
|
fn proximity_in(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
tablet: &Tablet,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
self.inner_tablet_tool_target()
|
||||||
|
.proximity_in(seat, data, tool_descriptor, tablet, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
) {
|
||||||
|
self.inner_tablet_tool_target()
|
||||||
|
.proximity_out(seat, data, tool_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolDownEvent,
|
||||||
|
) {
|
||||||
|
self.inner_tablet_tool_target()
|
||||||
|
.down(seat, data, tool_descriptor, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolUpEvent,
|
||||||
|
) {
|
||||||
|
self.inner_tablet_tool_target()
|
||||||
|
.up(seat, data, tool_descriptor, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolMotionEvent,
|
||||||
|
) {
|
||||||
|
self.inner_tablet_tool_target()
|
||||||
|
.motion(seat, data, tool_descriptor, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
frame: ToolAxisFrame,
|
||||||
|
) {
|
||||||
|
self.inner_tablet_tool_target()
|
||||||
|
.axis(seat, data, tool_descriptor, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolButtonEvent,
|
||||||
|
) {
|
||||||
|
self.inner_tablet_tool_target()
|
||||||
|
.button(seat, data, tool_descriptor, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
self.inner_tablet_tool_target()
|
||||||
|
.frame(seat, data, tool_descriptor, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TouchTarget<State> for PointerFocusTarget {
|
impl TouchTarget<State> for PointerFocusTarget {
|
||||||
fn down(&self, seat: &Seat<State>, data: &mut State, event: &DownEvent) {
|
fn down(&self, seat: &Seat<State>, data: &mut State, event: &TouchDownEvent) {
|
||||||
self.inner_touch_target().down(seat, data, event);
|
self.inner_touch_target().down(seat, data, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&self, seat: &Seat<State>, data: &mut State, event: &UpEvent) {
|
fn up(&self, seat: &Seat<State>, data: &mut State, event: &TouchUpEvent) {
|
||||||
self.inner_touch_target().up(seat, data, event);
|
self.inner_touch_target().up(seat, data, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -593,7 +714,7 @@ impl DndFocus<State> for PointerFocusTarget {
|
||||||
offer: Option<&mut CosmicOfferData<S>>,
|
offer: Option<&mut CosmicOfferData<S>>,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
PointerFocusTarget::WlSurface { surface, .. } => {
|
PointerFocusTarget::WlSurface { surface, .. } => {
|
||||||
|
|
@ -695,7 +816,7 @@ impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
key: KeysymHandle<'_>,
|
key: KeysymHandle<'_>,
|
||||||
state: KeyState,
|
state: KeyState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
if let Some(inner) = self.inner_keyboard_target() {
|
if let Some(inner) = self.inner_keyboard_target() {
|
||||||
inner.key(seat, data, key, state, serial, time);
|
inner.key(seat, data, key, state, serial, time);
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,34 @@
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
backend::input::{InputTime, TabletToolDescriptor},
|
||||||
input::{
|
input::{
|
||||||
Seat, SeatHandler,
|
Seat, SeatHandler,
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, Focus, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, Focus,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
GrabStartData as PointerGrabStartData, MotionEvent as PointerMotionEvent, PointerGrab,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData,
|
||||||
PointerInnerHandle, RelativeMotionEvent,
|
MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle,
|
||||||
|
RelativeMotionEvent,
|
||||||
|
},
|
||||||
|
tablet::{
|
||||||
|
TabletSeatHandler, TabletSeatTrait,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent,
|
||||||
|
DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData,
|
||||||
|
MotionEvent as TabletMotionEvent, ProximityInEvent, ProximityOutEvent,
|
||||||
|
TabletToolGrab, TabletToolInnerHandle, UpEvent as TabletUpEvent,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent,
|
DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData,
|
||||||
OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, UpEvent,
|
MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab,
|
||||||
|
TouchInnerHandle, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
utils::{Logical, Point, SERIAL_COUNTER, Serial},
|
utils::{Logical, Point, SERIAL_COUNTER, Serial},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::{shell::grabs::GrabType, state::State};
|
||||||
|
|
||||||
use super::GrabStartData;
|
use super::GrabStartData;
|
||||||
|
|
||||||
|
|
@ -44,10 +56,15 @@ impl<G> DelayGrab<G> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_touch_grab(&self) -> bool {
|
pub fn grab_type(&self) -> GrabType {
|
||||||
match self.start_data {
|
self.start_data.type_()
|
||||||
GrabStartData::Touch(_) => true,
|
}
|
||||||
GrabStartData::Pointer(_) => false,
|
|
||||||
|
pub fn tool(&self) -> Option<&TabletToolDescriptor> {
|
||||||
|
if let GrabStartData::TabletTool { tool, .. } = &self.start_data {
|
||||||
|
Some(tool)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +109,7 @@ impl<G: PointerGrab<State>> PointerGrab<State> for DelayGrab<G> {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
event: &ButtonEvent,
|
event: &PointerButtonEvent,
|
||||||
) {
|
) {
|
||||||
handle.button(data, event);
|
handle.button(data, event);
|
||||||
if handle.current_pressed().is_empty() {
|
if handle.current_pressed().is_empty() {
|
||||||
|
|
@ -104,7 +121,7 @@ impl<G: PointerGrab<State>> PointerGrab<State> for DelayGrab<G> {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
details: AxisFrame,
|
details: PointerAxisFrame,
|
||||||
) {
|
) {
|
||||||
handle.axis(data, details);
|
handle.axis(data, details);
|
||||||
}
|
}
|
||||||
|
|
@ -201,12 +218,17 @@ impl<G: TouchGrab<State>> TouchGrab<State> for DelayGrab<G> {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
focus: Option<(<State as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
|
focus: Option<(<State as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
|
||||||
event: &DownEvent,
|
event: &TouchDownEvent,
|
||||||
) {
|
) {
|
||||||
handle.down(data, focus, event);
|
handle.down(data, focus, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) {
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
|
event: &TouchUpEvent,
|
||||||
|
) {
|
||||||
handle.up(data, event);
|
handle.up(data, event);
|
||||||
|
|
||||||
if event.slot == TouchGrab::start_data(self).slot {
|
if event.slot == TouchGrab::start_data(self).slot {
|
||||||
|
|
@ -273,3 +295,110 @@ impl<G: TouchGrab<State>> TouchGrab<State> for DelayGrab<G> {
|
||||||
|
|
||||||
fn unset(&mut self, _data: &mut State) {}
|
fn unset(&mut self, _data: &mut State) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<G: TabletToolGrab<State>> TabletToolGrab<State> for DelayGrab<G> {
|
||||||
|
fn start_data(&self) -> &TabletGrabStartData<State> {
|
||||||
|
match &self.start_data {
|
||||||
|
GrabStartData::TabletTool { data, .. } => data,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ProximityOutEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_out(data, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
handle.motion(data, focus, event);
|
||||||
|
|
||||||
|
let distance = self.start_data.distance(event.location);
|
||||||
|
if distance >= 1.
|
||||||
|
&& let Some(factory) = self.grab_factory.take()
|
||||||
|
{
|
||||||
|
let seat = self.seat.clone();
|
||||||
|
let serial = self.serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial());
|
||||||
|
let time = InputTime::now();
|
||||||
|
let Some(tool) = self.tool().cloned() else {
|
||||||
|
handle.unset_grab(self, data, serial, time, true);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
data.common.event_loop_handle.insert_idle(move |data| {
|
||||||
|
if let Some((grab, focus)) = factory(data) {
|
||||||
|
seat.tablet_seat()
|
||||||
|
.get_tool(&tool)
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(data, grab, time, serial, focus);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
handle.down(data, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
handle.up(data, event);
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
handle.button(data, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
frame: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
handle.axis(data, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
handle.frame(data, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(&mut self, _data: &mut State) {}
|
||||||
|
|
||||||
|
fn proximity_in(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &ProximityInEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_in(data, focus, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
use cosmic_settings_config::shortcuts::Action;
|
use cosmic_settings_config::shortcuts::Action;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
input::pointer::MotionEvent, reexports::wayland_server::protocol::wl_surface::WlSurface,
|
backend::input::InputTime,
|
||||||
utils::SERIAL_COUNTER, wayland::seat::WaylandFocus,
|
input::{pointer::MotionEvent, tablet::TabletSeatTrait},
|
||||||
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
|
utils::SERIAL_COUNTER,
|
||||||
|
wayland::seat::WaylandFocus,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -10,7 +13,7 @@ use crate::{
|
||||||
shell::{
|
shell::{
|
||||||
CosmicSurface, PointGlobalExt, Shell,
|
CosmicSurface, PointGlobalExt, Shell,
|
||||||
element::{CosmicMapped, CosmicWindow},
|
element::{CosmicMapped, CosmicWindow},
|
||||||
grabs::ReleaseMode,
|
grabs::{GrabType, ReleaseMode},
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{prelude::SeatExt, screenshot::screenshot_window},
|
utils::{prelude::SeatExt, screenshot::screenshot_window},
|
||||||
|
|
@ -352,19 +355,20 @@ pub fn window_items(
|
||||||
|
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if let Some((grab, focus)) = res {
|
if let Some((grab, focus)) = res {
|
||||||
if grab.is_touch_grab() {
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
seat.get_touch().unwrap().set_grab(
|
match grab.grab_type() {
|
||||||
state,
|
GrabType::Touch => {
|
||||||
grab,
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
SERIAL_COUNTER.next_serial(),
|
}
|
||||||
)
|
GrabType::Pointer => seat
|
||||||
} else {
|
.get_pointer()
|
||||||
seat.get_pointer().unwrap().set_grab(
|
.unwrap()
|
||||||
state,
|
.set_grab(state, grab, serial, focus),
|
||||||
grab,
|
GrabType::TabletTool => seat
|
||||||
SERIAL_COUNTER.next_serial(),
|
.tablet_seat()
|
||||||
focus,
|
.get_tool(grab.tool().unwrap())
|
||||||
);
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -388,9 +392,16 @@ pub fn window_items(
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if let Some(((target, loc), (grab, focus))) = res {
|
if let Some(((target, loc), (grab, focus))) = res {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
|
}
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus),
|
||||||
|
GrabType::Pointer => {
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.motion(
|
pointer.motion(
|
||||||
state,
|
state,
|
||||||
|
|
@ -398,13 +409,14 @@ pub fn window_items(
|
||||||
&MotionEvent {
|
&MotionEvent {
|
||||||
location: loc.as_logical().to_f64(),
|
location: loc.as_logical().to_f64(),
|
||||||
serial,
|
serial,
|
||||||
time: state.common.clock.now().as_millis(),
|
time: InputTime::now(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
pointer.frame(state);
|
pointer.frame(state);
|
||||||
pointer.set_grab(state, grab, serial, focus);
|
pointer.set_grab(state, grab, serial, focus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.disabled(!possible_resizes.contains(ResizeEdge::TOP)),
|
.disabled(!possible_resizes.contains(ResizeEdge::TOP)),
|
||||||
|
|
@ -423,9 +435,11 @@ pub fn window_items(
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if let Some(((target, loc), (grab, focus))) = res {
|
if let Some(((target, loc), (grab, focus))) = res {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
|
}
|
||||||
|
GrabType::Pointer => {
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.motion(
|
pointer.motion(
|
||||||
state,
|
state,
|
||||||
|
|
@ -433,12 +447,19 @@ pub fn window_items(
|
||||||
&MotionEvent {
|
&MotionEvent {
|
||||||
location: loc.as_logical().to_f64(),
|
location: loc.as_logical().to_f64(),
|
||||||
serial,
|
serial,
|
||||||
time: state.common.clock.now().as_millis(),
|
time: InputTime::now(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
pointer.frame(state);
|
pointer.frame(state);
|
||||||
pointer.set_grab(state, grab, serial, focus);
|
pointer.set_grab(state, grab, serial, focus);
|
||||||
}
|
}
|
||||||
|
GrabType::TabletTool => {
|
||||||
|
seat.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -458,9 +479,11 @@ pub fn window_items(
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if let Some(((target, loc), (grab, focus))) = res {
|
if let Some(((target, loc), (grab, focus))) = res {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
|
}
|
||||||
|
GrabType::Pointer => {
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.motion(
|
pointer.motion(
|
||||||
state,
|
state,
|
||||||
|
|
@ -468,12 +491,19 @@ pub fn window_items(
|
||||||
&MotionEvent {
|
&MotionEvent {
|
||||||
location: loc.as_logical().to_f64(),
|
location: loc.as_logical().to_f64(),
|
||||||
serial,
|
serial,
|
||||||
time: state.common.clock.now().as_millis(),
|
time: InputTime::now(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
pointer.frame(state);
|
pointer.frame(state);
|
||||||
pointer.set_grab(state, grab, serial, focus);
|
pointer.set_grab(state, grab, serial, focus);
|
||||||
}
|
}
|
||||||
|
GrabType::TabletTool => {
|
||||||
|
seat.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -493,9 +523,11 @@ pub fn window_items(
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if let Some(((target, loc), (grab, focus))) = res {
|
if let Some(((target, loc), (grab, focus))) = res {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
|
}
|
||||||
|
GrabType::Pointer => {
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.motion(
|
pointer.motion(
|
||||||
state,
|
state,
|
||||||
|
|
@ -503,12 +535,18 @@ pub fn window_items(
|
||||||
&MotionEvent {
|
&MotionEvent {
|
||||||
location: loc.as_logical().to_f64(),
|
location: loc.as_logical().to_f64(),
|
||||||
serial,
|
serial,
|
||||||
time: state.common.clock.now().as_millis(),
|
time: InputTime::now(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
pointer.frame(state);
|
pointer.frame(state);
|
||||||
pointer.set_grab(state, grab, serial, focus);
|
pointer.set_grab(state, grab, serial, focus);
|
||||||
}
|
}
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -627,19 +665,20 @@ pub fn fullscreen_items(window: &CosmicSurface, config: &Config) -> impl Iterato
|
||||||
|
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if let Some((grab, focus)) = res {
|
if let Some((grab, focus)) = res {
|
||||||
if grab.is_touch_grab() {
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
seat.get_touch().unwrap().set_grab(
|
match grab.grab_type() {
|
||||||
state,
|
GrabType::Touch => {
|
||||||
grab,
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
SERIAL_COUNTER.next_serial(),
|
}
|
||||||
)
|
GrabType::Pointer => seat
|
||||||
} else {
|
.get_pointer()
|
||||||
seat.get_pointer().unwrap().set_grab(
|
.unwrap()
|
||||||
state,
|
.set_grab(state, grab, serial, focus),
|
||||||
grab,
|
GrabType::TabletTool => seat
|
||||||
SERIAL_COUNTER.next_serial(),
|
.tablet_seat()
|
||||||
focus,
|
.get_tool(grab.tool().unwrap())
|
||||||
);
|
.unwrap()
|
||||||
|
.set_grab(state, grab, InputTime::now(), serial, focus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,22 +19,33 @@ use cosmic::{
|
||||||
};
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
input::{ButtonState, TouchSlot},
|
input::{ButtonState, InputTime, TabletToolDescriptor, TouchSlot},
|
||||||
renderer::ImportMem,
|
renderer::ImportMem,
|
||||||
},
|
},
|
||||||
desktop::space::SpaceElement,
|
desktop::space::SpaceElement,
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
GrabStartData as PointerGrabStartData, MotionEvent as PointerMotionEvent, PointerGrab,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData,
|
||||||
PointerInnerHandle, PointerTarget, RelativeMotionEvent,
|
MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle, PointerTarget,
|
||||||
|
RelativeMotionEvent,
|
||||||
|
},
|
||||||
|
tablet::{
|
||||||
|
TabletSeatHandler,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent,
|
||||||
|
DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData,
|
||||||
|
MotionEvent as TabletMotionEvent, ProximityInEvent, ProximityOutEvent,
|
||||||
|
TabletToolGrab, TabletToolInnerHandle, TabletToolTarget, UpEvent as TabletUpEvent,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent,
|
DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData,
|
||||||
TouchGrab, TouchInnerHandle, TouchTarget, UpEvent,
|
MotionEvent as TouchMotionEvent, TouchGrab, TouchInnerHandle, TouchTarget,
|
||||||
|
UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -43,7 +54,7 @@ use smithay::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::element::AsGlowRenderer,
|
backend::render::element::AsGlowRenderer,
|
||||||
shell::{SeatExt, focus::target::PointerFocusTarget},
|
shell::{SeatExt, focus::target::PointerFocusTarget, grabs::GrabType},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
iced::{IcedElement, IcedRenderElement, Program},
|
iced::{IcedElement, IcedRenderElement, Program},
|
||||||
|
|
@ -350,6 +361,7 @@ impl Program for ContextMenu {
|
||||||
position,
|
position,
|
||||||
pointer_entered: false,
|
pointer_entered: false,
|
||||||
touch_entered: None,
|
touch_entered: None,
|
||||||
|
tablet_entered: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -509,6 +521,7 @@ pub struct Element {
|
||||||
position: Point<i32, Global>,
|
position: Point<i32, Global>,
|
||||||
pointer_entered: bool,
|
pointer_entered: bool,
|
||||||
touch_entered: Option<TouchSlot>,
|
touch_entered: Option<TouchSlot>,
|
||||||
|
tablet_entered: Option<TabletToolDescriptor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MenuGrab {
|
pub struct MenuGrab {
|
||||||
|
|
@ -517,6 +530,7 @@ pub struct MenuGrab {
|
||||||
seat: Seat<State>,
|
seat: Seat<State>,
|
||||||
screen_space_relative: Option<Output>,
|
screen_space_relative: Option<Output>,
|
||||||
scale: Arc<Mutex<f64>>,
|
scale: Arc<Mutex<f64>>,
|
||||||
|
last_tablet_idx: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerGrab<State> for MenuGrab {
|
impl PointerGrab<State> for MenuGrab {
|
||||||
|
|
@ -599,7 +613,7 @@ impl PointerGrab<State> for MenuGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
event: &ButtonEvent,
|
event: &PointerButtonEvent,
|
||||||
) {
|
) {
|
||||||
let any_entered = self
|
let any_entered = self
|
||||||
.elements
|
.elements
|
||||||
|
|
@ -633,7 +647,7 @@ impl PointerGrab<State> for MenuGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
details: AxisFrame,
|
details: PointerAxisFrame,
|
||||||
) {
|
) {
|
||||||
handle.axis(state, details);
|
handle.axis(state, details);
|
||||||
}
|
}
|
||||||
|
|
@ -730,7 +744,7 @@ impl TouchGrab<State> for MenuGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &DownEvent,
|
event: &TouchDownEvent,
|
||||||
) {
|
) {
|
||||||
{
|
{
|
||||||
let mut guard = self.elements.lock().unwrap();
|
let mut guard = self.elements.lock().unwrap();
|
||||||
|
|
@ -758,7 +772,7 @@ impl TouchGrab<State> for MenuGrab {
|
||||||
}) {
|
}) {
|
||||||
let element = &mut elements[i];
|
let element = &mut elements[i];
|
||||||
|
|
||||||
let new_event = DownEvent {
|
let new_event = TouchDownEvent {
|
||||||
slot: event.slot,
|
slot: event.slot,
|
||||||
location: event_location - element.position.as_logical().to_f64(),
|
location: event_location - element.position.as_logical().to_f64(),
|
||||||
serial: event.serial,
|
serial: event.serial,
|
||||||
|
|
@ -773,7 +787,12 @@ impl TouchGrab<State> for MenuGrab {
|
||||||
handle.down(data, None, event);
|
handle.down(data, None, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) {
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
|
event: &TouchUpEvent,
|
||||||
|
) {
|
||||||
{
|
{
|
||||||
let elements = self.elements.lock().unwrap();
|
let elements = self.elements.lock().unwrap();
|
||||||
for element in elements.iter().filter(|elem| {
|
for element in elements.iter().filter(|elem| {
|
||||||
|
|
@ -849,6 +868,248 @@ impl TouchGrab<State> for MenuGrab {
|
||||||
fn unset(&mut self, _data: &mut State) {}
|
fn unset(&mut self, _data: &mut State) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolGrab<State> for MenuGrab {
|
||||||
|
fn start_data(&self) -> &TabletGrabStartData<State> {
|
||||||
|
match &self.start_data {
|
||||||
|
GrabStartData::TabletTool { data, .. } => data,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_in(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
_focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &ProximityInEvent,
|
||||||
|
) {
|
||||||
|
{
|
||||||
|
let location = if let Some(output) = self.screen_space_relative.as_ref() {
|
||||||
|
if data.common.shell.read().zoom_state().is_some() {
|
||||||
|
event
|
||||||
|
.location
|
||||||
|
.as_global()
|
||||||
|
.to_zoomed(output)
|
||||||
|
.to_global(output)
|
||||||
|
.as_logical()
|
||||||
|
} else {
|
||||||
|
event.location
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
event.location
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut elements = self.elements.lock().unwrap();
|
||||||
|
if let Some(i) = elements.iter().position(|elem| {
|
||||||
|
let mut bbox = elem.iced.bbox();
|
||||||
|
bbox.loc = elem.position.as_logical();
|
||||||
|
|
||||||
|
bbox.contains(location.to_i32_floor())
|
||||||
|
}) {
|
||||||
|
let element = &mut elements[i];
|
||||||
|
|
||||||
|
let new_event = TabletMotionEvent {
|
||||||
|
location: location - element.position.as_logical().to_f64(),
|
||||||
|
serial: event.serial,
|
||||||
|
time: event.time,
|
||||||
|
};
|
||||||
|
|
||||||
|
TabletToolTarget::proximity_in(
|
||||||
|
&element.iced,
|
||||||
|
&self.seat,
|
||||||
|
data,
|
||||||
|
handle.descriptor(),
|
||||||
|
&handle.current_tablet(),
|
||||||
|
event.serial,
|
||||||
|
);
|
||||||
|
element.tablet_entered = Some(handle.descriptor().clone());
|
||||||
|
TabletToolTarget::motion(
|
||||||
|
&element.iced,
|
||||||
|
&self.seat,
|
||||||
|
data,
|
||||||
|
handle.descriptor(),
|
||||||
|
&new_event,
|
||||||
|
);
|
||||||
|
self.last_tablet_idx = Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handle.proximity_in(data, None, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ProximityOutEvent,
|
||||||
|
) {
|
||||||
|
{
|
||||||
|
let mut elements = self.elements.lock().unwrap();
|
||||||
|
for element in elements.iter_mut().filter(|elem| {
|
||||||
|
elem.tablet_entered
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|tool| tool == handle.descriptor())
|
||||||
|
}) {
|
||||||
|
TabletToolTarget::proximity_out(
|
||||||
|
&element.iced,
|
||||||
|
&self.seat,
|
||||||
|
data,
|
||||||
|
handle.descriptor(),
|
||||||
|
);
|
||||||
|
element.tablet_entered.take();
|
||||||
|
}
|
||||||
|
self.last_tablet_idx.take();
|
||||||
|
}
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
_focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
{
|
||||||
|
let location = if let Some(output) = self.screen_space_relative.as_ref() {
|
||||||
|
if data.common.shell.read().zoom_state().is_some() {
|
||||||
|
event
|
||||||
|
.location
|
||||||
|
.as_global()
|
||||||
|
.to_zoomed(output)
|
||||||
|
.to_global(output)
|
||||||
|
.as_logical()
|
||||||
|
} else {
|
||||||
|
event.location
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
event.location
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut elements = self.elements.lock().unwrap();
|
||||||
|
if let Some(i) = elements.iter().position(|elem| {
|
||||||
|
let mut bbox = elem.iced.bbox();
|
||||||
|
bbox.loc = elem.position.as_logical();
|
||||||
|
|
||||||
|
bbox.contains(location.to_i32_floor())
|
||||||
|
}) {
|
||||||
|
let element = &mut elements[i];
|
||||||
|
|
||||||
|
let new_event = TabletMotionEvent {
|
||||||
|
location: location - element.position.as_logical().to_f64(),
|
||||||
|
serial: event.serial,
|
||||||
|
time: event.time,
|
||||||
|
};
|
||||||
|
|
||||||
|
if element.tablet_entered.is_none() {
|
||||||
|
TabletToolTarget::proximity_in(
|
||||||
|
&element.iced,
|
||||||
|
&self.seat,
|
||||||
|
data,
|
||||||
|
handle.descriptor(),
|
||||||
|
&handle.current_tablet(),
|
||||||
|
event.serial,
|
||||||
|
);
|
||||||
|
element.tablet_entered = Some(handle.descriptor().clone());
|
||||||
|
}
|
||||||
|
TabletToolTarget::motion(
|
||||||
|
&element.iced,
|
||||||
|
&self.seat,
|
||||||
|
data,
|
||||||
|
handle.descriptor(),
|
||||||
|
&new_event,
|
||||||
|
);
|
||||||
|
self.last_tablet_idx = Some(i);
|
||||||
|
} else {
|
||||||
|
elements
|
||||||
|
.iter_mut()
|
||||||
|
.filter(|element| element.tablet_entered.is_some())
|
||||||
|
.skip(1)
|
||||||
|
.for_each(|element| {
|
||||||
|
TabletToolTarget::proximity_out(
|
||||||
|
&element.iced,
|
||||||
|
&self.seat,
|
||||||
|
data,
|
||||||
|
handle.descriptor(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
self.last_tablet_idx.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handle.motion(data, None, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
let mut guard = self.elements.lock().unwrap();
|
||||||
|
let elements = &mut *guard;
|
||||||
|
|
||||||
|
if let Some(elem) = self.last_tablet_idx.and_then(|i| elements.get_mut(i))
|
||||||
|
&& elem
|
||||||
|
.tablet_entered
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|desc| desc == handle.descriptor())
|
||||||
|
{
|
||||||
|
TabletToolTarget::down(&elem.iced, &self.seat, data, handle.descriptor(), event);
|
||||||
|
} else {
|
||||||
|
handle.down(data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
let mut guard = self.elements.lock().unwrap();
|
||||||
|
let elements = &mut *guard;
|
||||||
|
|
||||||
|
if let Some(elem) = self.last_tablet_idx.and_then(|i| elements.get_mut(i))
|
||||||
|
&& elem
|
||||||
|
.tablet_entered
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|desc| desc == handle.descriptor())
|
||||||
|
{
|
||||||
|
TabletToolTarget::up(&elem.iced, &self.seat, data, handle.descriptor(), event);
|
||||||
|
} else {
|
||||||
|
handle.up(data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
handle.button(data, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
frame: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
handle.axis(data, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
handle.frame(data, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(&mut self, _data: &mut State) {}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MenuAlignment {
|
pub struct MenuAlignment {
|
||||||
pub x: AxisAlignment,
|
pub x: AxisAlignment,
|
||||||
|
|
@ -1052,6 +1313,7 @@ impl MenuGrab {
|
||||||
position,
|
position,
|
||||||
pointer_entered: false,
|
pointer_entered: false,
|
||||||
touch_entered: None,
|
touch_entered: None,
|
||||||
|
tablet_entered: None,
|
||||||
}]));
|
}]));
|
||||||
|
|
||||||
let scale = Arc::new(Mutex::new(screen_space_relative.unwrap_or(1.)));
|
let scale = Arc::new(Mutex::new(screen_space_relative.unwrap_or(1.)));
|
||||||
|
|
@ -1076,6 +1338,7 @@ impl MenuGrab {
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
screen_space_relative,
|
screen_space_relative,
|
||||||
scale,
|
scale,
|
||||||
|
last_tablet_idx: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1086,10 +1349,15 @@ impl MenuGrab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_touch_grab(&self) -> bool {
|
pub fn grab_type(&self) -> GrabType {
|
||||||
match self.start_data {
|
self.start_data.type_()
|
||||||
GrabStartData::Touch(_) => true,
|
}
|
||||||
GrabStartData::Pointer(_) => false,
|
|
||||||
|
pub fn tool(&self) -> Option<&TabletToolDescriptor> {
|
||||||
|
if let GrabStartData::TabletTool { tool, .. } = &self.start_data {
|
||||||
|
Some(tool)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,26 @@
|
||||||
use calloop::LoopHandle;
|
use calloop::LoopHandle;
|
||||||
use cosmic_settings_config::shortcuts;
|
use cosmic_settings_config::shortcuts;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
backend::input::{InputTime, TabletToolDescriptor},
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData,
|
||||||
RelativeMotionEvent,
|
MotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent,
|
||||||
|
},
|
||||||
|
tablet::tool::{
|
||||||
|
AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent,
|
||||||
|
DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData,
|
||||||
|
MotionEvent as TabletMotionEvent, ProximityOutEvent, TabletToolGrab,
|
||||||
|
TabletToolInnerHandle, UpEvent as TabletUpEvent,
|
||||||
},
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent,
|
DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData,
|
||||||
OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, UpEvent,
|
MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab,
|
||||||
|
TouchInnerHandle, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -39,6 +47,17 @@ use super::{
|
||||||
pub enum GrabStartData {
|
pub enum GrabStartData {
|
||||||
Touch(TouchGrabStartData<State>),
|
Touch(TouchGrabStartData<State>),
|
||||||
Pointer(PointerGrabStartData<State>),
|
Pointer(PointerGrabStartData<State>),
|
||||||
|
TabletTool {
|
||||||
|
tool: TabletToolDescriptor,
|
||||||
|
data: TabletGrabStartData<State>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum GrabType {
|
||||||
|
Touch,
|
||||||
|
Pointer,
|
||||||
|
TabletTool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GrabStartData {
|
impl GrabStartData {
|
||||||
|
|
@ -46,6 +65,7 @@ impl GrabStartData {
|
||||||
match self {
|
match self {
|
||||||
Self::Touch(touch) => touch.focus.as_ref(),
|
Self::Touch(touch) => touch.focus.as_ref(),
|
||||||
Self::Pointer(pointer) => pointer.focus.as_ref(),
|
Self::Pointer(pointer) => pointer.focus.as_ref(),
|
||||||
|
Self::TabletTool { data, .. } => data.focus.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,6 +73,7 @@ impl GrabStartData {
|
||||||
match self {
|
match self {
|
||||||
Self::Touch(touch) => touch.focus = focus,
|
Self::Touch(touch) => touch.focus = focus,
|
||||||
Self::Pointer(pointer) => pointer.focus = focus,
|
Self::Pointer(pointer) => pointer.focus = focus,
|
||||||
|
Self::TabletTool { data, .. } => data.focus = focus,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,6 +81,7 @@ impl GrabStartData {
|
||||||
match self {
|
match self {
|
||||||
Self::Touch(touch) => touch.location,
|
Self::Touch(touch) => touch.location,
|
||||||
Self::Pointer(pointer) => pointer.location,
|
Self::Pointer(pointer) => pointer.location,
|
||||||
|
Self::TabletTool { data, .. } => data.location,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,6 +89,7 @@ impl GrabStartData {
|
||||||
match self {
|
match self {
|
||||||
Self::Touch(touch) => touch.location = location,
|
Self::Touch(touch) => touch.location = location,
|
||||||
Self::Pointer(pointer) => pointer.location = location,
|
Self::Pointer(pointer) => pointer.location = location,
|
||||||
|
Self::TabletTool { data, .. } => data.location = location,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +99,14 @@ impl GrabStartData {
|
||||||
|
|
||||||
((new.x - old.x).powi(2) + (new.y - old.y).powi(2)).sqrt()
|
((new.x - old.x).powi(2) + (new.y - old.y).powi(2)).sqrt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_(&self) -> GrabType {
|
||||||
|
match self {
|
||||||
|
Self::Pointer(_) => GrabType::Pointer,
|
||||||
|
Self::Touch(_) => GrabType::Touch,
|
||||||
|
Self::TabletTool { .. } => GrabType::TabletTool,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -203,10 +234,17 @@ impl From<ResizeForkGrab> for ResizeGrab {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResizeGrab {
|
impl ResizeGrab {
|
||||||
pub fn is_touch_grab(&self) -> bool {
|
pub fn grab_type(&self) -> GrabType {
|
||||||
match self {
|
match self {
|
||||||
ResizeGrab::Floating(grab) => grab.is_touch_grab(),
|
ResizeGrab::Floating(grab) => grab.grab_type(),
|
||||||
ResizeGrab::Tiling(grab) => grab.is_touch_grab(),
|
ResizeGrab::Tiling(grab) => grab.grab_type(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tool(&self) -> Option<&TabletToolDescriptor> {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => grab.tool(),
|
||||||
|
ResizeGrab::Tiling(grab) => grab.tool(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -242,11 +280,11 @@ impl PointerGrab<State> for ResizeGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
event: &ButtonEvent,
|
event: &PointerButtonEvent,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
ResizeGrab::Floating(grab) => grab.button(data, handle, event),
|
ResizeGrab::Floating(grab) => PointerGrab::button(grab, data, handle, event),
|
||||||
ResizeGrab::Tiling(grab) => grab.button(data, handle, event),
|
ResizeGrab::Tiling(grab) => PointerGrab::button(grab, data, handle, event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,11 +292,11 @@ impl PointerGrab<State> for ResizeGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
details: AxisFrame,
|
details: PointerAxisFrame,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
ResizeGrab::Floating(grab) => grab.axis(data, handle, details),
|
ResizeGrab::Floating(grab) => PointerGrab::axis(grab, data, handle, details),
|
||||||
ResizeGrab::Tiling(grab) => grab.axis(data, handle, details),
|
ResizeGrab::Tiling(grab) => PointerGrab::axis(grab, data, handle, details),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -386,7 +424,7 @@ impl TouchGrab<State> for ResizeGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &DownEvent,
|
event: &TouchDownEvent,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
ResizeGrab::Floating(grab) => TouchGrab::down(grab, data, handle, focus, event),
|
ResizeGrab::Floating(grab) => TouchGrab::down(grab, data, handle, focus, event),
|
||||||
|
|
@ -394,7 +432,12 @@ impl TouchGrab<State> for ResizeGrab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) {
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
|
event: &TouchUpEvent,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
ResizeGrab::Floating(grab) => TouchGrab::up(grab, data, handle, event),
|
ResizeGrab::Floating(grab) => TouchGrab::up(grab, data, handle, event),
|
||||||
ResizeGrab::Tiling(grab) => TouchGrab::up(grab, data, handle, event),
|
ResizeGrab::Tiling(grab) => TouchGrab::up(grab, data, handle, event),
|
||||||
|
|
@ -467,6 +510,107 @@ impl TouchGrab<State> for ResizeGrab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolGrab<State> for ResizeGrab {
|
||||||
|
fn down(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::down(grab, data, handle, event),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::down(grab, data, handle, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::up(grab, data, handle, event),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::up(grab, data, handle, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
|
event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::motion(grab, data, handle, focus, event),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::motion(grab, data, handle, focus, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
serial: InputTime,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::frame(grab, data, handle, serial),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::frame(grab, data, handle, serial),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::button(grab, data, handle, event),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::button(grab, data, handle, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
details: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::axis(grab, data, handle, details),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::axis(grab, data, handle, details),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ProximityOutEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::proximity_out(grab, data, handle, event),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::proximity_out(grab, data, handle, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_data(&self) -> &TabletGrabStartData<State> {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::start_data(grab),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::start_data(grab),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(&mut self, data: &mut State) {
|
||||||
|
match self {
|
||||||
|
ResizeGrab::Floating(grab) => TabletToolGrab::unset(grab, data),
|
||||||
|
ResizeGrab::Tiling(grab) => TabletToolGrab::unset(grab, data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum MoveGrab {
|
pub enum MoveGrab {
|
||||||
Move(moving::MoveGrab),
|
Move(moving::MoveGrab),
|
||||||
Delayed(delay::DelayGrab<MoveGrab>),
|
Delayed(delay::DelayGrab<MoveGrab>),
|
||||||
|
|
@ -536,10 +680,17 @@ impl MoveGrab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_touch_grab(&self) -> bool {
|
pub fn grab_type(&self) -> GrabType {
|
||||||
match self {
|
match self {
|
||||||
MoveGrab::Move(m) => m.is_touch_grab(),
|
MoveGrab::Move(m) => m.grab_type(),
|
||||||
MoveGrab::Delayed(d) => d.is_touch_grab(),
|
MoveGrab::Delayed(d) => d.grab_type(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tool(&self) -> Option<&TabletToolDescriptor> {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(m) => m.tool(),
|
||||||
|
MoveGrab::Delayed(d) => d.tool(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -574,11 +725,11 @@ impl PointerGrab<State> for MoveGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
event: &ButtonEvent,
|
event: &PointerButtonEvent,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
MoveGrab::Move(grab) => grab.button(data, handle, event),
|
MoveGrab::Move(grab) => PointerGrab::button(grab, data, handle, event),
|
||||||
MoveGrab::Delayed(grab) => grab.button(data, handle, event),
|
MoveGrab::Delayed(grab) => PointerGrab::button(grab, data, handle, event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -586,11 +737,11 @@ impl PointerGrab<State> for MoveGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
details: AxisFrame,
|
details: PointerAxisFrame,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
MoveGrab::Move(grab) => grab.axis(data, handle, details),
|
MoveGrab::Move(grab) => PointerGrab::axis(grab, data, handle, details),
|
||||||
MoveGrab::Delayed(grab) => grab.axis(data, handle, details),
|
MoveGrab::Delayed(grab) => PointerGrab::axis(grab, data, handle, details),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -718,7 +869,7 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &DownEvent,
|
event: &TouchDownEvent,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
MoveGrab::Move(grab) => TouchGrab::down(grab, data, handle, focus, event),
|
MoveGrab::Move(grab) => TouchGrab::down(grab, data, handle, focus, event),
|
||||||
|
|
@ -726,7 +877,12 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) {
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
|
event: &TouchUpEvent,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
MoveGrab::Move(grab) => TouchGrab::up(grab, data, handle, event),
|
MoveGrab::Move(grab) => TouchGrab::up(grab, data, handle, event),
|
||||||
MoveGrab::Delayed(grab) => TouchGrab::up(grab, data, handle, event),
|
MoveGrab::Delayed(grab) => TouchGrab::up(grab, data, handle, event),
|
||||||
|
|
@ -798,3 +954,104 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolGrab<State> for MoveGrab {
|
||||||
|
fn down(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::down(grab, data, handle, event),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::down(grab, data, handle, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::up(grab, data, handle, event),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::up(grab, data, handle, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
|
event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::motion(grab, data, handle, focus, event),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::motion(grab, data, handle, focus, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
serial: InputTime,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::frame(grab, data, handle, serial),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::frame(grab, data, handle, serial),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::button(grab, data, handle, event),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::button(grab, data, handle, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
details: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::axis(grab, data, handle, details),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::axis(grab, data, handle, details),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ProximityOutEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::proximity_out(grab, data, handle, event),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::proximity_out(grab, data, handle, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_data(&self) -> &TabletGrabStartData<State> {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::start_data(grab),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::start_data(grab),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(&mut self, data: &mut State) {
|
||||||
|
match self {
|
||||||
|
MoveGrab::Move(grab) => TabletToolGrab::unset(grab, data),
|
||||||
|
MoveGrab::Delayed(grab) => TabletToolGrab::unset(grab, data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use crate::{
|
||||||
CosmicMapped, CosmicSurface, Direction, ManagedLayer,
|
CosmicMapped, CosmicSurface, Direction, ManagedLayer,
|
||||||
element::{CosmicMappedRenderElement, stack_hover::StackHover},
|
element::{CosmicMappedRenderElement, stack_hover::StackHover},
|
||||||
focus::target::{KeyboardFocusTarget, PointerFocusTarget},
|
focus::target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||||
|
grabs::GrabType,
|
||||||
layout::floating::TiledCorners,
|
layout::floating::TiledCorners,
|
||||||
},
|
},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
|
|
@ -20,7 +21,7 @@ use smallvec::SmallVec;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
input::ButtonState,
|
input::{ButtonState, InputTime, TabletToolDescriptor},
|
||||||
renderer::{
|
renderer::{
|
||||||
ImportAll, ImportMem,
|
ImportAll, ImportMem,
|
||||||
element::{RenderElement, utils::RescaleRenderElement},
|
element::{RenderElement, utils::RescaleRenderElement},
|
||||||
|
|
@ -30,13 +31,27 @@ use smithay::{
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, CursorIcon, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorIcon,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData,
|
||||||
|
MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle,
|
||||||
RelativeMotionEvent,
|
RelativeMotionEvent,
|
||||||
},
|
},
|
||||||
touch::{self, GrabStartData as TouchGrabStartData, TouchGrab, TouchInnerHandle},
|
tablet::{
|
||||||
|
TabletSeatHandler,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent,
|
||||||
|
DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData,
|
||||||
|
MotionEvent as TabletMotionEvent, ProximityInEvent, ProximityOutEvent,
|
||||||
|
TabletToolGrab, TabletToolInnerHandle, UpEvent as TabletUpEvent,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
touch::{
|
||||||
|
DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData,
|
||||||
|
MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab,
|
||||||
|
TouchInnerHandle, UpEvent as TouchUpEvent,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{IsAlive, Logical, Point, Rectangle, SERIAL_COUNTER, Scale},
|
utils::{IsAlive, Logical, Point, Rectangle, SERIAL_COUNTER, Scale},
|
||||||
|
|
@ -503,7 +518,7 @@ impl PointerGrab<State> for MoveGrab {
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &MotionEvent,
|
event: &PointerMotionEvent,
|
||||||
) {
|
) {
|
||||||
self.update_location(state, event.location);
|
self.update_location(state, event.location);
|
||||||
|
|
||||||
|
|
@ -529,7 +544,7 @@ impl PointerGrab<State> for MoveGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
event: &ButtonEvent,
|
event: &PointerButtonEvent,
|
||||||
) {
|
) {
|
||||||
handle.button(state, event);
|
handle.button(state, event);
|
||||||
match self.release {
|
match self.release {
|
||||||
|
|
@ -550,7 +565,7 @@ impl PointerGrab<State> for MoveGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
details: AxisFrame,
|
details: PointerAxisFrame,
|
||||||
) {
|
) {
|
||||||
handle.axis(state, details);
|
handle.axis(state, details);
|
||||||
}
|
}
|
||||||
|
|
@ -647,7 +662,7 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &touch::DownEvent,
|
event: &TouchDownEvent,
|
||||||
) {
|
) {
|
||||||
handle.down(data, None, event)
|
handle.down(data, None, event)
|
||||||
}
|
}
|
||||||
|
|
@ -656,7 +671,7 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
event: &touch::UpEvent,
|
event: &TouchUpEvent,
|
||||||
) {
|
) {
|
||||||
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
|
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
|
||||||
handle.unset_grab(self, data);
|
handle.unset_grab(self, data);
|
||||||
|
|
@ -670,7 +685,7 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &touch::MotionEvent,
|
event: &TouchMotionEvent,
|
||||||
) {
|
) {
|
||||||
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
|
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
|
||||||
self.update_location(data, event.location);
|
self.update_location(data, event.location);
|
||||||
|
|
@ -691,7 +706,7 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
event: &touch::ShapeEvent,
|
event: &ShapeEvent,
|
||||||
) {
|
) {
|
||||||
handle.shape(data, event)
|
handle.shape(data, event)
|
||||||
}
|
}
|
||||||
|
|
@ -700,7 +715,7 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
event: &touch::OrientationEvent,
|
event: &OrientationEvent,
|
||||||
) {
|
) {
|
||||||
handle.orientation(data, event)
|
handle.orientation(data, event)
|
||||||
}
|
}
|
||||||
|
|
@ -715,6 +730,98 @@ impl TouchGrab<State> for MoveGrab {
|
||||||
fn unset(&mut self, _data: &mut State) {}
|
fn unset(&mut self, _data: &mut State) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolGrab<State> for MoveGrab {
|
||||||
|
fn start_data(&self) -> &TabletGrabStartData<State> {
|
||||||
|
match &self.start_data {
|
||||||
|
GrabStartData::TabletTool { data, .. } => data,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ProximityOutEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_out(data, event);
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
_focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
handle.motion(data, None, event);
|
||||||
|
|
||||||
|
self.update_location(data, event.location);
|
||||||
|
if !self.window.alive() {
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
handle.down(data, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
handle.up(data, event);
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
handle.button(data, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
frame: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
handle.axis(data, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
handle.frame(data, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_in(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &ProximityInEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_in(data, focus, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(&mut self, _data: &mut State) {}
|
||||||
|
}
|
||||||
|
|
||||||
impl MoveGrab {
|
impl MoveGrab {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
start_data: GrabStartData,
|
start_data: GrabStartData,
|
||||||
|
|
@ -778,10 +885,15 @@ impl MoveGrab {
|
||||||
self.previous == ManagedLayer::Tiling
|
self.previous == ManagedLayer::Tiling
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_touch_grab(&self) -> bool {
|
pub fn grab_type(&self) -> GrabType {
|
||||||
match self.start_data {
|
self.start_data.type_()
|
||||||
GrabStartData::Touch(_) => true,
|
}
|
||||||
GrabStartData::Pointer(_) => false,
|
|
||||||
|
pub fn tool(&self) -> Option<&TabletToolDescriptor> {
|
||||||
|
if let GrabStartData::TabletTool { tool, .. } = &self.start_data {
|
||||||
|
Some(tool)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -793,7 +905,7 @@ impl Drop for MoveGrab {
|
||||||
let seat = self.seat.clone();
|
let seat = self.seat.clone();
|
||||||
// false-positive: `Output`s hash is based on it's inner ptr
|
// false-positive: `Output`s hash is based on it's inner ptr
|
||||||
#[allow(clippy::mutable_key_type)]
|
#[allow(clippy::mutable_key_type)]
|
||||||
let window_outputs = self.window_outputs.drain().collect::<HashSet<_>>();
|
let window_outputs = std::mem::take(&mut self.window_outputs);
|
||||||
let previous = self.previous;
|
let previous = self.previous;
|
||||||
let window = self.window.clone();
|
let window = self.window.clone();
|
||||||
let is_touch_grab = matches!(self.start_data, GrabStartData::Touch(_));
|
let is_touch_grab = matches!(self.start_data, GrabStartData::Touch(_));
|
||||||
|
|
@ -953,10 +1065,10 @@ impl Drop for MoveGrab {
|
||||||
position.as_logical().to_f64() - window.geometry().loc.to_f64()
|
position.as_logical().to_f64() - window.geometry().loc.to_f64()
|
||||||
+ offset,
|
+ offset,
|
||||||
)),
|
)),
|
||||||
&MotionEvent {
|
&PointerMotionEvent {
|
||||||
location: pointer.current_location(),
|
location: pointer.current_location(),
|
||||||
serial,
|
serial,
|
||||||
time: state.common.clock.now().as_millis(),
|
time: InputTime::now(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,25 +7,36 @@ use crate::{
|
||||||
shell::{
|
shell::{
|
||||||
element::CosmicMapped,
|
element::CosmicMapped,
|
||||||
focus::target::PointerFocusTarget,
|
focus::target::PointerFocusTarget,
|
||||||
grabs::{GrabStartData, ReleaseMode, ResizeEdge},
|
grabs::{GrabStartData, GrabType, ReleaseMode, ResizeEdge},
|
||||||
},
|
},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
};
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::ButtonState,
|
backend::input::{ButtonState, InputTime, TabletToolDescriptor},
|
||||||
desktop::{WindowSurface, space::SpaceElement},
|
desktop::{WindowSurface, space::SpaceElement},
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, CursorIcon, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorIcon,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData,
|
||||||
|
MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle,
|
||||||
RelativeMotionEvent,
|
RelativeMotionEvent,
|
||||||
},
|
},
|
||||||
|
tablet::{
|
||||||
|
TabletSeatHandler,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent,
|
||||||
|
DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData,
|
||||||
|
MotionEvent as TabletMotionEvent, ProximityInEvent, ProximityOutEvent,
|
||||||
|
TabletToolGrab, TabletToolInnerHandle, UpEvent as TabletUpEvent,
|
||||||
|
},
|
||||||
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent,
|
DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData,
|
||||||
OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, UpEvent,
|
MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab,
|
||||||
|
TouchInnerHandle, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -170,10 +181,19 @@ impl ResizeSurfaceGrab {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_touch_grab(&self) -> bool {
|
pub fn grab_type(&self) -> GrabType {
|
||||||
match self.start_data {
|
match self.start_data {
|
||||||
GrabStartData::Touch(_) => true,
|
GrabStartData::Pointer(_) => GrabType::Pointer,
|
||||||
GrabStartData::Pointer(_) => false,
|
GrabStartData::Touch(_) => GrabType::Touch,
|
||||||
|
GrabStartData::TabletTool { .. } => GrabType::TabletTool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tool(&self) -> Option<&TabletToolDescriptor> {
|
||||||
|
if let GrabStartData::TabletTool { tool, .. } = &self.start_data {
|
||||||
|
Some(tool)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +204,7 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &MotionEvent,
|
event: &PointerMotionEvent,
|
||||||
) {
|
) {
|
||||||
// While the grab is active, no client has pointer focus
|
// While the grab is active, no client has pointer focus
|
||||||
handle.motion(data, None, event);
|
handle.motion(data, None, event);
|
||||||
|
|
@ -209,7 +229,7 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
event: &ButtonEvent,
|
event: &PointerButtonEvent,
|
||||||
) {
|
) {
|
||||||
handle.button(data, event);
|
handle.button(data, event);
|
||||||
match self.release {
|
match self.release {
|
||||||
|
|
@ -230,7 +250,7 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
details: AxisFrame,
|
details: PointerAxisFrame,
|
||||||
) {
|
) {
|
||||||
handle.axis(data, details)
|
handle.axis(data, details)
|
||||||
}
|
}
|
||||||
|
|
@ -329,12 +349,17 @@ impl TouchGrab<State> for ResizeSurfaceGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &DownEvent,
|
event: &TouchDownEvent,
|
||||||
) {
|
) {
|
||||||
handle.down(data, None, event)
|
handle.down(data, None, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) {
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
|
event: &TouchUpEvent,
|
||||||
|
) {
|
||||||
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
|
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
|
||||||
handle.unset_grab(self, data);
|
handle.unset_grab(self, data);
|
||||||
}
|
}
|
||||||
|
|
@ -396,6 +421,99 @@ impl TouchGrab<State> for ResizeSurfaceGrab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolGrab<State> for ResizeSurfaceGrab {
|
||||||
|
fn start_data(&self) -> &TabletGrabStartData<State> {
|
||||||
|
match &self.start_data {
|
||||||
|
GrabStartData::TabletTool { data, .. } => data,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ProximityOutEvent,
|
||||||
|
) {
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
handle.proximity_out(data, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
_focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
if self.update_location(event.location.as_global()) {
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle.motion(data, None, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
handle.down(data, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
handle.up(data, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
handle.button(data, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
frame: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
handle.axis(data, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
handle.frame(data, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(&mut self, _data: &mut State) {
|
||||||
|
self.ungrab()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_in(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
_focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &ProximityInEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_in(data, None, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ResizeGrabMarker(AtomicBool);
|
pub struct ResizeGrabMarker(AtomicBool);
|
||||||
|
|
||||||
impl ResizeGrabMarker {
|
impl ResizeGrabMarker {
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,42 @@ use crate::{
|
||||||
backend::render::cursor::CursorState,
|
backend::render::cursor::CursorState,
|
||||||
shell::{
|
shell::{
|
||||||
focus::target::PointerFocusTarget,
|
focus::target::PointerFocusTarget,
|
||||||
grabs::{GrabStartData, ReleaseMode},
|
grabs::{GrabStartData, GrabType, ReleaseMode},
|
||||||
layout::Orientation,
|
layout::Orientation,
|
||||||
},
|
},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
};
|
};
|
||||||
use id_tree::{NodeId, Tree};
|
use id_tree::{NodeId, Tree};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::ButtonState,
|
backend::input::{ButtonState, InputTime, TabletToolDescriptor},
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, CursorIcon, Focus, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorIcon, Focus,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData,
|
||||||
PointerTarget, RelativeMotionEvent,
|
MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle, PointerTarget,
|
||||||
|
RelativeMotionEvent,
|
||||||
|
},
|
||||||
|
tablet::{
|
||||||
|
Tablet, TabletSeatHandler, TabletSeatTrait,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent,
|
||||||
|
DownEvent as TabletDownEvent, GrabStartData as TabletToolGrabStartData,
|
||||||
|
GrabTrigger as TabletToolGrabTrigger, MotionEvent as TabletMotionEvent,
|
||||||
|
ProximityInEvent, ProximityOutEvent, TabletToolGrab, TabletToolInnerHandle,
|
||||||
|
TabletToolTarget, UpEvent as TabletUpEvent,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, FrameMarker, GrabStartData as TouchGrabStartData,
|
DownEvent as TouchDownEvent, FrameMarker, GrabStartData as TouchGrabStartData,
|
||||||
MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab,
|
MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab,
|
||||||
TouchInnerHandle, TouchTarget, UpEvent,
|
TouchInnerHandle, TouchTarget, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output::WeakOutput,
|
output::WeakOutput,
|
||||||
utils::{IsAlive, Logical, Point},
|
utils::{IsAlive, Logical, Point, Serial},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::{Data, TilingLayout};
|
use super::super::{Data, TilingLayout};
|
||||||
|
|
@ -48,7 +59,7 @@ impl IsAlive for ResizeForkTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerTarget<State> for ResizeForkTarget {
|
impl PointerTarget<State> for ResizeForkTarget {
|
||||||
fn enter(&self, seat: &Seat<State>, _data: &mut State, _event: &MotionEvent) {
|
fn enter(&self, seat: &Seat<State>, _data: &mut State, _event: &PointerMotionEvent) {
|
||||||
let user_data = seat.user_data();
|
let user_data = seat.user_data();
|
||||||
let cursor_state = user_data.get::<CursorState>().unwrap();
|
let cursor_state = user_data.get::<CursorState>().unwrap();
|
||||||
cursor_state
|
cursor_state
|
||||||
|
|
@ -60,19 +71,13 @@ impl PointerTarget<State> for ResizeForkTarget {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(
|
fn leave(&self, seat: &Seat<State>, _data: &mut State, _serial: Serial, _time: InputTime) {
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_serial: smithay::utils::Serial,
|
|
||||||
_time: u32,
|
|
||||||
) {
|
|
||||||
let user_data = seat.user_data();
|
let user_data = seat.user_data();
|
||||||
let cursor_state = user_data.get::<CursorState>().unwrap();
|
let cursor_state = user_data.get::<CursorState>().unwrap();
|
||||||
cursor_state.lock().unwrap().unset_shape();
|
cursor_state.lock().unwrap().unset_shape();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &PointerButtonEvent) {
|
||||||
if event.button == 0x110 && event.state == ButtonState::Pressed {
|
if event.button == 0x110 && event.state == ButtonState::Pressed {
|
||||||
let seat = seat.clone();
|
let seat = seat.clone();
|
||||||
let node = self.node.clone();
|
let node = self.node.clone();
|
||||||
|
|
@ -106,7 +111,7 @@ impl PointerTarget<State> for ResizeForkTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn motion(&self, _seat: &Seat<State>, _data: &mut State, _event: &MotionEvent) {}
|
fn motion(&self, _seat: &Seat<State>, _data: &mut State, _event: &PointerMotionEvent) {}
|
||||||
fn relative_motion(
|
fn relative_motion(
|
||||||
&self,
|
&self,
|
||||||
_seat: &Seat<State>,
|
_seat: &Seat<State>,
|
||||||
|
|
@ -114,7 +119,7 @@ impl PointerTarget<State> for ResizeForkTarget {
|
||||||
_event: &RelativeMotionEvent,
|
_event: &RelativeMotionEvent,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn axis(&self, _seat: &Seat<State>, _data: &mut State, _frame: AxisFrame) {}
|
fn axis(&self, _seat: &Seat<State>, _data: &mut State, _frame: PointerAxisFrame) {}
|
||||||
fn frame(&self, _seat: &Seat<State>, _data: &mut State) {}
|
fn frame(&self, _seat: &Seat<State>, _data: &mut State) {}
|
||||||
fn gesture_swipe_begin(&self, _: &Seat<State>, _: &mut State, _: &GestureSwipeBeginEvent) {}
|
fn gesture_swipe_begin(&self, _: &Seat<State>, _: &mut State, _: &GestureSwipeBeginEvent) {}
|
||||||
fn gesture_swipe_update(&self, _: &Seat<State>, _: &mut State, _: &GestureSwipeUpdateEvent) {}
|
fn gesture_swipe_update(&self, _: &Seat<State>, _: &mut State, _: &GestureSwipeUpdateEvent) {}
|
||||||
|
|
@ -127,7 +132,7 @@ impl PointerTarget<State> for ResizeForkTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TouchTarget<State> for ResizeForkTarget {
|
impl TouchTarget<State> for ResizeForkTarget {
|
||||||
fn down(&self, seat: &Seat<State>, data: &mut State, event: &DownEvent) {
|
fn down(&self, seat: &Seat<State>, data: &mut State, event: &TouchDownEvent) {
|
||||||
let seat = seat.clone();
|
let seat = seat.clone();
|
||||||
let node = self.node.clone();
|
let node = self.node.clone();
|
||||||
let output = self.output.clone();
|
let output = self.output.clone();
|
||||||
|
|
@ -158,7 +163,7 @@ impl TouchTarget<State> for ResizeForkTarget {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&self, _seat: &Seat<State>, _data: &mut State, _event: &UpEvent) {}
|
fn up(&self, _seat: &Seat<State>, _data: &mut State, _event: &TouchUpEvent) {}
|
||||||
fn motion(&self, _seat: &Seat<State>, _data: &mut State, _event: &TouchMotionEvent) {}
|
fn motion(&self, _seat: &Seat<State>, _data: &mut State, _event: &TouchMotionEvent) {}
|
||||||
fn frame(&self, _seat: &Seat<State>, _data: &mut State, _frame: FrameMarker) {}
|
fn frame(&self, _seat: &Seat<State>, _data: &mut State, _frame: FrameMarker) {}
|
||||||
fn cancel(&self, _seat: &Seat<State>, _data: &mut State, _frame: FrameMarker) {}
|
fn cancel(&self, _seat: &Seat<State>, _data: &mut State, _frame: FrameMarker) {}
|
||||||
|
|
@ -169,6 +174,121 @@ impl TouchTarget<State> for ResizeForkTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolTarget<State> for ResizeForkTarget {
|
||||||
|
fn down(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
let seat = seat.clone();
|
||||||
|
let node = self.node.clone();
|
||||||
|
let output = self.output.clone();
|
||||||
|
let left_up_idx = self.left_up_idx;
|
||||||
|
let orientation = self.orientation;
|
||||||
|
let serial = event.serial;
|
||||||
|
let time = event.time;
|
||||||
|
let tool = tool_descriptor.clone();
|
||||||
|
data.common.event_loop_handle.insert_idle(move |state| {
|
||||||
|
let pointer = seat.get_pointer().unwrap();
|
||||||
|
let location = pointer.current_location();
|
||||||
|
let tablet = seat.tablet_seat().get_tool(&tool).unwrap();
|
||||||
|
tablet.set_grab(
|
||||||
|
state,
|
||||||
|
ResizeForkGrab::new(
|
||||||
|
GrabStartData::TabletTool {
|
||||||
|
tool,
|
||||||
|
data: TabletToolGrabStartData {
|
||||||
|
focus: None,
|
||||||
|
location,
|
||||||
|
trigger: TabletToolGrabTrigger::Tip,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
location.as_global(),
|
||||||
|
node,
|
||||||
|
left_up_idx,
|
||||||
|
orientation,
|
||||||
|
output,
|
||||||
|
ReleaseMode::NoMouseButtons,
|
||||||
|
),
|
||||||
|
time,
|
||||||
|
serial,
|
||||||
|
Focus::Keep,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn motion(
|
||||||
|
&self,
|
||||||
|
_seat: &Seat<State>,
|
||||||
|
_data: &mut State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
fn proximity_out(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
_data: &mut State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
) {
|
||||||
|
let user_data = seat.user_data();
|
||||||
|
let cursor_state = user_data.get::<CursorState>().unwrap();
|
||||||
|
cursor_state.lock().unwrap().unset_shape();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_in(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
_data: &mut State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_tablet: &Tablet,
|
||||||
|
_serial: Serial,
|
||||||
|
) {
|
||||||
|
let user_data = seat.user_data();
|
||||||
|
let cursor_state = user_data.get::<CursorState>().unwrap();
|
||||||
|
cursor_state
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_shape(match self.orientation {
|
||||||
|
Orientation::Horizontal => CursorIcon::RowResize,
|
||||||
|
Orientation::Vertical => CursorIcon::ColResize,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn up(
|
||||||
|
&self,
|
||||||
|
_seat: &Seat<State>,
|
||||||
|
_data: &mut State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
fn axis(
|
||||||
|
&self,
|
||||||
|
_seat: &Seat<State>,
|
||||||
|
_data: &mut State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_frame: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
fn button(
|
||||||
|
&self,
|
||||||
|
_seat: &Seat<State>,
|
||||||
|
_data: &mut State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
fn frame(
|
||||||
|
&self,
|
||||||
|
_seat: &Seat<State>,
|
||||||
|
_data: &mut State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_time: InputTime,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ResizeForkGrab {
|
pub struct ResizeForkGrab {
|
||||||
start_data: GrabStartData,
|
start_data: GrabStartData,
|
||||||
last_loc: Point<f64, Global>,
|
last_loc: Point<f64, Global>,
|
||||||
|
|
@ -338,10 +458,19 @@ impl ResizeForkGrab {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_touch_grab(&self) -> bool {
|
pub fn grab_type(&self) -> GrabType {
|
||||||
match self.start_data {
|
match self.start_data {
|
||||||
GrabStartData::Touch(_) => true,
|
GrabStartData::Pointer(_) => GrabType::Pointer,
|
||||||
GrabStartData::Pointer(_) => false,
|
GrabStartData::Touch(_) => GrabType::Touch,
|
||||||
|
GrabStartData::TabletTool { .. } => GrabType::TabletTool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tool(&self) -> Option<&TabletToolDescriptor> {
|
||||||
|
if let GrabStartData::TabletTool { tool, .. } = &self.start_data {
|
||||||
|
Some(tool)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -352,7 +481,7 @@ impl PointerGrab<State> for ResizeForkGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &MotionEvent,
|
event: &PointerMotionEvent,
|
||||||
) {
|
) {
|
||||||
// While the grab is active, no client has pointer focus
|
// While the grab is active, no client has pointer focus
|
||||||
handle.motion(data, None, event);
|
handle.motion(data, None, event);
|
||||||
|
|
@ -377,7 +506,7 @@ impl PointerGrab<State> for ResizeForkGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
event: &ButtonEvent,
|
event: &PointerButtonEvent,
|
||||||
) {
|
) {
|
||||||
handle.button(data, event);
|
handle.button(data, event);
|
||||||
match self.release {
|
match self.release {
|
||||||
|
|
@ -398,7 +527,7 @@ impl PointerGrab<State> for ResizeForkGrab {
|
||||||
&mut self,
|
&mut self,
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut PointerInnerHandle<'_, State>,
|
handle: &mut PointerInnerHandle<'_, State>,
|
||||||
details: AxisFrame,
|
details: PointerAxisFrame,
|
||||||
) {
|
) {
|
||||||
handle.axis(data, details)
|
handle.axis(data, details)
|
||||||
}
|
}
|
||||||
|
|
@ -497,12 +626,17 @@ impl TouchGrab<State> for ResizeForkGrab {
|
||||||
data: &mut State,
|
data: &mut State,
|
||||||
handle: &mut TouchInnerHandle<'_, State>,
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
_focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||||
event: &DownEvent,
|
event: &TouchDownEvent,
|
||||||
) {
|
) {
|
||||||
handle.down(data, None, event)
|
handle.down(data, None, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) {
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TouchInnerHandle<'_, State>,
|
||||||
|
event: &TouchUpEvent,
|
||||||
|
) {
|
||||||
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
|
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
|
||||||
handle.unset_grab(self, data);
|
handle.unset_grab(self, data);
|
||||||
}
|
}
|
||||||
|
|
@ -563,3 +697,96 @@ impl TouchGrab<State> for ResizeForkGrab {
|
||||||
self.update_location(data, self.last_loc.as_logical(), true);
|
self.update_location(data, self.last_loc.as_logical(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolGrab<State> for ResizeForkGrab {
|
||||||
|
fn start_data(&self) -> &TabletToolGrabStartData<State> {
|
||||||
|
match &self.start_data {
|
||||||
|
GrabStartData::TabletTool { data, .. } => data,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &ProximityOutEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_out(data, event);
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
_focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
handle.motion(data, None, event);
|
||||||
|
|
||||||
|
if self.update_location(data, event.location, false) {
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
handle.down(data, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
handle.up(data, event);
|
||||||
|
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
handle.button(data, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
frame: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
handle.axis(data, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
handle.frame(data, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset(&mut self, data: &mut State) {
|
||||||
|
self.update_location(data, self.last_loc.as_logical(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_in(
|
||||||
|
&mut self,
|
||||||
|
data: &mut State,
|
||||||
|
handle: &mut TabletToolInnerHandle<'_, State>,
|
||||||
|
focus: Option<(<State as TabletSeatHandler>::ToolFocus, Point<f64, Logical>)>,
|
||||||
|
event: &ProximityInEvent,
|
||||||
|
) {
|
||||||
|
handle.proximity_in(data, focus, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use cosmic_settings_config::shortcuts;
|
use cosmic_settings_config::shortcuts;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::{KeyState, Keycode},
|
backend::input::{InputTime, KeyState, Keycode},
|
||||||
input::{
|
input::{
|
||||||
Seat, SeatHandler,
|
Seat, SeatHandler,
|
||||||
keyboard::{
|
keyboard::{
|
||||||
|
|
@ -38,7 +38,7 @@ impl KeyboardGrab<State> for SwapWindowGrab {
|
||||||
state: KeyState,
|
state: KeyState,
|
||||||
modifiers: Option<ModifiersState>,
|
modifiers: Option<ModifiersState>,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
if !matches!(&data.common.shell.read().overview_mode.active_trigger(), Some(Trigger::KeyboardSwap(_, d)) if d == &self.desc)
|
if !matches!(&data.common.shell.read().overview_mode.active_trigger(), Some(Trigger::KeyboardSwap(_, d)) if d == &self.desc)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3381,7 +3381,7 @@ impl TilingLayout {
|
||||||
let Some(root) = tree.root_node_id() else {
|
let Some(root) = tree.root_node_id() else {
|
||||||
if matches!(
|
if matches!(
|
||||||
overview.active_trigger(),
|
overview.active_trigger(),
|
||||||
Some(Trigger::Pointer(_) | Trigger::Touch(_))
|
Some(Trigger::Pointer(_) | Trigger::Touch(_) | Trigger::Tool(_, _))
|
||||||
) && location_f64.is_some()
|
) && location_f64.is_some()
|
||||||
{
|
{
|
||||||
let mut tree = tree.copy_clone();
|
let mut tree = tree.copy_clone();
|
||||||
|
|
@ -3414,7 +3414,7 @@ impl TilingLayout {
|
||||||
|
|
||||||
if matches!(
|
if matches!(
|
||||||
overview.active_trigger(),
|
overview.active_trigger(),
|
||||||
Some(Trigger::Pointer(_) | Trigger::Touch(_))
|
Some(Trigger::Pointer(_) | Trigger::Touch(_) | Trigger::Tool(_, _))
|
||||||
) {
|
) {
|
||||||
let non_exclusive_zone = layer_map_for_output(&self.output)
|
let non_exclusive_zone = layer_map_for_output(&self.output)
|
||||||
.non_exclusive_zone()
|
.non_exclusive_zone()
|
||||||
|
|
@ -4062,7 +4062,10 @@ impl TilingLayout {
|
||||||
let draw_groups = overview.0.alpha();
|
let draw_groups = overview.0.alpha();
|
||||||
|
|
||||||
let is_overview = !matches!(overview.0, OverviewMode::None);
|
let is_overview = !matches!(overview.0, OverviewMode::None);
|
||||||
let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_))))
|
let is_mouse_tiling = (matches!(
|
||||||
|
overview.0.trigger(),
|
||||||
|
Some(Trigger::Pointer(_) | Trigger::Tool(_, _))
|
||||||
|
))
|
||||||
.then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone));
|
.then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone));
|
||||||
let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() {
|
let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() {
|
||||||
Some(desc.clone())
|
Some(desc.clone())
|
||||||
|
|
@ -4216,7 +4219,10 @@ impl TilingLayout {
|
||||||
};
|
};
|
||||||
let draw_groups = overview.0.alpha();
|
let draw_groups = overview.0.alpha();
|
||||||
|
|
||||||
let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_))))
|
let is_mouse_tiling = (matches!(
|
||||||
|
overview.0.trigger(),
|
||||||
|
Some(Trigger::Pointer(_) | Trigger::Tool(_, _))
|
||||||
|
))
|
||||||
.then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone));
|
.then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone));
|
||||||
let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() {
|
let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() {
|
||||||
Some(desc.clone())
|
Some(desc.clone())
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,10 @@ use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection, Resiz
|
||||||
use cosmic_settings_config::{shortcuts, window_rules::ApplicationException};
|
use cosmic_settings_config::{shortcuts, window_rules::ApplicationException};
|
||||||
use keyframe::{ease, functions::EaseInOutCubic};
|
use keyframe::{ease, functions::EaseInOutCubic};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{input::TouchSlot, renderer::element::RenderElementStates},
|
backend::{
|
||||||
|
input::{TabletToolDescriptor, TouchSlot},
|
||||||
|
renderer::element::RenderElementStates,
|
||||||
|
},
|
||||||
desktop::{
|
desktop::{
|
||||||
LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, layer_map_for_output,
|
LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, layer_map_for_output,
|
||||||
space::SpaceElement,
|
space::SpaceElement,
|
||||||
|
|
@ -46,6 +49,7 @@ use smithay::{
|
||||||
pointer::{
|
pointer::{
|
||||||
CursorImageStatus, CursorImageSurfaceData, Focus, GrabStartData as PointerGrabStartData,
|
CursorImageStatus, CursorImageSurfaceData, Focus, GrabStartData as PointerGrabStartData,
|
||||||
},
|
},
|
||||||
|
tablet::{TabletSeatTrait, tool::GrabTrigger as TabletGrabTrigger},
|
||||||
},
|
},
|
||||||
output::{Output, WeakOutput},
|
output::{Output, WeakOutput},
|
||||||
reexports::{
|
reexports::{
|
||||||
|
|
@ -130,6 +134,7 @@ pub enum Trigger {
|
||||||
KeyboardMove(shortcuts::Modifiers),
|
KeyboardMove(shortcuts::Modifiers),
|
||||||
Pointer(u32),
|
Pointer(u32),
|
||||||
Touch(TouchSlot),
|
Touch(TouchSlot),
|
||||||
|
Tool(TabletToolDescriptor, TabletGrabTrigger),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -254,6 +259,7 @@ pub struct PendingWindow {
|
||||||
pub surface: CosmicSurface,
|
pub surface: CosmicSurface,
|
||||||
pub seat: Seat<State>,
|
pub seat: Seat<State>,
|
||||||
pub fullscreen: Option<Output>,
|
pub fullscreen: Option<Output>,
|
||||||
|
pub minimized: bool,
|
||||||
pub maximized: bool,
|
pub maximized: bool,
|
||||||
pub sticky: bool,
|
pub sticky: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -1754,7 +1760,7 @@ impl Shell {
|
||||||
if let Some(set) = self.workspaces.sets.get_mut(output) {
|
if let Some(set) = self.workspaces.sets.get_mut(output) {
|
||||||
if matches!(
|
if matches!(
|
||||||
self.overview_mode.active_trigger(),
|
self.overview_mode.active_trigger(),
|
||||||
Some(Trigger::Pointer(_) | Trigger::Touch(_))
|
Some(Trigger::Pointer(_) | Trigger::Touch(_) | Trigger::Tool(_, _))
|
||||||
) {
|
) {
|
||||||
set.workspaces[set.active].tiling_layer.cleanup_drag();
|
set.workspaces[set.active].tiling_layer.cleanup_drag();
|
||||||
}
|
}
|
||||||
|
|
@ -1805,7 +1811,7 @@ impl Shell {
|
||||||
if let Some(set) = self.workspaces.sets.get_mut(output) {
|
if let Some(set) = self.workspaces.sets.get_mut(output) {
|
||||||
if matches!(
|
if matches!(
|
||||||
self.overview_mode.active_trigger(),
|
self.overview_mode.active_trigger(),
|
||||||
Some(Trigger::Pointer(_) | Trigger::Touch(_))
|
Some(Trigger::Pointer(_) | Trigger::Touch(_) | Trigger::Tool(_, _))
|
||||||
) {
|
) {
|
||||||
set.workspaces[set.active].tiling_layer.cleanup_drag();
|
set.workspaces[set.active].tiling_layer.cleanup_drag();
|
||||||
}
|
}
|
||||||
|
|
@ -2856,6 +2862,7 @@ impl Shell {
|
||||||
surface: window,
|
surface: window,
|
||||||
seat,
|
seat,
|
||||||
fullscreen: output,
|
fullscreen: output,
|
||||||
|
minimized: should_be_minimized,
|
||||||
maximized: should_be_maximized,
|
maximized: should_be_maximized,
|
||||||
sticky: mut should_be_sticky,
|
sticky: mut should_be_sticky,
|
||||||
} = self.pending_windows.remove(pos);
|
} = self.pending_windows.remove(pos);
|
||||||
|
|
@ -2939,6 +2946,7 @@ impl Shell {
|
||||||
if let Some(FocusTarget::Window(focused)) = maybe_focused
|
if let Some(FocusTarget::Window(focused)) = maybe_focused
|
||||||
&& let Some(stack) = focused.stack_ref()
|
&& let Some(stack) = focused.stack_ref()
|
||||||
&& !is_dialog
|
&& !is_dialog
|
||||||
|
&& !should_be_minimized
|
||||||
&& !should_be_maximized
|
&& !should_be_maximized
|
||||||
&& !(workspace.is_tiled(&focused.active_window()) && floating_exception)
|
&& !(workspace.is_tiled(&focused.active_window()) && floating_exception)
|
||||||
{
|
{
|
||||||
|
|
@ -2988,8 +2996,13 @@ impl Shell {
|
||||||
self.maximize_request(&mapped, &seat, false, loop_handle);
|
self.maximize_request(&mapped, &seat, false, loop_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_target = if (workspace_output == seat.active_output()
|
if should_be_minimized {
|
||||||
&& active_handle == workspace_handle)
|
self.minimize_request(&window);
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_target = if should_be_minimized {
|
||||||
|
None
|
||||||
|
} else if (workspace_output == seat.active_output() && active_handle == workspace_handle)
|
||||||
|| should_be_sticky
|
|| should_be_sticky
|
||||||
{
|
{
|
||||||
// TODO: enforce focus stealing prevention by also checking the same rules as for the else case.
|
// TODO: enforce focus stealing prevention by also checking the same rules as for the else case.
|
||||||
|
|
@ -3113,6 +3126,7 @@ impl Shell {
|
||||||
surface,
|
surface,
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
fullscreen: None,
|
fullscreen: None,
|
||||||
|
minimized: false,
|
||||||
maximized: false,
|
maximized: false,
|
||||||
sticky: false,
|
sticky: false,
|
||||||
});
|
});
|
||||||
|
|
@ -3831,6 +3845,7 @@ impl Shell {
|
||||||
let trigger = match &start_data {
|
let trigger = match &start_data {
|
||||||
GrabStartData::Pointer(start_data) => Trigger::Pointer(start_data.button),
|
GrabStartData::Pointer(start_data) => Trigger::Pointer(start_data.button),
|
||||||
GrabStartData::Touch(start_data) => Trigger::Touch(start_data.slot),
|
GrabStartData::Touch(start_data) => Trigger::Touch(start_data.slot),
|
||||||
|
GrabStartData::TabletTool { tool, data } => Trigger::Tool(tool.clone(), data.trigger),
|
||||||
};
|
};
|
||||||
let active_hint = if config.cosmic_conf.active_hint {
|
let active_hint = if config.cosmic_conf.active_hint {
|
||||||
self.theme.cosmic().active_hint as u8
|
self.theme.cosmic().active_hint as u8
|
||||||
|
|
@ -5149,10 +5164,19 @@ pub fn check_grab_preconditions(
|
||||||
|
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
let touch = seat.get_touch().unwrap();
|
let touch = seat.get_touch().unwrap();
|
||||||
|
let tablet = seat.tablet_seat();
|
||||||
|
let tools = tablet.get_tools();
|
||||||
|
|
||||||
let start_data =
|
let start_data =
|
||||||
if serial.is_some_and(|serial| touch.has_grab(serial)) {
|
if serial.is_some_and(|serial| touch.has_grab(serial)) {
|
||||||
GrabStartData::Touch(touch.grab_start_data().unwrap())
|
GrabStartData::Touch(touch.grab_start_data().unwrap())
|
||||||
|
} else if let Some((desc, tool)) =
|
||||||
|
serial.and_then(|serial| tools.iter().find(|(_, tool)| tool.has_grab(serial)))
|
||||||
|
{
|
||||||
|
GrabStartData::TabletTool {
|
||||||
|
tool: desc.clone(),
|
||||||
|
data: tool.grab_start_data().unwrap(),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
GrabStartData::Pointer(pointer.grab_start_data().unwrap_or_else(|| {
|
GrabStartData::Pointer(pointer.grab_start_data().unwrap_or_else(|| {
|
||||||
PointerGrabStartData {
|
PointerGrabStartData {
|
||||||
|
|
@ -5166,8 +5190,16 @@ pub fn check_grab_preconditions(
|
||||||
if let Some(surface) = client_initiated {
|
if let Some(surface) = client_initiated {
|
||||||
// Check that this surface has a click or touch down grab.
|
// Check that this surface has a click or touch down grab.
|
||||||
if !match serial {
|
if !match serial {
|
||||||
Some(serial) => pointer.has_grab(serial) || touch.has_grab(serial),
|
Some(serial) => {
|
||||||
None => pointer.is_grabbed() | touch.is_grabbed(),
|
pointer.has_grab(serial)
|
||||||
|
|| touch.has_grab(serial)
|
||||||
|
|| tools.values().any(|tool| tool.has_grab(serial))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
pointer.is_grabbed()
|
||||||
|
|| touch.is_grabbed()
|
||||||
|
|| tools.values().any(|tool| tool.is_grabbed())
|
||||||
|
}
|
||||||
} {
|
} {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,31 @@ use cosmic_comp_config::{ZoomConfig, ZoomMovement};
|
||||||
use cosmic_config::ConfigSet;
|
use cosmic_config::ConfigSet;
|
||||||
use keyframe::{ease, functions::Linear};
|
use keyframe::{ease, functions::Linear};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::ImportMem,
|
backend::{
|
||||||
|
input::{InputTime, TabletToolDescriptor},
|
||||||
|
renderer::ImportMem,
|
||||||
|
},
|
||||||
desktop::space::SpaceElement,
|
desktop::space::SpaceElement,
|
||||||
input::{
|
input::{
|
||||||
Seat,
|
Seat,
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, Focus, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, Focus,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent,
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent,
|
||||||
|
PointerTarget, RelativeMotionEvent,
|
||||||
|
},
|
||||||
|
tablet::{
|
||||||
|
Tablet, TabletSeatTrait,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent,
|
||||||
|
DownEvent as TabletDownEvent, MotionEvent as TabletMotionEvent, TabletToolTarget,
|
||||||
|
UpEvent as TabletUpEvent,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent,
|
DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent,
|
||||||
TouchTarget, UpEvent,
|
OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -33,6 +45,7 @@ use tracing::error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::element::AsGlowRenderer,
|
backend::render::element::AsGlowRenderer,
|
||||||
|
shell::grabs::GrabType,
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
iced::{IcedElement, IcedRenderElement, Program},
|
iced::{IcedElement, IcedRenderElement, Program},
|
||||||
|
|
@ -699,15 +712,27 @@ impl Program for ZoomProgram {
|
||||||
);
|
);
|
||||||
|
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
seat.get_pointer().unwrap().set_grab(
|
}
|
||||||
|
GrabType::Pointer => seat.get_pointer().unwrap().set_grab(
|
||||||
state,
|
state,
|
||||||
grab,
|
grab,
|
||||||
serial,
|
serial,
|
||||||
Focus::Clear,
|
Focus::Clear,
|
||||||
);
|
),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(
|
||||||
|
state,
|
||||||
|
grab,
|
||||||
|
InputTime::now(),
|
||||||
|
serial,
|
||||||
|
Focus::Clear,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -786,15 +811,27 @@ impl Program for ZoomProgram {
|
||||||
);
|
);
|
||||||
|
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(state, grab, serial);
|
GrabType::Touch => {
|
||||||
} else {
|
seat.get_touch().unwrap().set_grab(state, grab, serial)
|
||||||
seat.get_pointer().unwrap().set_grab(
|
}
|
||||||
|
GrabType::Pointer => seat.get_pointer().unwrap().set_grab(
|
||||||
state,
|
state,
|
||||||
grab,
|
grab,
|
||||||
serial,
|
serial,
|
||||||
Focus::Clear,
|
Focus::Clear,
|
||||||
);
|
),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(
|
||||||
|
state,
|
||||||
|
grab,
|
||||||
|
InputTime::now(),
|
||||||
|
serial,
|
||||||
|
Focus::Clear,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -884,14 +921,14 @@ impl PointerTarget<State> for ZoomFocusTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &PointerButtonEvent) {
|
||||||
match self {
|
match self {
|
||||||
ZoomFocusTarget::Main(elem) => PointerTarget::button(elem, seat, data, event),
|
ZoomFocusTarget::Main(elem) => PointerTarget::button(elem, seat, data, event),
|
||||||
ZoomFocusTarget::Menu(elem) => PointerTarget::button(elem, seat, data, event),
|
ZoomFocusTarget::Menu(elem) => PointerTarget::button(elem, seat, data, event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: PointerAxisFrame) {
|
||||||
match self {
|
match self {
|
||||||
ZoomFocusTarget::Main(elem) => PointerTarget::axis(elem, seat, data, frame),
|
ZoomFocusTarget::Main(elem) => PointerTarget::axis(elem, seat, data, frame),
|
||||||
ZoomFocusTarget::Menu(elem) => PointerTarget::axis(elem, seat, data, frame),
|
ZoomFocusTarget::Menu(elem) => PointerTarget::axis(elem, seat, data, frame),
|
||||||
|
|
@ -1024,7 +1061,7 @@ impl PointerTarget<State> for ZoomFocusTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: InputTime) {
|
||||||
match self {
|
match self {
|
||||||
ZoomFocusTarget::Main(elem) => PointerTarget::leave(elem, seat, data, serial, time),
|
ZoomFocusTarget::Main(elem) => PointerTarget::leave(elem, seat, data, serial, time),
|
||||||
ZoomFocusTarget::Menu(elem) => PointerTarget::leave(elem, seat, data, serial, time),
|
ZoomFocusTarget::Menu(elem) => PointerTarget::leave(elem, seat, data, serial, time),
|
||||||
|
|
@ -1033,14 +1070,14 @@ impl PointerTarget<State> for ZoomFocusTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TouchTarget<State> for ZoomFocusTarget {
|
impl TouchTarget<State> for ZoomFocusTarget {
|
||||||
fn down(&self, seat: &Seat<State>, data: &mut State, event: &DownEvent) {
|
fn down(&self, seat: &Seat<State>, data: &mut State, event: &TouchDownEvent) {
|
||||||
match self {
|
match self {
|
||||||
ZoomFocusTarget::Main(elem) => TouchTarget::down(elem, seat, data, event),
|
ZoomFocusTarget::Main(elem) => TouchTarget::down(elem, seat, data, event),
|
||||||
ZoomFocusTarget::Menu(elem) => TouchTarget::down(elem, seat, data, event),
|
ZoomFocusTarget::Menu(elem) => TouchTarget::down(elem, seat, data, event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up(&self, seat: &Seat<State>, data: &mut State, event: &UpEvent) {
|
fn up(&self, seat: &Seat<State>, data: &mut State, event: &TouchUpEvent) {
|
||||||
match self {
|
match self {
|
||||||
ZoomFocusTarget::Main(elem) => TouchTarget::up(elem, seat, data, event),
|
ZoomFocusTarget::Main(elem) => TouchTarget::up(elem, seat, data, event),
|
||||||
ZoomFocusTarget::Menu(elem) => TouchTarget::up(elem, seat, data, event),
|
ZoomFocusTarget::Menu(elem) => TouchTarget::up(elem, seat, data, event),
|
||||||
|
|
@ -1090,6 +1127,144 @@ impl TouchTarget<State> for ZoomFocusTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TabletToolTarget<State> for ZoomFocusTarget {
|
||||||
|
fn proximity_in(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
tablet: &Tablet,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ZoomFocusTarget::Main(elem) => {
|
||||||
|
TabletToolTarget::proximity_in(elem, seat, data, tool_descriptor, tablet, serial)
|
||||||
|
}
|
||||||
|
ZoomFocusTarget::Menu(elem) => {
|
||||||
|
TabletToolTarget::proximity_in(elem, seat, data, tool_descriptor, tablet, serial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ZoomFocusTarget::Main(elem) => {
|
||||||
|
TabletToolTarget::proximity_out(elem, seat, data, tool_descriptor)
|
||||||
|
}
|
||||||
|
ZoomFocusTarget::Menu(elem) => {
|
||||||
|
TabletToolTarget::proximity_out(elem, seat, data, tool_descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &TabletDownEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ZoomFocusTarget::Main(elem) => {
|
||||||
|
TabletToolTarget::down(elem, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
ZoomFocusTarget::Menu(elem) => {
|
||||||
|
TabletToolTarget::down(elem, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &TabletUpEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ZoomFocusTarget::Main(elem) => {
|
||||||
|
TabletToolTarget::up(elem, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
ZoomFocusTarget::Menu(elem) => {
|
||||||
|
TabletToolTarget::up(elem, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &TabletMotionEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ZoomFocusTarget::Main(elem) => {
|
||||||
|
TabletToolTarget::motion(elem, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
ZoomFocusTarget::Menu(elem) => {
|
||||||
|
TabletToolTarget::motion(elem, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
frame: TabletAxisFrame,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ZoomFocusTarget::Main(elem) => {
|
||||||
|
TabletToolTarget::axis(elem, seat, data, tool_descriptor, frame)
|
||||||
|
}
|
||||||
|
ZoomFocusTarget::Menu(elem) => {
|
||||||
|
TabletToolTarget::axis(elem, seat, data, tool_descriptor, frame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &TabletButtonEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ZoomFocusTarget::Main(elem) => {
|
||||||
|
TabletToolTarget::button(elem, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
ZoomFocusTarget::Menu(elem) => {
|
||||||
|
TabletToolTarget::button(elem, seat, data, tool_descriptor, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
tool_descriptor: &TabletToolDescriptor,
|
||||||
|
time: InputTime,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
ZoomFocusTarget::Main(elem) => {
|
||||||
|
TabletToolTarget::frame(elem, seat, data, tool_descriptor, time)
|
||||||
|
}
|
||||||
|
ZoomFocusTarget::Menu(elem) => {
|
||||||
|
TabletToolTarget::frame(elem, seat, data, tool_descriptor, time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IsAlive for ZoomFocusTarget {
|
impl IsAlive for ZoomFocusTarget {
|
||||||
fn alive(&self) -> bool {
|
fn alive(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
||||||
37
src/state.rs
37
src/state.rs
|
|
@ -1328,8 +1328,12 @@ impl Common {
|
||||||
const THROTTLE: Option<Duration> = Some(Duration::from_millis(995));
|
const THROTTLE: Option<Duration> = Some(Duration::from_millis(995));
|
||||||
const SCREENCOPY_THROTTLE: Option<Duration> = Some(Duration::from_nanos(16_666_666));
|
const SCREENCOPY_THROTTLE: Option<Duration> = Some(Duration::from_nanos(16_666_666));
|
||||||
|
|
||||||
fn throttle(session_holder: &impl SessionHolder) -> Option<Duration> {
|
fn throttle(session_holder: &impl SessionHolder, is_xwayland: bool) -> Option<Duration> {
|
||||||
if session_holder.sessions().is_empty() && session_holder.cursor_sessions().is_empty() {
|
if is_xwayland {
|
||||||
|
Some(Duration::ZERO)
|
||||||
|
} else if session_holder.sessions().is_empty()
|
||||||
|
&& session_holder.cursor_sessions().is_empty()
|
||||||
|
{
|
||||||
THROTTLE
|
THROTTLE
|
||||||
} else {
|
} else {
|
||||||
SCREENCOPY_THROTTLE
|
SCREENCOPY_THROTTLE
|
||||||
|
|
@ -1365,7 +1369,8 @@ impl Common {
|
||||||
&& let Some(grab_state) = move_grab.lock().unwrap().as_ref()
|
&& let Some(grab_state) = move_grab.lock().unwrap().as_ref()
|
||||||
{
|
{
|
||||||
for (window, _) in grab_state.element().windows() {
|
for (window, _) in grab_state.element().windows() {
|
||||||
window.send_frame(output, time, throttle(&window), should_send);
|
let throttle = throttle(&window, window.x11_surface().is_some());
|
||||||
|
window.send_frame(output, time, throttle, should_send);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1389,25 +1394,28 @@ impl Common {
|
||||||
.mapped()
|
.mapped()
|
||||||
.for_each(|mapped| {
|
.for_each(|mapped| {
|
||||||
for (window, _) in mapped.windows() {
|
for (window, _) in mapped.windows() {
|
||||||
window.send_frame(output, time, throttle(&window), should_send);
|
let throttle = throttle(&window, window.x11_surface().is_some());
|
||||||
|
window.send_frame(output, time, throttle, should_send);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(active) = shell.active_space(output) {
|
if let Some(active) = shell.active_space(output) {
|
||||||
if let Some(fs) = active.get_fullscreen(shell.seats.last_active()) {
|
if let Some(fs) = active.get_fullscreen(shell.seats.last_active()) {
|
||||||
fs.surface
|
let throttle = throttle(&fs.surface, fs.surface.x11_surface().is_some());
|
||||||
.send_frame(output, time, throttle(&fs.surface), should_send);
|
fs.surface.send_frame(output, time, throttle, should_send);
|
||||||
}
|
}
|
||||||
active.mapped().for_each(|mapped| {
|
active.mapped().for_each(|mapped| {
|
||||||
for (window, _) in mapped.windows() {
|
for (window, _) in mapped.windows() {
|
||||||
window.send_frame(output, time, throttle(&window), should_send);
|
let throttle = throttle(&window, window.x11_surface().is_some());
|
||||||
|
window.send_frame(output, time, throttle, should_send);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// other (throttled) windows
|
// other (throttled) windows
|
||||||
active.minimized_windows.iter().for_each(|m| {
|
active.minimized_windows.iter().for_each(|m| {
|
||||||
for window in m.windows() {
|
for window in m.windows() {
|
||||||
window.send_frame(output, time, throttle(&window), |_, _| None);
|
let throttle = throttle(&window, window.x11_surface().is_some());
|
||||||
|
window.send_frame(output, time, throttle, |_, _| None);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1417,18 +1425,25 @@ impl Common {
|
||||||
.filter(|w| w.handle != active.handle)
|
.filter(|w| w.handle != active.handle)
|
||||||
{
|
{
|
||||||
if let Some(fs) = space.get_fullscreen(shell.seats.last_active()) {
|
if let Some(fs) = space.get_fullscreen(shell.seats.last_active()) {
|
||||||
let throttle = min(throttle(space), throttle(&fs.surface));
|
let throttle = min(
|
||||||
|
throttle(space, false),
|
||||||
|
throttle(&fs.surface, fs.surface.x11_surface().is_some()),
|
||||||
|
);
|
||||||
fs.surface.send_frame(output, time, throttle, |_, _| None);
|
fs.surface.send_frame(output, time, throttle, |_, _| None);
|
||||||
}
|
}
|
||||||
space.mapped().for_each(|mapped| {
|
space.mapped().for_each(|mapped| {
|
||||||
for (window, _) in mapped.windows() {
|
for (window, _) in mapped.windows() {
|
||||||
let throttle = min(throttle(space), throttle(&window));
|
let throttle = min(
|
||||||
|
throttle(space, false),
|
||||||
|
throttle(&window, window.x11_surface().is_some()),
|
||||||
|
);
|
||||||
window.send_frame(output, time, throttle, |_, _| None);
|
window.send_frame(output, time, throttle, |_, _| None);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
space.minimized_windows.iter().for_each(|m| {
|
space.minimized_windows.iter().for_each(|m| {
|
||||||
for window in m.windows() {
|
for window in m.windows() {
|
||||||
window.send_frame(output, time, throttle(&window), |_, _| None);
|
let throttle = throttle(&window, window.x11_surface().is_some());
|
||||||
|
window.send_frame(output, time, throttle, |_, _| None);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ use ordered_float::OrderedFloat;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::Fourcc,
|
allocator::Fourcc,
|
||||||
input::{ButtonState, KeyState},
|
input::{ButtonState, InputTime, KeyState, TabletToolDescriptor},
|
||||||
renderer::{
|
renderer::{
|
||||||
ImportMem,
|
ImportMem,
|
||||||
element::{
|
element::{
|
||||||
|
|
@ -45,14 +45,23 @@ use smithay::{
|
||||||
Seat,
|
Seat,
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
|
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||||
|
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent,
|
||||||
PointerTarget, RelativeMotionEvent,
|
PointerTarget, RelativeMotionEvent,
|
||||||
},
|
},
|
||||||
|
tablet::{
|
||||||
|
Tablet,
|
||||||
|
tool::{
|
||||||
|
AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent,
|
||||||
|
DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolTarget,
|
||||||
|
UpEvent as ToolUpEvent,
|
||||||
|
},
|
||||||
|
},
|
||||||
touch::{
|
touch::{
|
||||||
DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent,
|
DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent,
|
||||||
TouchTarget, UpEvent,
|
OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -189,6 +198,7 @@ pub(crate) struct IcedElementInternal<P: Program + Send + 'static> {
|
||||||
touch_map: HashMap<Finger, IcedPoint>,
|
touch_map: HashMap<Finger, IcedPoint>,
|
||||||
last_touch_frame: Option<FrameMarker>,
|
last_touch_frame: Option<FrameMarker>,
|
||||||
last_touch_serial: Option<Serial>,
|
last_touch_serial: Option<Serial>,
|
||||||
|
last_tablet_serial: Option<Serial>,
|
||||||
|
|
||||||
// iced
|
// iced
|
||||||
theme: Theme,
|
theme: Theme,
|
||||||
|
|
@ -240,6 +250,7 @@ impl<P: Program + Send + Clone + 'static> Clone for IcedElementInternal<P> {
|
||||||
touch_map: self.touch_map.clone(),
|
touch_map: self.touch_map.clone(),
|
||||||
last_touch_frame: None,
|
last_touch_frame: None,
|
||||||
last_touch_serial: None,
|
last_touch_serial: None,
|
||||||
|
last_tablet_serial: None,
|
||||||
theme: self.theme.clone(),
|
theme: self.theme.clone(),
|
||||||
renderer,
|
renderer,
|
||||||
state,
|
state,
|
||||||
|
|
@ -267,6 +278,7 @@ impl<P: Program + Send + 'static> fmt::Debug for IcedElementInternal<P> {
|
||||||
.field("touch_map", &self.touch_map)
|
.field("touch_map", &self.touch_map)
|
||||||
.field("last_touch_frame", &self.last_touch_frame)
|
.field("last_touch_frame", &self.last_touch_frame)
|
||||||
.field("last_touch_serial", &self.last_touch_serial)
|
.field("last_touch_serial", &self.last_touch_serial)
|
||||||
|
.field("last_tablet_serial", &self.last_tablet_serial)
|
||||||
.field("theme", &"...")
|
.field("theme", &"...")
|
||||||
.field("renderer", &"...")
|
.field("renderer", &"...")
|
||||||
.field("state", &"...")
|
.field("state", &"...")
|
||||||
|
|
@ -326,6 +338,7 @@ impl<P: Program + Send + 'static> IcedElement<P> {
|
||||||
touch_map: HashMap::new(),
|
touch_map: HashMap::new(),
|
||||||
last_touch_frame: None,
|
last_touch_frame: None,
|
||||||
last_touch_serial: None,
|
last_touch_serial: None,
|
||||||
|
last_tablet_serial: None,
|
||||||
theme,
|
theme,
|
||||||
renderer,
|
renderer,
|
||||||
state,
|
state,
|
||||||
|
|
@ -481,12 +494,143 @@ impl<P: Program + Send + 'static> IcedElementInternal<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<P: Program + Send + 'static> TabletToolTarget<crate::state::State> for IcedElement<P> {
|
||||||
|
fn proximity_in(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<crate::state::State>,
|
||||||
|
_data: &mut crate::state::State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_tablet: &Tablet,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
internal
|
||||||
|
.state
|
||||||
|
.queue_event(Event::Mouse(MouseEvent::CursorEntered));
|
||||||
|
internal.last_tablet_serial = Some(serial);
|
||||||
|
*internal.last_seat.lock().unwrap() = Some((seat.clone(), serial));
|
||||||
|
internal.update(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn proximity_out(
|
||||||
|
&self,
|
||||||
|
_seat: &Seat<crate::state::State>,
|
||||||
|
_data: &mut crate::state::State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
) {
|
||||||
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
internal
|
||||||
|
.state
|
||||||
|
.queue_event(Event::Mouse(MouseEvent::CursorLeft));
|
||||||
|
internal.update(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<crate::state::State>,
|
||||||
|
_data: &mut crate::state::State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolDownEvent,
|
||||||
|
) {
|
||||||
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
let id = Finger(0);
|
||||||
|
let Some(event_location) = internal.cursor_pos else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let position = IcedPoint::new(event_location.x as f32, event_location.y as f32);
|
||||||
|
internal
|
||||||
|
.state
|
||||||
|
.queue_event(Event::Touch(TouchEvent::FingerPressed { id, position }));
|
||||||
|
internal.last_tablet_serial = Some(event.serial);
|
||||||
|
*internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
|
||||||
|
internal.update(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<crate::state::State>,
|
||||||
|
_data: &mut crate::state::State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_event: &ToolUpEvent,
|
||||||
|
) {
|
||||||
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
let id = Finger(0);
|
||||||
|
if let Some(event_location) = internal.cursor_pos {
|
||||||
|
*internal.last_seat.lock().unwrap() =
|
||||||
|
Some((seat.clone(), internal.last_tablet_serial.unwrap()));
|
||||||
|
let position = IcedPoint::new(event_location.x as f32, event_location.y as f32);
|
||||||
|
internal
|
||||||
|
.state
|
||||||
|
.queue_event(Event::Touch(TouchEvent::FingerLifted { id, position }));
|
||||||
|
internal.update(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<crate::state::State>,
|
||||||
|
_data: &mut crate::state::State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolMotionEvent,
|
||||||
|
) {
|
||||||
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
let event_location = event.location.downscale(internal.additional_scale);
|
||||||
|
let position = IcedPoint::new(event_location.x as f32, event_location.y as f32);
|
||||||
|
internal
|
||||||
|
.state
|
||||||
|
.queue_event(Event::Mouse(MouseEvent::CursorMoved { position }));
|
||||||
|
internal.cursor_pos = Some(event_location);
|
||||||
|
*internal.last_seat.lock().unwrap() =
|
||||||
|
Some((seat.clone(), internal.last_tablet_serial.unwrap()));
|
||||||
|
internal.update(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(
|
||||||
|
&self,
|
||||||
|
_seat: &Seat<crate::state::State>,
|
||||||
|
_data: &mut crate::state::State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_frame: ToolAxisFrame,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<crate::state::State>,
|
||||||
|
_data: &mut crate::state::State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
event: &ToolButtonEvent,
|
||||||
|
) {
|
||||||
|
let mut internal = self.0.lock().unwrap();
|
||||||
|
let button = match event.button {
|
||||||
|
0x14b => MouseButton::Right,
|
||||||
|
0x14c => MouseButton::Middle,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
internal.state.queue_event(Event::Mouse(match event.state {
|
||||||
|
ButtonState::Pressed => MouseEvent::ButtonPressed(button),
|
||||||
|
ButtonState::Released => MouseEvent::ButtonReleased(button),
|
||||||
|
}));
|
||||||
|
*internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
|
||||||
|
internal.update(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&self,
|
||||||
|
_seat: &Seat<crate::state::State>,
|
||||||
|
_data: &mut crate::state::State,
|
||||||
|
_tool_descriptor: &TabletToolDescriptor,
|
||||||
|
_time: InputTime,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedElement<P> {
|
impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedElement<P> {
|
||||||
fn enter(
|
fn enter(
|
||||||
&self,
|
&self,
|
||||||
seat: &Seat<crate::state::State>,
|
seat: &Seat<crate::state::State>,
|
||||||
_data: &mut crate::state::State,
|
_data: &mut crate::state::State,
|
||||||
event: &MotionEvent,
|
event: &PointerMotionEvent,
|
||||||
) {
|
) {
|
||||||
let mut internal = self.0.lock().unwrap();
|
let mut internal = self.0.lock().unwrap();
|
||||||
internal
|
internal
|
||||||
|
|
@ -507,7 +651,7 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
|
||||||
&self,
|
&self,
|
||||||
seat: &Seat<crate::state::State>,
|
seat: &Seat<crate::state::State>,
|
||||||
_data: &mut crate::state::State,
|
_data: &mut crate::state::State,
|
||||||
event: &MotionEvent,
|
event: &PointerMotionEvent,
|
||||||
) {
|
) {
|
||||||
let mut internal = self.0.lock().unwrap();
|
let mut internal = self.0.lock().unwrap();
|
||||||
let event_location = event.location.downscale(internal.additional_scale);
|
let event_location = event.location.downscale(internal.additional_scale);
|
||||||
|
|
@ -532,7 +676,7 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
|
||||||
&self,
|
&self,
|
||||||
seat: &Seat<crate::state::State>,
|
seat: &Seat<crate::state::State>,
|
||||||
_data: &mut crate::state::State,
|
_data: &mut crate::state::State,
|
||||||
event: &ButtonEvent,
|
event: &PointerButtonEvent,
|
||||||
) {
|
) {
|
||||||
let mut internal = self.0.lock().unwrap();
|
let mut internal = self.0.lock().unwrap();
|
||||||
let button = match event.button {
|
let button = match event.button {
|
||||||
|
|
@ -553,7 +697,7 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
|
||||||
&self,
|
&self,
|
||||||
_seat: &Seat<crate::state::State>,
|
_seat: &Seat<crate::state::State>,
|
||||||
_data: &mut crate::state::State,
|
_data: &mut crate::state::State,
|
||||||
frame: AxisFrame,
|
frame: PointerAxisFrame,
|
||||||
) {
|
) {
|
||||||
let mut internal = self.0.lock().unwrap();
|
let mut internal = self.0.lock().unwrap();
|
||||||
internal
|
internal
|
||||||
|
|
@ -581,7 +725,7 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
|
||||||
_seat: &Seat<crate::state::State>,
|
_seat: &Seat<crate::state::State>,
|
||||||
_data: &mut crate::state::State,
|
_data: &mut crate::state::State,
|
||||||
_serial: Serial,
|
_serial: Serial,
|
||||||
_time: u32,
|
_time: InputTime,
|
||||||
) {
|
) {
|
||||||
let mut internal = self.0.lock().unwrap();
|
let mut internal = self.0.lock().unwrap();
|
||||||
internal
|
internal
|
||||||
|
|
@ -653,7 +797,7 @@ impl<P: Program + Send + 'static> TouchTarget<crate::state::State> for IcedEleme
|
||||||
&self,
|
&self,
|
||||||
seat: &Seat<crate::state::State>,
|
seat: &Seat<crate::state::State>,
|
||||||
_data: &mut crate::state::State,
|
_data: &mut crate::state::State,
|
||||||
event: &DownEvent,
|
event: &TouchDownEvent,
|
||||||
) {
|
) {
|
||||||
let mut internal = self.0.lock().unwrap();
|
let mut internal = self.0.lock().unwrap();
|
||||||
let id = Finger(i32::from(event.slot) as u64);
|
let id = Finger(i32::from(event.slot) as u64);
|
||||||
|
|
@ -673,7 +817,7 @@ impl<P: Program + Send + 'static> TouchTarget<crate::state::State> for IcedEleme
|
||||||
&self,
|
&self,
|
||||||
seat: &Seat<crate::state::State>,
|
seat: &Seat<crate::state::State>,
|
||||||
_data: &mut crate::state::State,
|
_data: &mut crate::state::State,
|
||||||
event: &UpEvent,
|
event: &TouchUpEvent,
|
||||||
) {
|
) {
|
||||||
let mut internal = self.0.lock().unwrap();
|
let mut internal = self.0.lock().unwrap();
|
||||||
let id = Finger(i32::from(event.slot) as u64);
|
let id = Finger(i32::from(event.slot) as u64);
|
||||||
|
|
@ -784,7 +928,7 @@ impl<P: Program + Send + 'static> KeyboardTarget<crate::state::State> for IcedEl
|
||||||
_key: KeysymHandle<'_>,
|
_key: KeysymHandle<'_>,
|
||||||
_state: KeyState,
|
_state: KeyState,
|
||||||
_serial: Serial,
|
_serial: Serial,
|
||||||
_time: u32,
|
_time: InputTime,
|
||||||
) {
|
) {
|
||||||
// TODO convert keys
|
// TODO convert keys
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,13 @@
|
||||||
use crate::{shell::grabs::SeatMoveGrabState, state::ClientState, utils::prelude::*};
|
use crate::{shell::grabs::SeatMoveGrabState, state::ClientState, utils::prelude::*};
|
||||||
use calloop::Interest;
|
use calloop::Interest;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::{
|
||||||
|
input::InputTime,
|
||||||
|
renderer::{
|
||||||
element::{Kind, surface::KindEvaluation},
|
element::{Kind, surface::KindEvaluation},
|
||||||
utils::{on_commit_buffer_handler, with_renderer_surface_state},
|
utils::{on_commit_buffer_handler, with_renderer_surface_state},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
desktop::{LayerSurface, PopupKind, WindowSurfaceType, layer_map_for_output},
|
desktop::{LayerSurface, PopupKind, WindowSurfaceType, layer_map_for_output},
|
||||||
reexports::wayland_server::{Client, Resource, protocol::wl_surface::WlSurface},
|
reexports::wayland_server::{Client, Resource, protocol::wl_surface::WlSurface},
|
||||||
utils::{Clock, Logical, Monotonic, SERIAL_COUNTER, Size, Time},
|
utils::{Clock, Logical, Monotonic, SERIAL_COUNTER, Size, Time},
|
||||||
|
|
@ -325,9 +328,11 @@ impl CompositorHandler for State {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
seat.get_pointer()
|
seat.get_pointer().unwrap().unset_grab(
|
||||||
.unwrap()
|
self,
|
||||||
.unset_grab(self, SERIAL_COUNTER.next_serial(), 0);
|
SERIAL_COUNTER.next_serial(),
|
||||||
|
InputTime::now(),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,18 +45,11 @@ pub fn surface_corners(states: &SurfaceData, size: Size<i32, Logical>) -> Option
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn surface_padding(states: &SurfaceData, size: Size<i32, Logical>) -> Option<[i32; 4]> {
|
pub fn surface_padding(states: &SurfaceData) -> Option<[i32; 4]> {
|
||||||
let mut guard = states.cached_state.get::<CacheablePadding>();
|
let mut guard = states.cached_state.get::<CacheablePadding>();
|
||||||
|
|
||||||
let padding = guard.current().0?;
|
let padding = guard.current().0?;
|
||||||
|
Some([padding.top, padding.right, padding.bottom, padding.left])
|
||||||
// guard against padding being too large
|
|
||||||
Some([
|
|
||||||
padding.top.min(size.h / 2),
|
|
||||||
padding.right.min(size.w / 2),
|
|
||||||
padding.bottom.min(size.h / 2),
|
|
||||||
padding.left.min(size.w / 2),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pad_rect(
|
pub fn pad_rect(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{cell::RefCell, sync::Mutex};
|
use std::{cell::RefCell, sync::Mutex};
|
||||||
|
|
||||||
|
use cosmic_comp_config::DecorationPreference;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::Window,
|
desktop::Window,
|
||||||
reexports::{
|
reexports::{
|
||||||
|
|
@ -20,7 +21,7 @@ use smithay::{
|
||||||
};
|
};
|
||||||
use wayland_backend::protocol::WEnum;
|
use wayland_backend::protocol::WEnum;
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::{shell::CosmicMapped, state::State};
|
||||||
|
|
||||||
pub struct PreferredDecorationMode(RefCell<Option<XdgMode>>);
|
pub struct PreferredDecorationMode(RefCell<Option<XdgMode>>);
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ impl PreferredDecorationMode {
|
||||||
window
|
window
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<PreferredDecorationMode>()
|
.get::<PreferredDecorationMode>()
|
||||||
.is_none()
|
.is_none_or(|mode| mode.0.borrow().is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mode(window: &Window) -> Option<XdgMode> {
|
pub fn mode(window: &Window) -> Option<XdgMode> {
|
||||||
|
|
@ -53,6 +54,72 @@ impl PreferredDecorationMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn default_decoration(&self) -> DecorationPreference {
|
||||||
|
self.common.config.cosmic_conf.decoration_preference
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_decorations(&self) {
|
||||||
|
let shell = self.common.shell.read();
|
||||||
|
|
||||||
|
let update = |mapped: &CosmicMapped| {
|
||||||
|
let mode = if mapped.is_stack() {
|
||||||
|
XdgMode::ServerSide
|
||||||
|
} else {
|
||||||
|
XdgMode::from_preference(self.default_decoration())
|
||||||
|
};
|
||||||
|
for (window, _) in mapped.windows() {
|
||||||
|
if PreferredDecorationMode::is_unset(&window.0)
|
||||||
|
&& let Some(toplevel) = window.0.toplevel()
|
||||||
|
&& toplevel.with_committed_state(|state| {
|
||||||
|
state.is_some_and(|state| state.decoration_mode.is_some())
|
||||||
|
})
|
||||||
|
{
|
||||||
|
toplevel.with_pending_state(|state| {
|
||||||
|
state.decoration_mode = Some(mode);
|
||||||
|
});
|
||||||
|
toplevel.send_configure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for set in shell.workspaces.sets.values() {
|
||||||
|
set.sticky_layer.mapped().for_each(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
for space in shell.workspaces.spaces() {
|
||||||
|
space.mapped().for_each(update);
|
||||||
|
space
|
||||||
|
.minimized_windows
|
||||||
|
.iter()
|
||||||
|
.filter_map(|m| m.mapped())
|
||||||
|
.for_each(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait FromDecorationPreference {
|
||||||
|
fn from_preference(preference: DecorationPreference) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromDecorationPreference for XdgMode {
|
||||||
|
fn from_preference(preference: DecorationPreference) -> Self {
|
||||||
|
match preference {
|
||||||
|
DecorationPreference::ClientSide => XdgMode::ClientSide,
|
||||||
|
DecorationPreference::ServerSide => XdgMode::ServerSide,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromDecorationPreference for KdeMode {
|
||||||
|
fn from_preference(preference: DecorationPreference) -> Self {
|
||||||
|
match preference {
|
||||||
|
DecorationPreference::ClientSide => KdeMode::Client,
|
||||||
|
DecorationPreference::ServerSide => KdeMode::Server,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type KdeDecorationData = Mutex<KdeDecorationSurfaceState>;
|
pub type KdeDecorationData = Mutex<KdeDecorationSurfaceState>;
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct KdeDecorationSurfaceState {
|
pub struct KdeDecorationSurfaceState {
|
||||||
|
|
@ -67,7 +134,7 @@ impl XdgDecorationHandler for State {
|
||||||
let mode = if mapped.is_stack() {
|
let mode = if mapped.is_stack() {
|
||||||
XdgMode::ServerSide
|
XdgMode::ServerSide
|
||||||
} else {
|
} else {
|
||||||
XdgMode::ClientSide
|
XdgMode::from_preference(self.default_decoration())
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((window, _)) = mapped
|
if let Some((window, _)) = mapped
|
||||||
|
|
@ -80,6 +147,10 @@ impl XdgDecorationHandler for State {
|
||||||
});
|
});
|
||||||
toplevel.send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
toplevel.with_pending_state(|state| {
|
||||||
|
state.decoration_mode = Some(XdgMode::from_preference(self.default_decoration()))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,6 +170,13 @@ impl XdgDecorationHandler for State {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
|
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
|
||||||
|
if let Some(pending) = shell
|
||||||
|
.pending_windows
|
||||||
|
.iter()
|
||||||
|
.find(|pending| pending.surface.0.toplevel().is_some_and(|t| t == &toplevel))
|
||||||
|
{
|
||||||
|
PreferredDecorationMode::update(&pending.surface.0, Some(mode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,11 +188,28 @@ impl XdgDecorationHandler for State {
|
||||||
.find(|(window, _)| window.wl_surface().as_deref() == Some(toplevel.wl_surface()))
|
.find(|(window, _)| window.wl_surface().as_deref() == Some(toplevel.wl_surface()))
|
||||||
&& let Some(toplevel) = window.0.toplevel()
|
&& let Some(toplevel) = window.0.toplevel()
|
||||||
{
|
{
|
||||||
|
let mode = if mapped.is_stack() {
|
||||||
|
XdgMode::ServerSide
|
||||||
|
} else {
|
||||||
|
XdgMode::from_preference(self.default_decoration())
|
||||||
|
};
|
||||||
|
|
||||||
PreferredDecorationMode::update(&window.0, None);
|
PreferredDecorationMode::update(&window.0, None);
|
||||||
toplevel.with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.decoration_mode = None;
|
state.decoration_mode = Some(mode);
|
||||||
});
|
});
|
||||||
toplevel.send_configure();
|
toplevel.send_configure();
|
||||||
|
} else {
|
||||||
|
toplevel.with_pending_state(|state| {
|
||||||
|
state.decoration_mode = Some(XdgMode::from_preference(self.default_decoration()))
|
||||||
|
});
|
||||||
|
if let Some(pending) = shell
|
||||||
|
.pending_windows
|
||||||
|
.iter()
|
||||||
|
.find(|pending| pending.surface.0.toplevel().is_some_and(|t| t == &toplevel))
|
||||||
|
{
|
||||||
|
PreferredDecorationMode::update(&pending.surface.0, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -129,10 +224,10 @@ impl KdeDecorationHandler for State {
|
||||||
if mapped.is_stack() {
|
if mapped.is_stack() {
|
||||||
KdeMode::Server
|
KdeMode::Server
|
||||||
} else {
|
} else {
|
||||||
KdeMode::Client
|
KdeMode::from_preference(self.default_decoration())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
KdeMode::Client
|
KdeMode::from_preference(self.default_decoration())
|
||||||
};
|
};
|
||||||
|
|
||||||
with_states(surface, |states| {
|
with_states(surface, |states| {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use smithay::input::keyboard::KeyboardHandle;
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::wayland::protocols::keyboard_layout::{KeyboardLayoutHandler, KeyboardLayoutState};
|
use crate::wayland::protocols::keyboard_layout::{KeyboardLayoutHandler, KeyboardLayoutState};
|
||||||
|
|
||||||
|
|
@ -7,4 +9,8 @@ impl KeyboardLayoutHandler for State {
|
||||||
fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState {
|
fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState {
|
||||||
&mut self.common.keyboard_layout_state
|
&mut self.common.keyboard_layout_state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn group_changed(&mut self, keyboard: &KeyboardHandle<Self>) {
|
||||||
|
self.broadcast_ei_keyboard_modifiers(keyboard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ use smithay::{
|
||||||
input::pointer::PointerHandle,
|
input::pointer::PointerHandle,
|
||||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
utils::{Logical, Point},
|
utils::{Logical, Point},
|
||||||
wayland::{pointer_constraints::PointerConstraintsHandler, seat::WaylandFocus},
|
wayland::{
|
||||||
|
pointer_constraints::{ConstraintRemove, PointerConstraintsHandler},
|
||||||
|
seat::WaylandFocus,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use smithay::wayland::pointer_constraints::{PointerConstraintRef, with_pointer_constraint};
|
pub use smithay::wayland::pointer_constraints::{PointerConstraintRef, with_pointer_constraint};
|
||||||
|
|
@ -76,26 +79,40 @@ impl PointerConstraintsHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle<Self>) {
|
fn remove_constraint(
|
||||||
if with_pointer_constraint(surface, pointer, |constraint| constraint.is_none()) {
|
&mut self,
|
||||||
let seat = self
|
surface: &WlSurface,
|
||||||
|
pointer: &PointerHandle<Self>,
|
||||||
|
constraint_remove: ConstraintRemove,
|
||||||
|
) {
|
||||||
|
match constraint_remove {
|
||||||
|
ConstraintRemove::PointerLeave(_) => {
|
||||||
|
// If the constraint was broken by the pointer forcibly leaving the surface, then it doesn't
|
||||||
|
// make much sense to warp it.
|
||||||
|
}
|
||||||
|
ConstraintRemove::Destroyed(constraint) => {
|
||||||
|
let Some(seat) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.read()
|
.read()
|
||||||
.seats
|
.seats
|
||||||
.iter()
|
.iter()
|
||||||
.find(|s| s.get_pointer().as_ref() == Some(pointer))
|
.find(|s| s.get_pointer().as_ref() == Some(pointer))
|
||||||
.cloned();
|
.cloned()
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some((hint_surface, hint_location)) = seat.pointer_constraint_hint() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(seat) = seat
|
if hint_surface == *surface {
|
||||||
&& let Some((hint_surface, hint_location)) = seat.pointer_constraint_hint()
|
self.apply_cursor_hint(surface, pointer, hint_location, Some(&constraint));
|
||||||
&& hint_surface == *surface
|
|
||||||
{
|
|
||||||
self.apply_cursor_hint(surface, pointer, hint_location);
|
|
||||||
seat.set_pointer_constraint_hint(None);
|
seat.set_pointer_constraint_hint(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn cursor_position_hint(
|
fn cursor_position_hint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ impl PointerWarpHandler for State {
|
||||||
drop(shell);
|
drop(shell);
|
||||||
|
|
||||||
if let Some(pointer_handle) = pointer_handle {
|
if let Some(pointer_handle) = pointer_handle {
|
||||||
self.apply_cursor_hint(&surface, &pointer_handle, pos);
|
self.apply_cursor_hint(&surface, &pointer_handle, pos, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::{shell::focus::target::PointerFocusTarget, state::State};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::TabletToolDescriptor, input::pointer::CursorImageStatus,
|
backend::input::TabletToolDescriptor, input::pointer::CursorImageStatus,
|
||||||
input::tablet::TabletSeatHandler, reexports::wayland_server::protocol::wl_surface,
|
input::tablet::TabletSeatHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl TabletSeatHandler for State {
|
impl TabletSeatHandler for State {
|
||||||
type ToolFocus = wl_surface::WlSurface;
|
type ToolFocus = PointerFocusTarget;
|
||||||
|
|
||||||
fn tablet_tool_image(&mut self, _tool: &TabletToolDescriptor, _image: CursorImageStatus) {
|
fn tablet_tool_image(&mut self, _tool: &TabletToolDescriptor, _image: CursorImageStatus) {
|
||||||
// TODO display cursor for each tablet tool
|
// TODO display cursor for each tablet tool
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
backend::input::InputTime,
|
||||||
desktop::{WindowSurfaceType, layer_map_for_output},
|
desktop::{WindowSurfaceType, layer_map_for_output},
|
||||||
input::{Seat, pointer::MotionEvent},
|
input::{Seat, pointer::MotionEvent},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -124,7 +125,7 @@ impl ToplevelManagementHandler for State {
|
||||||
&MotionEvent {
|
&MotionEvent {
|
||||||
location: new_pos.to_f64().as_logical(),
|
location: new_pos.to_f64().as_logical(),
|
||||||
serial,
|
serial,
|
||||||
time: self.common.clock.now().as_millis(),
|
time: InputTime::now(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
ptr.frame(self);
|
ptr.frame(self);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
shell::{CosmicSurface, PendingWindow, focus::target::KeyboardFocusTarget, grabs::ReleaseMode},
|
shell::{
|
||||||
|
CosmicSurface, PendingWindow,
|
||||||
|
focus::target::KeyboardFocusTarget,
|
||||||
|
grabs::{GrabType, ReleaseMode},
|
||||||
|
},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
};
|
};
|
||||||
use smithay::desktop::layer_map_for_output;
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
backend::input::InputTime,
|
||||||
desktop::{
|
desktop::{
|
||||||
PopupGrab, PopupKeyboardGrab, PopupKind, PopupPointerGrab, PopupUngrabStrategy,
|
PopupGrab, PopupKeyboardGrab, PopupKind, PopupPointerGrab, PopupUngrabStrategy,
|
||||||
WindowSurfaceType, find_popup_root_surface,
|
WindowSurfaceType, find_popup_root_surface,
|
||||||
|
|
@ -26,6 +30,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use smithay::{desktop::layer_map_for_output, input::tablet::TabletSeatTrait};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
|
|
@ -50,6 +55,7 @@ impl XdgShellHandler for State {
|
||||||
surface,
|
surface,
|
||||||
seat,
|
seat,
|
||||||
fullscreen: None,
|
fullscreen: None,
|
||||||
|
minimized: false,
|
||||||
maximized: false,
|
maximized: false,
|
||||||
sticky: false,
|
sticky: false,
|
||||||
})
|
})
|
||||||
|
|
@ -189,12 +195,17 @@ impl XdgShellHandler for State {
|
||||||
true,
|
true,
|
||||||
) {
|
) {
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(self, grab, serial);
|
GrabType::Touch => seat.get_touch().unwrap().set_grab(self, grab, serial),
|
||||||
} else {
|
GrabType::Pointer => seat
|
||||||
seat.get_pointer()
|
.get_pointer()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(self, grab, serial, focus)
|
.set_grab(self, grab, serial, focus),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(self, grab, InputTime::now(), serial, focus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -217,12 +228,17 @@ impl XdgShellHandler for State {
|
||||||
true,
|
true,
|
||||||
) {
|
) {
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
seat.get_touch().unwrap().set_grab(self, grab, serial)
|
GrabType::Touch => seat.get_touch().unwrap().set_grab(self, grab, serial),
|
||||||
} else {
|
GrabType::Pointer => seat
|
||||||
seat.get_pointer()
|
.get_pointer()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(self, grab, serial, focus)
|
.set_grab(self, grab, serial, focus),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(self, grab, InputTime::now(), serial, focus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,19 @@ use cosmic_protocols::corner_radius::v1::server::cosmic_corner_radius_toplevel_v
|
||||||
use cosmic_protocols::corner_radius::v1::server::{
|
use cosmic_protocols::corner_radius::v1::server::{
|
||||||
cosmic_corner_radius_manager_v1, cosmic_corner_radius_toplevel_v1,
|
cosmic_corner_radius_manager_v1, cosmic_corner_radius_toplevel_v1,
|
||||||
};
|
};
|
||||||
use smithay::desktop::utils::bbox_from_surface_tree;
|
use smithay::backend::renderer::buffer_dimensions;
|
||||||
|
use smithay::backend::renderer::utils::RendererSurfaceStateUserData;
|
||||||
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_popup::XdgPopup;
|
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_popup::XdgPopup;
|
||||||
use smithay::reexports::wayland_protocols_wlr::layer_shell::v1::server::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
|
use smithay::reexports::wayland_protocols_wlr::layer_shell::v1::server::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
|
||||||
use smithay::reexports::wayland_server::New;
|
use smithay::reexports::wayland_server::New;
|
||||||
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||||
use smithay::utils::{HookId, Logical, Point, Rectangle};
|
use smithay::utils::{HookId, Logical, Rectangle};
|
||||||
use smithay::wayland::compositor::Cacheable;
|
|
||||||
use smithay::wayland::compositor::add_pre_commit_hook;
|
use smithay::wayland::compositor::add_pre_commit_hook;
|
||||||
use smithay::wayland::compositor::with_states;
|
use smithay::wayland::compositor::with_states;
|
||||||
|
use smithay::wayland::compositor::{BufferAssignment, Cacheable, SurfaceAttributes};
|
||||||
use smithay::wayland::shell::wlr_layer::WlrLayerShellHandler;
|
use smithay::wayland::shell::wlr_layer::WlrLayerShellHandler;
|
||||||
use smithay::wayland::shell::xdg::{SurfaceCachedState, XdgShellSurfaceUserData};
|
use smithay::wayland::shell::xdg::{SurfaceCachedState, XdgShellSurfaceUserData};
|
||||||
|
use smithay::wayland::viewporter::ViewportCachedState;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
reexports::{
|
reexports::{
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel,
|
wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel,
|
||||||
|
|
@ -655,7 +657,6 @@ fn pad_rect(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layer_radius_hook<D: 'static>(_state: &mut D, _dh: &DisplayHandle, surface: &WlSurface) {
|
fn layer_radius_hook<D: 'static>(_state: &mut D, _dh: &DisplayHandle, surface: &WlSurface) {
|
||||||
let bbox = bbox_from_surface_tree(surface, Point::default());
|
|
||||||
with_states(surface, |surface_data| {
|
with_states(surface, |surface_data| {
|
||||||
let corners = *surface_data
|
let corners = *surface_data
|
||||||
.cached_state
|
.cached_state
|
||||||
|
|
@ -665,8 +666,40 @@ fn layer_radius_hook<D: 'static>(_state: &mut D, _dh: &DisplayHandle, surface: &
|
||||||
.cached_state
|
.cached_state
|
||||||
.get::<CacheablePadding>()
|
.get::<CacheablePadding>()
|
||||||
.pending();
|
.pending();
|
||||||
|
|
||||||
|
// The wl_surface size after this commit is:
|
||||||
|
// - viewport destination if set
|
||||||
|
// - else the logical size of the buffer that will be current attached now
|
||||||
|
// - else existing
|
||||||
|
let size = surface_data
|
||||||
|
.cached_state
|
||||||
|
.get::<ViewportCachedState>()
|
||||||
|
.pending()
|
||||||
|
.size()
|
||||||
|
.or_else(|| {
|
||||||
|
let mut guard = surface_data.cached_state.get::<SurfaceAttributes>();
|
||||||
|
let attrs = guard.pending();
|
||||||
|
match &attrs.buffer {
|
||||||
|
Some(BufferAssignment::NewBuffer(buffer)) => buffer_dimensions(buffer)
|
||||||
|
.map(|d| d.to_logical(attrs.buffer_scale, attrs.buffer_transform.into())),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
surface_data
|
||||||
|
.data_map
|
||||||
|
.get::<RendererSurfaceStateUserData>()
|
||||||
|
.and_then(|state| state.lock().unwrap().surface_size())
|
||||||
|
});
|
||||||
|
let Some(size) = size else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let empty = Padding::default();
|
let empty = Padding::default();
|
||||||
let Some(padded_box) = pad_rect(bbox, padding.0.as_ref().unwrap_or(&empty)) else {
|
let Some(padded_box) = pad_rect(
|
||||||
|
Rectangle::from_size(size),
|
||||||
|
padding.0.as_ref().unwrap_or(&empty),
|
||||||
|
) else {
|
||||||
if let Some(hook) = surface_data.data_map.get::<LayerHookId>() {
|
if let Some(hook) = surface_data.data_map.get::<LayerHookId>() {
|
||||||
let hook_ref = hook.lock().unwrap();
|
let hook_ref = hook.lock().unwrap();
|
||||||
if let Some((_, obj)) = hook_ref.as_ref()
|
if let Some((_, obj)) = hook_ref.as_ref()
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@ use smithay::{
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use wayland_backend::server::{ClientId, GlobalId};
|
use wayland_backend::server::{ClientId, GlobalId};
|
||||||
|
|
||||||
pub trait KeyboardLayoutHandler {
|
pub trait KeyboardLayoutHandler: SeatHandler {
|
||||||
fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState;
|
fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState;
|
||||||
|
/// Group has been changed through the protocol
|
||||||
|
fn group_changed(&mut self, keyboard: &KeyboardHandle<Self>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -57,6 +59,7 @@ impl KeyboardLayoutState {
|
||||||
let active_layout = handle.with_xkb_state(state, |context| {
|
let active_layout = handle.with_xkb_state(state, |context| {
|
||||||
context.xkb().lock().unwrap().active_layout()
|
context.xkb().lock().unwrap().active_layout()
|
||||||
});
|
});
|
||||||
|
state.group_changed(handle);
|
||||||
if *last_layout != Some(active_layout) {
|
if *last_layout != Some(active_layout) {
|
||||||
keyboard_layout.group(active_layout.0);
|
keyboard_layout.group(active_layout.0);
|
||||||
*last_layout = Some(active_layout);
|
*last_layout = Some(active_layout);
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,12 @@ where
|
||||||
handle.closed();
|
handle.closed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remove the foreign handle too, so new subscribers cannot
|
||||||
|
// discover a toplevel whose window has already been destroyed.
|
||||||
|
if let Some(handle) = state.foreign_handle.take() {
|
||||||
|
self.foreign_toplevel_list.remove_toplevel(&handle);
|
||||||
|
}
|
||||||
|
*state = Default::default();
|
||||||
dirty = true;
|
dirty = true;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ use std::{
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::cursor::{Cursor, load_cursor_env, load_cursor_theme},
|
backend::render::cursor::{Cursor, load_cursor_env, load_cursor_theme},
|
||||||
shell::{
|
shell::{
|
||||||
CosmicSurface, PendingWindow, Shell, focus::target::KeyboardFocusTarget, grabs::ReleaseMode,
|
CosmicSurface, PendingWindow, Shell,
|
||||||
|
focus::target::KeyboardFocusTarget,
|
||||||
|
grabs::{GrabType, ReleaseMode},
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
|
|
@ -20,7 +22,7 @@ use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::Fourcc,
|
allocator::Fourcc,
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
input::{ButtonState, KeyState, Keycode},
|
input::{ButtonState, InputTime, KeyState, Keycode},
|
||||||
renderer::{
|
renderer::{
|
||||||
Bind, Frame, Offscreen, Renderer,
|
Bind, Frame, Offscreen, Renderer,
|
||||||
element::{
|
element::{
|
||||||
|
|
@ -32,7 +34,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
desktop::space::SpaceElement,
|
desktop::space::SpaceElement,
|
||||||
input::{keyboard::ModifiersState, pointer::CursorIcon},
|
input::{keyboard::ModifiersState, pointer::CursorIcon, tablet::TabletSeatTrait},
|
||||||
reexports::{wayland_server::Client, x11rb::protocol::xproto::Window as X11Window},
|
reexports::{wayland_server::Client, x11rb::protocol::xproto::Window as X11Window},
|
||||||
utils::{
|
utils::{
|
||||||
Buffer as BufferCoords, Logical, Point, Rectangle, SERIAL_COUNTER, Serial, Size, Transform,
|
Buffer as BufferCoords, Logical, Point, Rectangle, SERIAL_COUNTER, Serial, Size, Transform,
|
||||||
|
|
@ -396,7 +398,7 @@ impl Common {
|
||||||
state: KeyState,
|
state: KeyState,
|
||||||
modifiers: ModifiersState,
|
modifiers: ModifiersState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
let config = self.config.cosmic_conf.xwayland_eavesdropping.keyboard;
|
let config = self.config.cosmic_conf.xwayland_eavesdropping.keyboard;
|
||||||
if config == EavesdroppingKeyboardMode::None {
|
if config == EavesdroppingKeyboardMode::None {
|
||||||
|
|
@ -458,7 +460,7 @@ impl Common {
|
||||||
|
|
||||||
tracing::trace!("Forwaring key {} {:?} to xwayland", code.raw() - 8, state);
|
tracing::trace!("Forwaring key {} {:?} to xwayland", code.raw() - 8, state);
|
||||||
for wl_keyboard in keyboard.client_keyboards(&xstate.client) {
|
for wl_keyboard in keyboard.client_keyboards(&xstate.client) {
|
||||||
wl_keyboard.key(serial.into(), time, code.raw() - 8, state.into());
|
wl_keyboard.key(serial.into(), time.millis(), code.raw() - 8, state.into());
|
||||||
if xstate.last_modifier_state != Some(modifiers) {
|
if xstate.last_modifier_state != Some(modifiers) {
|
||||||
xstate.last_modifier_state = Some(modifiers);
|
xstate.last_modifier_state = Some(modifiers);
|
||||||
wl_keyboard.modifiers(
|
wl_keyboard.modifiers(
|
||||||
|
|
@ -478,7 +480,7 @@ impl Common {
|
||||||
button: u32,
|
button: u32,
|
||||||
state: ButtonState,
|
state: ButtonState,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: InputTime,
|
||||||
) {
|
) {
|
||||||
if !self.config.cosmic_conf.xwayland_eavesdropping.pointer {
|
if !self.config.cosmic_conf.xwayland_eavesdropping.pointer {
|
||||||
return;
|
return;
|
||||||
|
|
@ -518,7 +520,7 @@ impl Common {
|
||||||
|
|
||||||
tracing::trace!("Forwaring ptr button {} {:?} to Xwayland", button, state);
|
tracing::trace!("Forwaring ptr button {} {:?} to Xwayland", button, state);
|
||||||
for wl_pointer in pointer.client_pointers(&xstate.client) {
|
for wl_pointer in pointer.client_pointers(&xstate.client) {
|
||||||
wl_pointer.button(serial.into(), time, button, state.into());
|
wl_pointer.button(serial.into(), time.millis(), button, state.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -808,6 +810,7 @@ impl XwmHandler for State {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let fullscreen = window.is_fullscreen().then(|| seat.active_output());
|
let fullscreen = window.is_fullscreen().then(|| seat.active_output());
|
||||||
|
let minimized = window.is_hidden();
|
||||||
let maximized = window.is_maximized();
|
let maximized = window.is_maximized();
|
||||||
if let Some(pending) = shell
|
if let Some(pending) = shell
|
||||||
.pending_windows
|
.pending_windows
|
||||||
|
|
@ -816,6 +819,7 @@ impl XwmHandler for State {
|
||||||
{
|
{
|
||||||
pending.seat = seat;
|
pending.seat = seat;
|
||||||
pending.fullscreen = fullscreen;
|
pending.fullscreen = fullscreen;
|
||||||
|
pending.minimized = minimized;
|
||||||
pending.maximized = maximized;
|
pending.maximized = maximized;
|
||||||
} else {
|
} else {
|
||||||
let surface = CosmicSurface::from(window);
|
let surface = CosmicSurface::from(window);
|
||||||
|
|
@ -823,6 +827,7 @@ impl XwmHandler for State {
|
||||||
surface,
|
surface,
|
||||||
seat,
|
seat,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
|
minimized,
|
||||||
maximized,
|
maximized,
|
||||||
sticky: false,
|
sticky: false,
|
||||||
})
|
})
|
||||||
|
|
@ -1042,17 +1047,29 @@ impl XwmHandler for State {
|
||||||
true,
|
true,
|
||||||
) {
|
) {
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
|
GrabType::Touch => {
|
||||||
seat.get_touch()
|
seat.get_touch()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(self, grab, SERIAL_COUNTER.next_serial())
|
.set_grab(self, grab, SERIAL_COUNTER.next_serial())
|
||||||
} else {
|
}
|
||||||
seat.get_pointer().unwrap().set_grab(
|
GrabType::Pointer => seat.get_pointer().unwrap().set_grab(
|
||||||
self,
|
self,
|
||||||
grab,
|
grab,
|
||||||
SERIAL_COUNTER.next_serial(),
|
SERIAL_COUNTER.next_serial(),
|
||||||
focus,
|
focus,
|
||||||
)
|
),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(
|
||||||
|
self,
|
||||||
|
grab,
|
||||||
|
InputTime::now(),
|
||||||
|
SERIAL_COUNTER.next_serial(),
|
||||||
|
focus,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1073,17 +1090,29 @@ impl XwmHandler for State {
|
||||||
true,
|
true,
|
||||||
) {
|
) {
|
||||||
std::mem::drop(shell);
|
std::mem::drop(shell);
|
||||||
if grab.is_touch_grab() {
|
match grab.grab_type() {
|
||||||
|
GrabType::Touch => {
|
||||||
seat.get_touch()
|
seat.get_touch()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_grab(self, grab, SERIAL_COUNTER.next_serial())
|
.set_grab(self, grab, SERIAL_COUNTER.next_serial())
|
||||||
} else {
|
}
|
||||||
seat.get_pointer().unwrap().set_grab(
|
GrabType::Pointer => seat.get_pointer().unwrap().set_grab(
|
||||||
self,
|
self,
|
||||||
grab,
|
grab,
|
||||||
SERIAL_COUNTER.next_serial(),
|
SERIAL_COUNTER.next_serial(),
|
||||||
focus,
|
focus,
|
||||||
)
|
),
|
||||||
|
GrabType::TabletTool => seat
|
||||||
|
.tablet_seat()
|
||||||
|
.get_tool(grab.tool().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.set_grab(
|
||||||
|
self,
|
||||||
|
grab,
|
||||||
|
InputTime::now(),
|
||||||
|
SERIAL_COUNTER.next_serial(),
|
||||||
|
focus,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue