2021-12-21 18:57:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
|
2022-07-08 19:15:56 +02:00
|
|
|
use crate::{
|
2023-07-31 17:36:32 +02:00
|
|
|
backend::render::cursor::CursorState,
|
2023-12-21 13:32:37 -08:00
|
|
|
config::{xkb_config_to_wl, Action, Config, KeyModifiers, KeyPattern},
|
2022-11-10 18:42:11 +01:00
|
|
|
shell::{
|
|
|
|
|
focus::{target::PointerFocusTarget, FocusDirection},
|
2023-12-07 19:53:41 +00:00
|
|
|
grabs::{ResizeEdge, SeatMenuGrabState, SeatMoveGrabState},
|
2023-10-23 21:09:38 +02:00
|
|
|
layout::{
|
|
|
|
|
floating::ResizeGrabMarker,
|
|
|
|
|
tiling::{SwapWindowGrab, TilingLayout},
|
|
|
|
|
},
|
2023-12-20 20:24:13 +00:00
|
|
|
Direction, FocusResult, MoveResult, OverviewMode, ResizeDirection, ResizeMode, Trigger,
|
2023-07-31 17:36:32 +02:00
|
|
|
},
|
2023-11-14 13:13:42 -08:00
|
|
|
state::Common,
|
2022-07-08 19:15:56 +02:00
|
|
|
utils::prelude::*,
|
2023-11-07 18:46:25 +01:00
|
|
|
wayland::{
|
|
|
|
|
handlers::{screencopy::ScreencopySessions, xdg_activation::ActivationContext},
|
|
|
|
|
protocols::screencopy::Session,
|
|
|
|
|
},
|
2022-07-08 19:15:56 +02:00
|
|
|
};
|
2023-07-06 18:20:10 +02:00
|
|
|
use calloop::{timer::Timer, RegistrationToken};
|
2024-02-08 14:25:18 -05:00
|
|
|
use cosmic_comp_config::{workspace::WorkspaceLayout, TileBehavior};
|
|
|
|
|
use cosmic_config::ConfigSet;
|
2022-11-03 18:51:27 +01:00
|
|
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
2021-12-21 18:57:09 +01:00
|
|
|
use smithay::{
|
2023-01-27 19:51:23 +01:00
|
|
|
backend::input::{
|
2023-11-07 13:56:31 -08:00
|
|
|
AbsolutePositionEvent, Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent,
|
|
|
|
|
GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend,
|
2023-12-28 13:36:59 -08:00
|
|
|
InputEvent, KeyState, PointerAxisEvent, ProximityState, TabletToolButtonEvent,
|
|
|
|
|
TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState,
|
|
|
|
|
TouchEvent,
|
2022-08-31 13:01:23 +02:00
|
|
|
},
|
2023-01-23 20:32:37 +01:00
|
|
|
desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType},
|
2022-08-31 13:01:23 +02:00
|
|
|
input::{
|
2023-09-29 21:33:16 +02:00
|
|
|
keyboard::{FilterResult, KeysymHandle, XkbConfig},
|
2023-09-05 13:41:21 -07:00
|
|
|
pointer::{
|
|
|
|
|
AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent,
|
|
|
|
|
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
|
|
|
|
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
|
|
|
|
|
RelativeMotionEvent,
|
|
|
|
|
},
|
2022-08-31 13:01:23 +02:00
|
|
|
Seat, SeatState,
|
2021-12-21 18:57:09 +01:00
|
|
|
},
|
2022-09-09 20:00:00 -07:00
|
|
|
output::Output,
|
2023-12-28 13:36:59 -08:00
|
|
|
reexports::{input::Device as InputDevice, wayland_server::DisplayHandle},
|
2023-10-25 19:41:30 +02:00
|
|
|
utils::{Point, Serial, SERIAL_COUNTER},
|
2022-09-09 20:17:40 -07:00
|
|
|
wayland::{
|
2023-09-13 20:52:10 -07:00
|
|
|
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat,
|
|
|
|
|
pointer_constraints::{with_pointer_constraint, PointerConstraint},
|
|
|
|
|
seat::WaylandFocus,
|
2022-09-09 20:17:40 -07:00
|
|
|
shell::wlr_layer::Layer as WlrLayer,
|
2023-12-28 13:36:59 -08:00
|
|
|
tablet_manager::{TabletDescriptor, TabletSeatTrait},
|
2022-09-09 20:17:40 -07:00
|
|
|
},
|
2021-12-21 18:57:09 +01:00
|
|
|
};
|
2023-02-24 17:41:52 +01:00
|
|
|
#[cfg(not(feature = "debug"))]
|
|
|
|
|
use tracing::info;
|
|
|
|
|
use tracing::{error, trace, warn};
|
2023-09-29 21:33:16 +02:00
|
|
|
use xkbcommon::xkb::{Keycode, Keysym};
|
2022-08-31 13:01:23 +02:00
|
|
|
|
2023-07-06 18:20:10 +02:00
|
|
|
use std::{
|
2023-09-01 12:33:55 -07:00
|
|
|
any::Any,
|
2023-07-06 18:20:10 +02:00
|
|
|
cell::RefCell,
|
|
|
|
|
collections::HashMap,
|
2024-02-08 14:25:18 -05:00
|
|
|
thread,
|
2023-07-06 18:20:10 +02:00
|
|
|
time::{Duration, Instant},
|
|
|
|
|
};
|
2021-12-21 18:57:09 +01:00
|
|
|
|
2022-07-08 14:00:13 +02:00
|
|
|
crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS);
|
|
|
|
|
|
|
|
|
|
#[repr(transparent)]
|
|
|
|
|
pub struct SeatId(pub usize);
|
2021-12-21 18:57:09 +01:00
|
|
|
pub struct ActiveOutput(pub RefCell<Output>);
|
2022-07-08 14:25:26 +02:00
|
|
|
#[derive(Default)]
|
2023-09-29 21:33:16 +02:00
|
|
|
pub struct SupressedKeys(RefCell<Vec<(Keycode, Option<RegistrationToken>)>>);
|
2023-09-30 08:42:42 -05:00
|
|
|
#[derive(Default, Debug)]
|
|
|
|
|
pub struct ModifiersShortcutQueue(RefCell<Option<KeyPattern>>);
|
2022-07-08 14:25:26 +02:00
|
|
|
#[derive(Default)]
|
2021-12-22 20:14:09 +01:00
|
|
|
pub struct Devices(RefCell<HashMap<String, Vec<DeviceCapability>>>);
|
|
|
|
|
|
2022-07-08 14:00:13 +02:00
|
|
|
impl Default for SeatId {
|
|
|
|
|
fn default() -> SeatId {
|
|
|
|
|
SeatId(next_seat_id())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Drop for SeatId {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
SEAT_IDS.lock().unwrap().remove(&self.0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-11 17:22:23 +01:00
|
|
|
impl SupressedKeys {
|
2023-07-06 18:20:10 +02:00
|
|
|
fn add(&self, keysym: &KeysymHandle, token: impl Into<Option<RegistrationToken>>) {
|
|
|
|
|
self.0.borrow_mut().push((keysym.raw_code(), token.into()));
|
2022-01-11 17:22:23 +01:00
|
|
|
}
|
|
|
|
|
|
2023-07-06 18:20:10 +02:00
|
|
|
fn filter(&self, keysym: &KeysymHandle) -> Option<Vec<RegistrationToken>> {
|
2022-01-11 17:22:23 +01:00
|
|
|
let mut keys = self.0.borrow_mut();
|
2023-07-06 18:20:10 +02:00
|
|
|
let (removed, remaining) = keys
|
|
|
|
|
.drain(..)
|
|
|
|
|
.partition(|(key, _)| *key == keysym.raw_code());
|
|
|
|
|
*keys = remaining;
|
|
|
|
|
|
|
|
|
|
let removed = removed
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(_, token)| token)
|
|
|
|
|
.flatten()
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
if removed.is_empty() {
|
|
|
|
|
None
|
2022-01-11 17:22:23 +01:00
|
|
|
} else {
|
2023-07-06 18:20:10 +02:00
|
|
|
Some(removed)
|
2022-01-11 17:22:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-30 08:42:42 -05:00
|
|
|
impl ModifiersShortcutQueue {
|
|
|
|
|
pub fn set(&self, binding: KeyPattern) {
|
|
|
|
|
let mut set = self.0.borrow_mut();
|
|
|
|
|
*set = Some(binding);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn take(&self, binding: &KeyPattern) -> bool {
|
|
|
|
|
let mut set = self.0.borrow_mut();
|
|
|
|
|
if set.is_some() && set.as_ref().unwrap() == binding {
|
|
|
|
|
*set = None;
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn clear(&self) {
|
|
|
|
|
let mut set = self.0.borrow_mut();
|
|
|
|
|
*set = None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 20:14:09 +01:00
|
|
|
impl Devices {
|
|
|
|
|
fn add_device<D: Device>(&self, device: &D) -> Vec<DeviceCapability> {
|
|
|
|
|
let id = device.id();
|
|
|
|
|
let mut map = self.0.borrow_mut();
|
2023-12-28 13:36:59 -08:00
|
|
|
let caps = [
|
|
|
|
|
DeviceCapability::Keyboard,
|
|
|
|
|
DeviceCapability::Pointer,
|
|
|
|
|
DeviceCapability::TabletTool,
|
|
|
|
|
]
|
|
|
|
|
.iter()
|
|
|
|
|
.cloned()
|
|
|
|
|
.filter(|c| device.has_capability(*c))
|
|
|
|
|
.collect::<Vec<_>>();
|
2021-12-22 20:14:09 +01:00
|
|
|
let new_caps = caps
|
|
|
|
|
.iter()
|
|
|
|
|
.cloned()
|
|
|
|
|
.filter(|c| map.values().flatten().all(|has| *c != *has))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
map.insert(id, caps);
|
|
|
|
|
new_caps
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn has_device<D: Device>(&self, device: &D) -> bool {
|
|
|
|
|
self.0.borrow().contains_key(&device.id())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn remove_device<D: Device>(&self, device: &D) -> Vec<DeviceCapability> {
|
|
|
|
|
let id = device.id();
|
|
|
|
|
let mut map = self.0.borrow_mut();
|
|
|
|
|
map.remove(&id)
|
|
|
|
|
.unwrap_or(Vec::new())
|
|
|
|
|
.into_iter()
|
|
|
|
|
.filter(|c| map.values().flatten().all(|has| *c != *has))
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 13:01:23 +02:00
|
|
|
pub fn add_seat(
|
|
|
|
|
dh: &DisplayHandle,
|
|
|
|
|
seat_state: &mut SeatState<State>,
|
2022-09-28 12:01:29 +02:00
|
|
|
output: &Output,
|
2022-08-31 13:01:23 +02:00
|
|
|
config: &Config,
|
|
|
|
|
name: String,
|
|
|
|
|
) -> Seat<State> {
|
2023-02-24 17:41:52 +01:00
|
|
|
let mut seat = seat_state.new_wl_seat(dh, name);
|
2021-12-22 20:14:09 +01:00
|
|
|
let userdata = seat.user_data();
|
2022-07-08 14:00:13 +02:00
|
|
|
userdata.insert_if_missing(SeatId::default);
|
2022-07-08 14:25:26 +02:00
|
|
|
userdata.insert_if_missing(Devices::default);
|
|
|
|
|
userdata.insert_if_missing(SupressedKeys::default);
|
2023-09-30 08:42:42 -05:00
|
|
|
userdata.insert_if_missing(ModifiersShortcutQueue::default);
|
2022-10-26 15:26:07 +02:00
|
|
|
userdata.insert_if_missing(SeatMoveGrabState::default);
|
2023-12-07 19:53:41 +00:00
|
|
|
userdata.insert_if_missing(SeatMenuGrabState::default);
|
2023-07-11 16:33:23 +02:00
|
|
|
userdata.insert_if_missing(CursorState::default);
|
2022-09-28 12:01:29 +02:00
|
|
|
userdata.insert_if_missing(|| ActiveOutput(RefCell::new(output.clone())));
|
2023-10-10 13:28:30 -07:00
|
|
|
userdata.insert_if_missing(|| RefCell::new(CursorImageStatus::default_named()));
|
2022-07-15 14:21:20 +02:00
|
|
|
|
|
|
|
|
// A lot of clients bind keyboard and pointer unconditionally once on launch..
|
|
|
|
|
// Initial clients might race the compositor on adding periheral and
|
|
|
|
|
// end up in a state, where they are not able to receive input.
|
|
|
|
|
// Additionally a lot of clients don't handle keyboards/pointer objects being
|
|
|
|
|
// removed very well either and we don't want to crash applications, because the
|
|
|
|
|
// user is replugging their keyboard or mouse.
|
|
|
|
|
//
|
|
|
|
|
// So instead of doing the right thing (and initialize these capabilities as matching
|
|
|
|
|
// devices appear), we have to surrender to reality and just always expose a keyboard and pointer.
|
2022-07-29 14:23:23 +02:00
|
|
|
let conf = config.xkb_config();
|
2024-01-23 09:23:10 -08:00
|
|
|
if let Err(err) = seat.add_keyboard(xkb_config_to_wl(&conf), 600, 25) {
|
2023-02-24 17:41:52 +01:00
|
|
|
warn!(
|
|
|
|
|
?err,
|
|
|
|
|
"Failed to load provided xkb config. Trying default...",
|
2022-09-23 18:22:37 +02:00
|
|
|
);
|
2024-01-23 09:23:10 -08:00
|
|
|
seat.add_keyboard(XkbConfig::default(), 600, 25)
|
2022-09-23 18:22:37 +02:00
|
|
|
.expect("Failed to load xkb configuration files");
|
|
|
|
|
}
|
|
|
|
|
seat.add_pointer();
|
2023-11-07 13:56:31 -08:00
|
|
|
seat.add_touch();
|
2022-07-15 14:21:20 +02:00
|
|
|
|
2021-12-21 18:57:09 +01:00
|
|
|
seat
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 12:35:55 +02:00
|
|
|
impl State {
|
2023-07-06 18:20:10 +02:00
|
|
|
pub fn process_input_event<B: InputBackend>(
|
|
|
|
|
&mut self,
|
|
|
|
|
event: InputEvent<B>,
|
|
|
|
|
needs_key_repetition: bool,
|
2023-09-01 12:33:55 -07:00
|
|
|
) where
|
2023-12-28 13:36:59 -08:00
|
|
|
<B as InputBackend>::Device: 'static,
|
2023-09-01 12:33:55 -07:00
|
|
|
{
|
2021-12-22 20:14:09 +01:00
|
|
|
use smithay::backend::input::Event;
|
|
|
|
|
match event {
|
|
|
|
|
InputEvent::DeviceAdded { device } => {
|
2022-09-28 12:01:29 +02:00
|
|
|
let seat = &mut self.common.last_active_seat();
|
2021-12-22 20:14:09 +01:00
|
|
|
let userdata = seat.user_data();
|
|
|
|
|
let devices = userdata.get::<Devices>().unwrap();
|
|
|
|
|
for cap in devices.add_device(&device) {
|
|
|
|
|
match cap {
|
2023-12-28 13:36:59 -08:00
|
|
|
DeviceCapability::TabletTool => {
|
|
|
|
|
seat.tablet_seat().add_tablet::<Self>(
|
|
|
|
|
&self.common.display_handle,
|
|
|
|
|
&TabletDescriptor::from(&device),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
// TODO: Handle touch
|
2021-12-22 20:14:09 +01:00
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-06 18:48:52 +01:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
{
|
|
|
|
|
self.common.egui.state.handle_device_added(&device);
|
|
|
|
|
}
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
InputEvent::DeviceRemoved { device } => {
|
2022-09-28 12:01:29 +02:00
|
|
|
for seat in &mut self.common.seats() {
|
2021-12-22 20:14:09 +01:00
|
|
|
let userdata = seat.user_data();
|
|
|
|
|
let devices = userdata.get::<Devices>().unwrap();
|
|
|
|
|
if devices.has_device(&device) {
|
|
|
|
|
for cap in devices.remove_device(&device) {
|
|
|
|
|
match cap {
|
2023-12-28 13:36:59 -08:00
|
|
|
DeviceCapability::TabletTool => {
|
|
|
|
|
seat.tablet_seat()
|
|
|
|
|
.remove_tablet(&TabletDescriptor::from(&device));
|
|
|
|
|
}
|
|
|
|
|
// TODO: Handle touch
|
2022-08-30 13:28:36 +02:00
|
|
|
_ => {}
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-06 18:48:52 +01:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
{
|
|
|
|
|
self.common.egui.state.handle_device_removed(&device);
|
|
|
|
|
}
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
InputEvent::Keyboard { event, .. } => {
|
|
|
|
|
use smithay::backend::input::KeyboardKeyEvent;
|
|
|
|
|
|
2023-07-06 18:20:10 +02:00
|
|
|
let loop_handle = self.common.event_loop_handle.clone();
|
|
|
|
|
|
2023-09-05 13:41:21 -07:00
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
|
|
|
|
let userdata = seat.user_data();
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
let current_output = seat.active_output();
|
2022-09-09 20:17:40 -07:00
|
|
|
let workspace = self.common.shell.active_space_mut(¤t_output);
|
|
|
|
|
let shortcuts_inhibited = workspace
|
2022-09-28 12:01:29 +02:00
|
|
|
.focus_stack
|
2023-09-05 13:41:21 -07:00
|
|
|
.get(&seat)
|
2022-09-09 20:17:40 -07:00
|
|
|
.last()
|
|
|
|
|
.and_then(|window| {
|
2022-09-28 12:01:29 +02:00
|
|
|
window.wl_surface().and_then(|surface| {
|
|
|
|
|
seat.keyboard_shortcuts_inhibitor_for_surface(&surface)
|
|
|
|
|
})
|
2022-09-09 20:17:40 -07:00
|
|
|
})
|
|
|
|
|
.map(|inhibitor| inhibitor.is_active())
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
|
2023-09-05 13:41:21 -07:00
|
|
|
let keycode = event.key_code();
|
|
|
|
|
let state = event.state();
|
|
|
|
|
trace!(?keycode, ?state, "key");
|
2021-12-22 20:14:09 +01:00
|
|
|
|
2023-09-05 13:41:21 -07:00
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let time = Event::time_msec(&event);
|
2023-08-11 18:15:22 +02:00
|
|
|
let keyboard = seat.get_keyboard().unwrap();
|
2023-12-13 16:36:49 +00:00
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
let is_grabbed = keyboard.is_grabbed() || pointer.is_grabbed();
|
2023-08-11 18:15:22 +02:00
|
|
|
let current_focus = keyboard.current_focus();
|
|
|
|
|
if let Some((action, pattern)) = keyboard
|
2022-08-31 13:01:23 +02:00
|
|
|
.input(
|
|
|
|
|
self,
|
|
|
|
|
keycode,
|
|
|
|
|
state,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
|data, modifiers, handle| {
|
2023-08-11 18:15:22 +02:00
|
|
|
// Leave move overview mode, if any modifier was released
|
|
|
|
|
if let OverviewMode::Started(Trigger::KeyboardMove(action_modifiers), _) =
|
|
|
|
|
data.common.shell.overview_mode().0
|
2023-05-19 19:44:57 +02:00
|
|
|
{
|
2023-05-26 11:47:45 +02:00
|
|
|
if (action_modifiers.ctrl && !modifiers.ctrl)
|
|
|
|
|
|| (action_modifiers.alt && !modifiers.alt)
|
|
|
|
|
|| (action_modifiers.logo && !modifiers.logo)
|
|
|
|
|
|| (action_modifiers.shift && !modifiers.shift)
|
2023-05-19 19:44:57 +02:00
|
|
|
{
|
2023-08-11 18:15:22 +02:00
|
|
|
data.common.shell.set_overview_mode(None, data.common.event_loop_handle.clone());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Leave swap overview mode, if any key was released
|
|
|
|
|
if let OverviewMode::Started(Trigger::KeyboardSwap(action_pattern, old_descriptor), _) =
|
|
|
|
|
data.common.shell.overview_mode().0
|
|
|
|
|
{
|
|
|
|
|
if (action_pattern.modifiers.ctrl && !modifiers.ctrl)
|
|
|
|
|
|| (action_pattern.modifiers.alt && !modifiers.alt)
|
|
|
|
|
|| (action_pattern.modifiers.logo && !modifiers.logo)
|
|
|
|
|
|| (action_pattern.modifiers.shift && !modifiers.shift)
|
2023-09-30 08:42:42 -05:00
|
|
|
|| (action_pattern.key.is_some() && handle.raw_syms().contains(&action_pattern.key.unwrap()) && state == KeyState::Released)
|
2023-08-11 18:15:22 +02:00
|
|
|
{
|
|
|
|
|
data.common.shell.set_overview_mode(None, data.common.event_loop_handle.clone());
|
|
|
|
|
|
|
|
|
|
if let Some(focus) = current_focus {
|
|
|
|
|
if let Some(new_descriptor) = data.common.shell.workspaces.active(¤t_output).1.node_desc(focus) {
|
|
|
|
|
let mut spaces = data.common.shell.workspaces.spaces_mut();
|
|
|
|
|
if old_descriptor.handle != new_descriptor.handle {
|
|
|
|
|
let (mut old_w, mut other_w) = spaces.partition::<Vec<_>, _>(|w| w.handle == old_descriptor.handle);
|
2023-09-11 21:11:34 +02:00
|
|
|
if let Some(old_workspace) = old_w.get_mut(0) {
|
|
|
|
|
if let Some(new_workspace) = other_w.iter_mut().find(|w| w.handle == new_descriptor.handle) {
|
|
|
|
|
if let Some(focus) = TilingLayout::swap_trees(&mut old_workspace.tiling_layer, Some(&mut new_workspace.tiling_layer), &old_descriptor, &new_descriptor, &mut data.common.shell.toplevel_info_state) {
|
2023-08-11 18:15:22 +02:00
|
|
|
let seat = seat.clone();
|
2023-09-29 21:33:16 +02:00
|
|
|
data.common.event_loop_handle.insert_idle(move |state| {
|
|
|
|
|
Common::set_focus(state, Some(&focus), &seat, None);
|
2023-08-11 18:15:22 +02:00
|
|
|
});
|
|
|
|
|
}
|
2023-09-11 21:11:34 +02:00
|
|
|
old_workspace.refresh_focus_stack();
|
|
|
|
|
new_workspace.refresh_focus_stack();
|
2023-08-11 18:15:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2023-09-11 21:11:34 +02:00
|
|
|
if let Some(workspace) = spaces.find(|w| w.handle == new_descriptor.handle) {
|
|
|
|
|
if let Some(focus) = TilingLayout::swap_trees(&mut workspace.tiling_layer, None, &old_descriptor, &new_descriptor, &mut data.common.shell.toplevel_info_state) {
|
2023-08-11 18:15:22 +02:00
|
|
|
std::mem::drop(spaces);
|
|
|
|
|
let seat = seat.clone();
|
2023-09-29 21:33:16 +02:00
|
|
|
data.common.event_loop_handle.insert_idle(move |state| {
|
|
|
|
|
Common::set_focus(state, Some(&focus), &seat, None);
|
2023-08-11 18:15:22 +02:00
|
|
|
});
|
|
|
|
|
}
|
2023-09-11 21:11:34 +02:00
|
|
|
workspace.refresh_focus_stack();
|
2023-08-11 18:15:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-11 21:12:52 +02:00
|
|
|
} else {
|
|
|
|
|
let new_workspace = data.common.shell.workspaces.active(¤t_output).1.handle;
|
|
|
|
|
if new_workspace != old_descriptor.handle {
|
|
|
|
|
let spaces = data.common.shell.workspaces.spaces_mut();
|
|
|
|
|
let (mut old_w, mut other_w) = spaces.partition::<Vec<_>, _>(|w| w.handle == old_descriptor.handle);
|
|
|
|
|
if let Some(old_workspace) = old_w.get_mut(0) {
|
|
|
|
|
if let Some(new_workspace) = other_w.iter_mut().find(|w| w.handle == new_workspace) {
|
|
|
|
|
if new_workspace.tiling_layer.windows().next().is_none() {
|
2023-10-25 19:40:26 +02:00
|
|
|
if let Some(focus) = TilingLayout::move_tree(&mut old_workspace.tiling_layer, &mut new_workspace.tiling_layer, &new_workspace.handle, &seat, new_workspace.focus_stack.get(&seat).iter(), old_descriptor, &mut data.common.shell.toplevel_info_state) {
|
2023-09-11 21:12:52 +02:00
|
|
|
let seat = seat.clone();
|
2023-09-29 21:33:16 +02:00
|
|
|
data.common.event_loop_handle.insert_idle(move |state| {
|
|
|
|
|
Common::set_focus(state, Some(&focus), &seat, None);
|
2023-09-11 21:12:52 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
old_workspace.refresh_focus_stack();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-11 18:15:22 +02:00
|
|
|
}
|
2023-05-19 19:44:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 21:29:39 +02:00
|
|
|
// Leave or update resize mode, if modifiers changed or initial key was released
|
2023-07-05 23:57:38 +02:00
|
|
|
if let (ResizeMode::Started(action_pattern, _, _), _) =
|
2023-06-28 21:29:39 +02:00
|
|
|
data.common.shell.resize_mode()
|
|
|
|
|
{
|
2023-09-30 08:42:42 -05:00
|
|
|
if action_pattern.key.is_some() && state == KeyState::Released
|
|
|
|
|
&& handle.raw_syms().contains(&action_pattern.key.unwrap())
|
2023-06-28 21:29:39 +02:00
|
|
|
{
|
2023-07-05 23:57:38 +02:00
|
|
|
data.common.shell.set_resize_mode(None, &data.common.config, data.common.event_loop_handle.clone());
|
2023-06-28 21:29:39 +02:00
|
|
|
} else if action_pattern.modifiers != *modifiers {
|
|
|
|
|
let mut new_pattern = action_pattern.clone();
|
|
|
|
|
new_pattern.modifiers = modifiers.clone().into();
|
|
|
|
|
let enabled = data
|
|
|
|
|
.common
|
|
|
|
|
.config
|
|
|
|
|
.static_conf
|
|
|
|
|
.key_bindings
|
|
|
|
|
.iter()
|
|
|
|
|
.find_map(move |(binding, action)| {
|
|
|
|
|
if binding == &new_pattern
|
|
|
|
|
&& matches!(action, Action::Resizing(_))
|
|
|
|
|
{
|
|
|
|
|
let Action::Resizing(direction) = action else { unreachable!() };
|
|
|
|
|
Some((new_pattern.clone(), *direction))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-07-05 23:57:38 +02:00
|
|
|
data.common.shell.set_resize_mode(enabled, &data.common.config, data.common.event_loop_handle.clone());
|
2023-06-28 21:29:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Special case resizing with regards to arrow keys
|
2023-07-05 23:57:38 +02:00
|
|
|
if let (ResizeMode::Started(_, _, direction), _) =
|
2023-06-28 21:29:39 +02:00
|
|
|
data.common.shell.resize_mode()
|
|
|
|
|
{
|
2023-07-05 23:57:38 +02:00
|
|
|
let resize_edge = match handle.modified_sym() {
|
2023-09-29 21:33:16 +02:00
|
|
|
Keysym::Left | Keysym::h | Keysym::H => Some(ResizeEdge::LEFT),
|
|
|
|
|
Keysym::Down | Keysym::j | Keysym::J => Some(ResizeEdge::BOTTOM),
|
|
|
|
|
Keysym::Up | Keysym::k | Keysym::K => Some(ResizeEdge::TOP),
|
|
|
|
|
Keysym::Right | Keysym::l | Keysym::L => Some(ResizeEdge::RIGHT),
|
2023-07-05 23:57:38 +02:00
|
|
|
_ => None,
|
|
|
|
|
};
|
2023-06-28 21:29:39 +02:00
|
|
|
|
2023-07-05 23:57:38 +02:00
|
|
|
if let Some(mut edge) = resize_edge {
|
|
|
|
|
if direction == ResizeDirection::Inwards {
|
|
|
|
|
edge.flip_direction();
|
2023-06-28 21:29:39 +02:00
|
|
|
}
|
2023-07-06 18:20:10 +02:00
|
|
|
let action = Action::_ResizingInternal(direction, edge, state);
|
|
|
|
|
let key_pattern = KeyPattern {
|
|
|
|
|
modifiers: modifiers.clone().into(),
|
2023-09-29 21:33:16 +02:00
|
|
|
key: Some(Keysym::new(handle.raw_code().raw())),
|
2023-07-06 18:20:10 +02:00
|
|
|
};
|
2023-07-31 17:36:32 +02:00
|
|
|
|
2023-07-06 18:20:10 +02:00
|
|
|
if state == KeyState::Released {
|
|
|
|
|
if let Some(tokens) = userdata.get::<SupressedKeys>().unwrap().filter(&handle) {
|
|
|
|
|
for token in tokens {
|
|
|
|
|
loop_handle.remove(token);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
let token = if needs_key_repetition {
|
|
|
|
|
let seat_clone = seat.clone();
|
|
|
|
|
let action_clone = action.clone();
|
|
|
|
|
let key_pattern_clone = key_pattern.clone();
|
|
|
|
|
let start = Instant::now();
|
2023-09-29 21:33:16 +02:00
|
|
|
loop_handle.insert_source(Timer::from_duration(Duration::from_millis(200)), move |current, _, state| {
|
2023-07-06 18:20:10 +02:00
|
|
|
let duration = current.duration_since(start).as_millis();
|
2023-11-22 17:42:11 +01:00
|
|
|
state.handle_action(action_clone.clone(), &seat_clone, serial, time.overflowing_add(duration as u32).0, key_pattern_clone.clone(), None, true);
|
2023-07-06 18:20:10 +02:00
|
|
|
calloop::timer::TimeoutAction::ToDuration(Duration::from_millis(25))
|
|
|
|
|
}).ok()
|
|
|
|
|
} else { None };
|
2023-07-31 17:36:32 +02:00
|
|
|
|
2023-09-30 08:42:42 -05:00
|
|
|
userdata
|
2023-07-06 18:20:10 +02:00
|
|
|
.get::<SupressedKeys>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.add(&handle, token);
|
|
|
|
|
}
|
2023-07-05 23:57:38 +02:00
|
|
|
return FilterResult::Intercept(Some((
|
2023-07-06 18:20:10 +02:00
|
|
|
action,
|
|
|
|
|
key_pattern
|
2023-07-05 23:57:38 +02:00
|
|
|
)));
|
2023-06-28 21:29:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-13 16:36:49 +00:00
|
|
|
// cancel grabs
|
|
|
|
|
if is_grabbed
|
|
|
|
|
&& handle.modified_sym() == Keysym::Escape
|
|
|
|
|
&& state == KeyState::Pressed
|
2024-01-17 13:12:46 -08:00
|
|
|
&& !modifiers.alt
|
2023-12-13 16:36:49 +00:00
|
|
|
&& !modifiers.ctrl
|
|
|
|
|
&& !modifiers.logo
|
|
|
|
|
&& !modifiers.shift
|
|
|
|
|
{
|
|
|
|
|
userdata
|
|
|
|
|
.get::<SupressedKeys>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.add(&handle, None);
|
|
|
|
|
return FilterResult::Intercept(Some((
|
|
|
|
|
Action::Escape,
|
|
|
|
|
KeyPattern {
|
|
|
|
|
modifiers: KeyModifiers::default(),
|
|
|
|
|
key: Some(Keysym::Escape),
|
|
|
|
|
}
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 21:29:39 +02:00
|
|
|
// Skip released events for initially surpressed keys
|
2023-07-06 18:20:10 +02:00
|
|
|
if state == KeyState::Released {
|
|
|
|
|
if let Some(tokens) = userdata.get::<SupressedKeys>().unwrap().filter(&handle) {
|
|
|
|
|
for token in tokens {
|
|
|
|
|
loop_handle.remove(token);
|
|
|
|
|
}
|
|
|
|
|
return FilterResult::Intercept(None);
|
|
|
|
|
}
|
2022-01-11 17:22:23 +01:00
|
|
|
}
|
2022-04-25 12:35:55 +02:00
|
|
|
|
2023-06-28 21:29:39 +02:00
|
|
|
// Pass keys to debug interface, if it has focus
|
2023-03-06 18:48:52 +01:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
{
|
2023-09-05 13:41:21 -07:00
|
|
|
if data.common.seats().position(|x| x == &seat).unwrap() == 0
|
2023-03-06 18:48:52 +01:00
|
|
|
&& data.common.egui.active
|
|
|
|
|
{
|
|
|
|
|
if data.common.egui.state.wants_keyboard() {
|
|
|
|
|
data.common.egui.state.handle_keyboard(
|
|
|
|
|
&handle,
|
|
|
|
|
state == KeyState::Pressed,
|
|
|
|
|
modifiers.clone(),
|
|
|
|
|
);
|
|
|
|
|
userdata
|
|
|
|
|
.get::<SupressedKeys>()
|
|
|
|
|
.unwrap()
|
2023-08-01 14:26:51 -07:00
|
|
|
.add(&handle, None);
|
2023-03-06 18:48:52 +01:00
|
|
|
return FilterResult::Intercept(None);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 21:29:39 +02:00
|
|
|
// Handle VT switches
|
2022-03-28 23:45:30 +02:00
|
|
|
if state == KeyState::Pressed
|
2023-09-29 21:33:16 +02:00
|
|
|
&& (Keysym::XF86_Switch_VT_1.raw() ..= Keysym::XF86_Switch_VT_12.raw())
|
|
|
|
|
.contains(&handle.modified_sym().raw())
|
2022-03-28 23:45:30 +02:00
|
|
|
{
|
2022-08-31 13:01:23 +02:00
|
|
|
if let Err(err) = data.backend.kms().switch_vt(
|
2023-09-29 21:33:16 +02:00
|
|
|
(handle.modified_sym().raw() - Keysym::XF86_Switch_VT_1.raw()
|
2022-08-31 13:01:23 +02:00
|
|
|
+ 1)
|
|
|
|
|
as i32,
|
|
|
|
|
) {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(?err, "Failed switching virtual terminal.");
|
2022-08-31 13:01:23 +02:00
|
|
|
}
|
2023-07-06 18:20:10 +02:00
|
|
|
userdata.get::<SupressedKeys>().unwrap().add(&handle, None);
|
2022-08-31 13:01:23 +02:00
|
|
|
return FilterResult::Intercept(None);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 21:29:39 +02:00
|
|
|
// handle the rest of the global shortcuts
|
2023-09-30 08:42:42 -05:00
|
|
|
let mut can_clear_modifiers_shortcut = true;
|
2022-09-09 20:17:40 -07:00
|
|
|
if !shortcuts_inhibited {
|
2023-09-30 08:42:42 -05:00
|
|
|
let modifiers_queue = userdata.get::<ModifiersShortcutQueue>().unwrap();
|
2022-09-09 20:17:40 -07:00
|
|
|
for (binding, action) in
|
|
|
|
|
data.common.config.static_conf.key_bindings.iter()
|
2022-08-31 13:01:23 +02:00
|
|
|
{
|
2023-09-30 08:42:42 -05:00
|
|
|
let modifiers_bypass = binding.key.is_none()
|
|
|
|
|
&& state == KeyState::Released
|
|
|
|
|
&& binding.modifiers != *modifiers
|
|
|
|
|
&& modifiers_queue.take(binding);
|
|
|
|
|
|
|
|
|
|
if !modifiers_bypass && binding.key.is_none() && state == KeyState::Pressed && binding.modifiers == *modifiers {
|
|
|
|
|
modifiers_queue.set(binding.clone());
|
|
|
|
|
can_clear_modifiers_shortcut = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
binding.key.is_some()
|
|
|
|
|
&& state == KeyState::Pressed
|
|
|
|
|
&& handle.raw_syms().contains(&binding.key.unwrap())
|
|
|
|
|
&& binding.modifiers == *modifiers
|
|
|
|
|
) || modifiers_bypass
|
2022-09-09 20:17:40 -07:00
|
|
|
{
|
2023-09-30 08:42:42 -05:00
|
|
|
modifiers_queue.clear();
|
2022-09-09 20:17:40 -07:00
|
|
|
userdata
|
|
|
|
|
.get::<SupressedKeys>()
|
|
|
|
|
.unwrap()
|
2023-07-06 18:20:10 +02:00
|
|
|
.add(&handle, None);
|
2023-05-19 19:44:57 +02:00
|
|
|
return FilterResult::Intercept(Some((
|
2022-09-09 20:17:40 -07:00
|
|
|
action.clone(),
|
2023-06-28 19:20:06 +02:00
|
|
|
binding.clone(),
|
2023-05-19 19:44:57 +02:00
|
|
|
)));
|
2022-09-09 20:17:40 -07:00
|
|
|
}
|
2022-08-31 13:01:23 +02:00
|
|
|
}
|
2022-03-28 23:45:30 +02:00
|
|
|
}
|
2022-01-11 17:22:23 +01:00
|
|
|
|
2023-09-30 08:42:42 -05:00
|
|
|
if can_clear_modifiers_shortcut {
|
|
|
|
|
userdata.get::<ModifiersShortcutQueue>().unwrap().clear();
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-28 21:29:39 +02:00
|
|
|
// keys are passed through to apps
|
2022-08-31 13:01:23 +02:00
|
|
|
FilterResult::Forward
|
|
|
|
|
},
|
|
|
|
|
)
|
2022-03-30 23:24:29 +02:00
|
|
|
.flatten()
|
|
|
|
|
{
|
2023-11-22 17:42:11 +01:00
|
|
|
self.handle_action(action, &seat, serial, time, pattern, None, true)
|
2022-03-30 23:24:29 +02:00
|
|
|
}
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::PointerMotion { event, .. } => {
|
|
|
|
|
use smithay::backend::input::PointerMotionEvent;
|
|
|
|
|
|
2023-09-05 13:41:21 -07:00
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
|
|
|
|
let current_output = seat.active_output();
|
2022-11-03 18:51:27 +01:00
|
|
|
|
2023-10-25 19:24:51 +02:00
|
|
|
let mut position = seat.get_pointer().unwrap().current_location().as_global();
|
2023-09-13 20:52:10 -07:00
|
|
|
|
2023-12-20 20:24:13 +00:00
|
|
|
let under =
|
|
|
|
|
State::surface_under(position, ¤t_output, &mut self.common.shell)
|
2023-12-20 20:51:04 +00:00
|
|
|
.map(|(target, pos)| (target, pos.as_logical()));
|
2023-09-13 20:52:10 -07:00
|
|
|
|
|
|
|
|
let ptr = seat.get_pointer().unwrap();
|
|
|
|
|
|
|
|
|
|
let mut pointer_locked = false;
|
|
|
|
|
let mut pointer_confined = false;
|
|
|
|
|
let mut confine_region = None;
|
|
|
|
|
if let Some((surface, surface_loc)) = under
|
|
|
|
|
.as_ref()
|
|
|
|
|
.and_then(|(target, l)| Some((target.wl_surface()?, l)))
|
|
|
|
|
{
|
|
|
|
|
with_pointer_constraint(&surface, &ptr, |constraint| match constraint {
|
|
|
|
|
Some(constraint) if constraint.is_active() => {
|
|
|
|
|
// Constraint does not apply if not within region
|
|
|
|
|
if !constraint.region().map_or(true, |x| {
|
|
|
|
|
x.contains(ptr.current_location().to_i32_round() - *surface_loc)
|
|
|
|
|
}) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
match &*constraint {
|
|
|
|
|
PointerConstraint::Locked(_locked) => {
|
|
|
|
|
pointer_locked = true;
|
|
|
|
|
}
|
|
|
|
|
PointerConstraint::Confined(confine) => {
|
|
|
|
|
pointer_confined = true;
|
|
|
|
|
confine_region = confine.region().cloned();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptr.relative_motion(
|
|
|
|
|
self,
|
|
|
|
|
under.clone(),
|
|
|
|
|
&RelativeMotionEvent {
|
|
|
|
|
delta: event.delta(),
|
|
|
|
|
delta_unaccel: event.delta_unaccel(),
|
|
|
|
|
utime: event.time(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if pointer_locked {
|
|
|
|
|
ptr.frame(self);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:24:51 +02:00
|
|
|
position += event.delta().as_global();
|
2023-09-05 13:41:21 -07:00
|
|
|
|
|
|
|
|
let output = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.outputs()
|
|
|
|
|
.find(|output| output.geometry().to_f64().contains(position))
|
|
|
|
|
.cloned()
|
|
|
|
|
.unwrap_or(current_output.clone());
|
2023-10-23 21:09:38 +02:00
|
|
|
|
|
|
|
|
if ptr.is_grabbed()
|
|
|
|
|
&& seat
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<ResizeGrabMarker>()
|
|
|
|
|
.map(|marker| marker.get())
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
{
|
|
|
|
|
if output != current_output {
|
|
|
|
|
ptr.frame(self);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:24:51 +02:00
|
|
|
let output_geometry = output.geometry();
|
2023-09-13 20:52:10 -07:00
|
|
|
|
2023-12-20 20:24:13 +00:00
|
|
|
let new_under = State::surface_under(position, &output, &mut self.common.shell)
|
2023-12-20 20:51:04 +00:00
|
|
|
.map(|(target, pos)| (target, pos.as_logical()));
|
2023-09-13 20:52:10 -07:00
|
|
|
|
|
|
|
|
position.x = position.x.clamp(
|
|
|
|
|
output_geometry.loc.x as f64,
|
|
|
|
|
(output_geometry.loc.x + output_geometry.size.w) as f64,
|
|
|
|
|
);
|
|
|
|
|
position.y = position.y.clamp(
|
|
|
|
|
output_geometry.loc.y as f64,
|
|
|
|
|
(output_geometry.loc.y + output_geometry.size.h) as f64,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// If confined, don't move pointer if it would go outside surface or region
|
|
|
|
|
if pointer_confined {
|
|
|
|
|
if let Some((surface, surface_loc)) = &under {
|
|
|
|
|
if new_under.as_ref().and_then(|(under, _)| under.wl_surface())
|
|
|
|
|
!= surface.wl_surface()
|
|
|
|
|
{
|
|
|
|
|
ptr.frame(self);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if let PointerFocusTarget::Element(element) = surface {
|
|
|
|
|
//if !element.is_in_input_region(&(position.to_i32_round() - *surface_loc).to_f64()) {
|
2023-10-25 19:24:51 +02:00
|
|
|
if !element.is_in_input_region(
|
|
|
|
|
&(position.as_logical() - surface_loc.to_f64()),
|
|
|
|
|
) {
|
2023-09-13 20:52:10 -07:00
|
|
|
ptr.frame(self);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if let Some(region) = confine_region {
|
2023-10-25 19:24:51 +02:00
|
|
|
if !region
|
|
|
|
|
.contains(position.as_logical().to_i32_round() - *surface_loc)
|
|
|
|
|
{
|
2023-09-13 20:52:10 -07:00
|
|
|
ptr.frame(self);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
ptr.motion(
|
|
|
|
|
self,
|
|
|
|
|
under,
|
|
|
|
|
&MotionEvent {
|
2023-10-25 19:24:51 +02:00
|
|
|
location: position.as_logical(),
|
2023-09-13 20:52:10 -07:00
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
ptr.frame(self);
|
|
|
|
|
|
|
|
|
|
// If pointer is now in a constraint region, activate it
|
|
|
|
|
if let Some((under, surface_location)) =
|
|
|
|
|
new_under.and_then(|(target, loc)| Some((target.wl_surface()?, loc)))
|
|
|
|
|
{
|
|
|
|
|
with_pointer_constraint(&under, &ptr, |constraint| match constraint {
|
|
|
|
|
Some(constraint) if !constraint.is_active() => {
|
|
|
|
|
let region = match &*constraint {
|
|
|
|
|
PointerConstraint::Locked(locked) => locked.region(),
|
|
|
|
|
PointerConstraint::Confined(confined) => confined.region(),
|
|
|
|
|
};
|
|
|
|
|
let point =
|
|
|
|
|
ptr.current_location().to_i32_round() - surface_location;
|
|
|
|
|
if region.map_or(true, |region| region.contains(point)) {
|
|
|
|
|
constraint.activate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-05 13:41:21 -07:00
|
|
|
if output != current_output {
|
|
|
|
|
for session in sessions_for_output(&self.common, ¤t_output) {
|
|
|
|
|
session.cursor_leave(&seat, InputType::Pointer);
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
|
|
|
|
|
for session in sessions_for_output(&self.common, &output) {
|
2023-09-05 13:41:21 -07:00
|
|
|
session.cursor_enter(&seat, InputType::Pointer);
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
|
|
|
|
|
seat.set_active_output(&output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for session in sessions_for_output(&self.common, &output) {
|
|
|
|
|
if let Some((geometry, offset)) = seat.cursor_geometry(
|
2023-10-25 19:24:51 +02:00
|
|
|
position.as_logical().to_buffer(
|
2023-09-05 13:41:21 -07:00
|
|
|
output.current_scale().fractional_scale(),
|
|
|
|
|
output.current_transform(),
|
2023-10-25 19:24:51 +02:00
|
|
|
&output_geometry.size.to_f64().as_logical(),
|
2023-09-05 13:41:21 -07:00
|
|
|
),
|
|
|
|
|
self.common.clock.now(),
|
|
|
|
|
) {
|
|
|
|
|
session.cursor_info(&seat, InputType::Pointer, geometry, offset);
|
2023-03-06 18:48:52 +01:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
}
|
|
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
if self.common.seats().position(|x| x == &seat).unwrap() == 0 {
|
2023-10-20 15:22:03 -07:00
|
|
|
if let Some(output) = self.common.shell.outputs().next() {
|
|
|
|
|
let location = position.to_local(&output).to_i32_round().as_logical();
|
|
|
|
|
self.common.egui.state.handle_pointer_motion(location);
|
|
|
|
|
}
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::PointerMotionAbsolute { event, .. } => {
|
2023-09-05 13:41:21 -07:00
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
|
|
|
|
let output = seat.active_output();
|
|
|
|
|
let geometry = output.geometry();
|
|
|
|
|
let position = geometry.loc.to_f64()
|
|
|
|
|
+ smithay::backend::input::AbsolutePositionEvent::position_transformed(
|
|
|
|
|
&event,
|
2023-10-25 19:24:51 +02:00
|
|
|
geometry.size.as_logical(),
|
|
|
|
|
)
|
|
|
|
|
.as_global();
|
2023-09-05 13:41:21 -07:00
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
2023-12-20 20:24:13 +00:00
|
|
|
let under = State::surface_under(position, &output, &mut self.common.shell)
|
2023-12-20 20:51:04 +00:00
|
|
|
.map(|(target, pos)| (target, pos.as_logical()));
|
2023-09-05 13:41:21 -07:00
|
|
|
|
|
|
|
|
for session in sessions_for_output(&self.common, &output) {
|
|
|
|
|
if let Some((geometry, offset)) = seat.cursor_geometry(
|
2023-10-25 19:24:51 +02:00
|
|
|
position.as_logical().to_buffer(
|
2023-09-05 13:41:21 -07:00
|
|
|
output.current_scale().fractional_scale(),
|
|
|
|
|
output.current_transform(),
|
2023-10-25 19:24:51 +02:00
|
|
|
&geometry.size.to_f64().as_logical(),
|
2023-09-05 13:41:21 -07:00
|
|
|
),
|
|
|
|
|
self.common.clock.now(),
|
|
|
|
|
) {
|
|
|
|
|
session.cursor_info(&seat, InputType::Pointer, geometry, offset);
|
2023-03-06 18:48:52 +01:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
}
|
2023-09-13 20:52:10 -07:00
|
|
|
let ptr = seat.get_pointer().unwrap();
|
|
|
|
|
ptr.motion(
|
2023-09-05 13:41:21 -07:00
|
|
|
self,
|
|
|
|
|
under,
|
|
|
|
|
&MotionEvent {
|
2023-10-25 19:24:51 +02:00
|
|
|
location: position.as_logical(),
|
2023-09-05 13:41:21 -07:00
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-09-13 20:52:10 -07:00
|
|
|
ptr.frame(self);
|
2023-09-05 13:41:21 -07:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
if self.common.seats().position(|x| x == &seat).unwrap() == 0 {
|
2023-10-20 15:22:03 -07:00
|
|
|
if let Some(output) = self.common.shell.outputs().next() {
|
|
|
|
|
let location = position.to_local(&output).to_i32_round().as_logical();
|
|
|
|
|
self.common.egui.state.handle_pointer_motion(location);
|
|
|
|
|
}
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::PointerButton { event, .. } => {
|
2022-08-31 13:01:23 +02:00
|
|
|
use smithay::backend::input::{ButtonState, PointerButtonEvent};
|
2021-12-22 20:14:09 +01:00
|
|
|
|
2023-09-05 13:41:21 -07:00
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
|
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
if self.common.seats().position(|x| x == &seat).unwrap() == 0
|
|
|
|
|
&& self.common.egui.active
|
|
|
|
|
{
|
|
|
|
|
if self.common.egui.state.wants_pointer() {
|
|
|
|
|
if let Some(button) = event.button() {
|
|
|
|
|
self.common.egui.state.handle_pointer_button(
|
|
|
|
|
button,
|
|
|
|
|
event.state() == ButtonState::Pressed,
|
|
|
|
|
);
|
2023-03-06 18:48:52 +01:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
return;
|
2023-03-06 18:48:52 +01:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
}
|
2023-03-06 18:48:52 +01:00
|
|
|
|
2023-09-05 13:41:21 -07:00
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let button = event.button_code();
|
|
|
|
|
if event.state() == ButtonState::Pressed {
|
|
|
|
|
// change the keyboard focus unless the pointer or keyboard is grabbed
|
|
|
|
|
// We test for any matching surface type here but always use the root
|
|
|
|
|
// (in case of a window the toplevel) surface for the focus.
|
|
|
|
|
// see: https://gitlab.freedesktop.org/wayland/wayland/-/issues/294
|
|
|
|
|
if !seat.get_pointer().unwrap().is_grabbed()
|
|
|
|
|
&& !seat.get_keyboard().map(|k| k.is_grabbed()).unwrap_or(false)
|
|
|
|
|
{
|
|
|
|
|
let output = seat.active_output();
|
2023-11-14 13:13:42 -08:00
|
|
|
|
2023-10-25 19:24:51 +02:00
|
|
|
let pos = seat.get_pointer().unwrap().current_location().as_global();
|
|
|
|
|
let relative_pos = pos.to_local(&output);
|
2023-09-05 13:41:21 -07:00
|
|
|
let mut under = None;
|
|
|
|
|
|
2023-11-14 13:13:42 -08:00
|
|
|
if let Some(session_lock) = self.common.shell.session_lock.as_ref() {
|
2023-10-16 12:28:19 -07:00
|
|
|
under = session_lock
|
|
|
|
|
.surfaces
|
|
|
|
|
.get(&output)
|
|
|
|
|
.map(|lock| lock.clone().into());
|
2023-11-14 13:13:42 -08:00
|
|
|
} else if let Some(window) =
|
|
|
|
|
self.common.shell.active_space(&output).get_fullscreen()
|
|
|
|
|
{
|
2023-09-05 13:41:21 -07:00
|
|
|
let layers = layer_map_for_output(&output);
|
|
|
|
|
if let Some(layer) =
|
2023-10-25 19:24:51 +02:00
|
|
|
layers.layer_under(WlrLayer::Overlay, relative_pos.as_logical())
|
2023-09-05 13:41:21 -07:00
|
|
|
{
|
|
|
|
|
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
|
|
|
|
|
if layer.can_receive_keyboard_focus()
|
|
|
|
|
&& layer
|
|
|
|
|
.surface_under(
|
2023-10-25 19:24:51 +02:00
|
|
|
relative_pos.as_logical() - layer_loc.to_f64(),
|
2023-09-05 13:41:21 -07:00
|
|
|
WindowSurfaceType::ALL,
|
|
|
|
|
)
|
|
|
|
|
.is_some()
|
|
|
|
|
{
|
|
|
|
|
under = Some(layer.clone().into());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
under = Some(window.clone().into());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
let done = {
|
2023-07-21 16:08:55 +02:00
|
|
|
let layers = layer_map_for_output(&output);
|
2023-09-05 13:41:21 -07:00
|
|
|
if let Some(layer) = layers
|
2023-10-25 19:24:51 +02:00
|
|
|
.layer_under(WlrLayer::Overlay, relative_pos.as_logical())
|
|
|
|
|
.or_else(|| {
|
|
|
|
|
layers.layer_under(
|
|
|
|
|
WlrLayer::Top,
|
|
|
|
|
relative_pos.as_logical(),
|
|
|
|
|
)
|
|
|
|
|
})
|
2022-08-31 13:01:23 +02:00
|
|
|
{
|
2022-11-11 23:23:38 +01:00
|
|
|
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
|
|
|
|
|
if layer.can_receive_keyboard_focus()
|
|
|
|
|
&& layer
|
|
|
|
|
.surface_under(
|
2023-10-25 19:24:51 +02:00
|
|
|
relative_pos.as_logical() - layer_loc.to_f64(),
|
2022-11-11 23:23:38 +01:00
|
|
|
WindowSurfaceType::ALL,
|
|
|
|
|
)
|
|
|
|
|
.is_some()
|
|
|
|
|
{
|
2022-09-28 12:01:29 +02:00
|
|
|
under = Some(layer.clone().into());
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
true
|
2022-04-22 15:18:28 +02:00
|
|
|
} else {
|
2023-09-05 13:41:21 -07:00
|
|
|
false
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
};
|
|
|
|
|
if !done {
|
2023-10-25 19:24:51 +02:00
|
|
|
if let Some((target, _)) =
|
2023-12-20 20:24:13 +00:00
|
|
|
self.common.shell.element_under(pos, &output)
|
2023-10-25 19:24:51 +02:00
|
|
|
{
|
|
|
|
|
under = Some(target);
|
2023-09-05 13:41:21 -07:00
|
|
|
} else {
|
2023-10-25 19:24:51 +02:00
|
|
|
let layers = layer_map_for_output(&output);
|
|
|
|
|
if let Some(layer) = layers
|
|
|
|
|
.layer_under(
|
|
|
|
|
WlrLayer::Bottom,
|
|
|
|
|
relative_pos.as_logical(),
|
|
|
|
|
)
|
|
|
|
|
.or_else(|| {
|
|
|
|
|
layers.layer_under(
|
|
|
|
|
WlrLayer::Background,
|
|
|
|
|
relative_pos.as_logical(),
|
|
|
|
|
)
|
|
|
|
|
})
|
2022-11-11 23:23:38 +01:00
|
|
|
{
|
2023-10-25 19:24:51 +02:00
|
|
|
let layer_loc =
|
|
|
|
|
layers.layer_geometry(layer).unwrap().loc;
|
|
|
|
|
if layer.can_receive_keyboard_focus()
|
|
|
|
|
&& layer
|
|
|
|
|
.surface_under(
|
|
|
|
|
relative_pos.as_logical()
|
|
|
|
|
- layer_loc.to_f64(),
|
|
|
|
|
WindowSurfaceType::ALL,
|
|
|
|
|
)
|
|
|
|
|
.is_some()
|
2023-07-21 16:08:55 +02:00
|
|
|
{
|
2023-10-25 19:24:51 +02:00
|
|
|
under = Some(layer.clone().into());
|
|
|
|
|
}
|
|
|
|
|
};
|
2023-07-21 16:08:55 +02:00
|
|
|
}
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
Common::set_focus(
|
|
|
|
|
self,
|
|
|
|
|
under.and_then(|target| target.try_into().ok()).as_ref(),
|
|
|
|
|
&seat,
|
|
|
|
|
Some(serial),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if let OverviewMode::Started(Trigger::Pointer(action_button), _) =
|
2023-08-11 18:15:22 +02:00
|
|
|
self.common.shell.overview_mode().0
|
2023-09-05 13:41:21 -07:00
|
|
|
{
|
|
|
|
|
if action_button == button {
|
2023-08-11 18:15:22 +02:00
|
|
|
self.common
|
|
|
|
|
.shell
|
|
|
|
|
.set_overview_mode(None, self.common.event_loop_handle.clone());
|
2023-07-17 21:11:45 +02:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
}
|
|
|
|
|
};
|
2023-09-13 20:52:10 -07:00
|
|
|
let ptr = seat.get_pointer().unwrap();
|
|
|
|
|
ptr.button(
|
2023-09-05 13:41:21 -07:00
|
|
|
self,
|
|
|
|
|
&ButtonEvent {
|
|
|
|
|
button,
|
|
|
|
|
state: event.state(),
|
|
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-09-13 20:52:10 -07:00
|
|
|
ptr.frame(self);
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::PointerAxis { event, .. } => {
|
2023-12-28 13:36:59 -08:00
|
|
|
let scroll_factor =
|
|
|
|
|
if let Some(device) = <dyn Any>::downcast_ref::<InputDevice>(&event.device()) {
|
|
|
|
|
self.common.config.scroll_factor(device)
|
|
|
|
|
} else {
|
|
|
|
|
1.0
|
|
|
|
|
};
|
2023-09-01 12:33:55 -07:00
|
|
|
|
2023-09-05 13:41:21 -07:00
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
2023-03-06 18:48:52 +01:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
if self.common.seats().position(|x| x == seat).unwrap() == 0
|
|
|
|
|
&& self.common.egui.active
|
|
|
|
|
{
|
|
|
|
|
if self.common.egui.state.wants_pointer() {
|
|
|
|
|
self.common.egui.state.handle_pointer_axis(
|
|
|
|
|
event
|
2023-12-12 14:32:49 -08:00
|
|
|
.amount_v120(Axis::Horizontal)
|
|
|
|
|
.or_else(|| {
|
|
|
|
|
event.amount(Axis::Horizontal).map(|x| x * 3.0 * 120.0)
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(0.0)
|
|
|
|
|
/ 120.0,
|
2023-03-06 18:48:52 +01:00
|
|
|
event
|
2023-12-12 14:32:49 -08:00
|
|
|
.amount_v120(Axis::Vertical)
|
|
|
|
|
.or_else(|| {
|
|
|
|
|
event.amount(Axis::Vertical).map(|x| x * 3.0 * 120.0)
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(0.0)
|
|
|
|
|
/ 120.0,
|
2023-03-06 18:48:52 +01:00
|
|
|
);
|
2023-09-05 13:41:21 -07:00
|
|
|
return;
|
2023-03-06 18:48:52 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-21 13:32:37 -08:00
|
|
|
let mut frame = AxisFrame::new(event.time_msec()).source(event.source());
|
|
|
|
|
if let Some(horizontal_amount) = event.amount(Axis::Horizontal) {
|
2023-09-05 13:41:21 -07:00
|
|
|
if horizontal_amount != 0.0 {
|
|
|
|
|
frame =
|
|
|
|
|
frame.value(Axis::Horizontal, scroll_factor * horizontal_amount);
|
2023-12-21 13:32:37 -08:00
|
|
|
if let Some(discrete) = event.amount_v120(Axis::Horizontal) {
|
2023-12-12 12:28:13 -08:00
|
|
|
frame = frame.v120(Axis::Horizontal, discrete as i32);
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
} else if event.source() == AxisSource::Finger {
|
|
|
|
|
frame = frame.stop(Axis::Horizontal);
|
|
|
|
|
}
|
2023-12-21 13:32:37 -08:00
|
|
|
}
|
|
|
|
|
if let Some(vertical_amount) = event.amount(Axis::Vertical) {
|
2023-09-05 13:41:21 -07:00
|
|
|
if vertical_amount != 0.0 {
|
|
|
|
|
frame = frame.value(Axis::Vertical, scroll_factor * vertical_amount);
|
2023-12-21 13:32:37 -08:00
|
|
|
if let Some(discrete) = event.amount_v120(Axis::Vertical) {
|
2023-12-12 12:28:13 -08:00
|
|
|
frame = frame.v120(Axis::Vertical, discrete as i32);
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
} else if event.source() == AxisSource::Finger {
|
|
|
|
|
frame = frame.stop(Axis::Vertical);
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-12-21 13:32:37 -08:00
|
|
|
let ptr = seat.get_pointer().unwrap();
|
|
|
|
|
ptr.axis(self, frame);
|
|
|
|
|
ptr.frame(self);
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-09-05 13:41:21 -07:00
|
|
|
InputEvent::GestureSwipeBegin { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.gesture_swipe_begin(
|
|
|
|
|
self,
|
|
|
|
|
&GestureSwipeBeginEvent {
|
|
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
fingers: event.fingers(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::GestureSwipeUpdate { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.gesture_swipe_update(
|
|
|
|
|
self,
|
|
|
|
|
&GestureSwipeUpdateEvent {
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
delta: event.delta(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::GestureSwipeEnd { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.gesture_swipe_end(
|
|
|
|
|
self,
|
|
|
|
|
&GestureSwipeEndEvent {
|
|
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
cancelled: event.cancelled(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::GesturePinchBegin { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.gesture_pinch_begin(
|
|
|
|
|
self,
|
|
|
|
|
&GesturePinchBeginEvent {
|
|
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
fingers: event.fingers(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::GesturePinchUpdate { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.gesture_pinch_update(
|
|
|
|
|
self,
|
|
|
|
|
&GesturePinchUpdateEvent {
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
delta: event.delta(),
|
|
|
|
|
scale: event.scale(),
|
|
|
|
|
rotation: event.rotation(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::GesturePinchEnd { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.gesture_pinch_end(
|
|
|
|
|
self,
|
|
|
|
|
&GesturePinchEndEvent {
|
|
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
cancelled: event.cancelled(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::GestureHoldBegin { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.gesture_hold_begin(
|
|
|
|
|
self,
|
|
|
|
|
&GestureHoldBeginEvent {
|
|
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
fingers: event.fingers(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::GestureHoldEnd { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.gesture_hold_end(
|
|
|
|
|
self,
|
|
|
|
|
&GestureHoldEndEvent {
|
|
|
|
|
serial,
|
|
|
|
|
time: event.time_msec(),
|
|
|
|
|
cancelled: event.cancelled(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-07 13:56:31 -08:00
|
|
|
InputEvent::TouchDown { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
2024-02-21 13:24:56 -08:00
|
|
|
let Some(output) =
|
|
|
|
|
mapped_output_for_device(&self.common, &event.device()).cloned()
|
|
|
|
|
else {
|
2023-11-07 13:56:31 -08:00
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let geometry = output.geometry();
|
|
|
|
|
|
|
|
|
|
let position = geometry.loc.to_f64()
|
|
|
|
|
+ event
|
|
|
|
|
.position_transformed(geometry.size.as_logical())
|
|
|
|
|
.as_global();
|
|
|
|
|
|
2024-01-17 13:12:46 -08:00
|
|
|
let under = State::surface_under(position, &output, &mut self.common.shell)
|
|
|
|
|
.map(|(target, pos)| (target, pos.as_logical()));
|
2023-11-07 13:56:31 -08:00
|
|
|
|
|
|
|
|
if let Some((target, pos)) = under {
|
|
|
|
|
if let Some(wl_surface) = target.wl_surface() {
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let touch = seat.get_touch().unwrap();
|
|
|
|
|
touch.down(
|
|
|
|
|
serial,
|
|
|
|
|
event.time_msec(),
|
|
|
|
|
&wl_surface,
|
|
|
|
|
position.as_logical() - pos.to_f64(),
|
|
|
|
|
event.slot(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::TouchMotion { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
2024-02-21 13:24:56 -08:00
|
|
|
let Some(output) =
|
|
|
|
|
mapped_output_for_device(&self.common, &event.device()).cloned()
|
|
|
|
|
else {
|
2023-11-07 13:56:31 -08:00
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let geometry = output.geometry();
|
|
|
|
|
|
|
|
|
|
let position = geometry.loc.to_f64()
|
|
|
|
|
+ event
|
|
|
|
|
.position_transformed(geometry.size.as_logical())
|
|
|
|
|
.as_global();
|
|
|
|
|
|
2024-01-17 13:12:46 -08:00
|
|
|
let under = State::surface_under(position, &output, &mut self.common.shell)
|
|
|
|
|
.map(|(target, pos)| (target, pos.as_logical()));
|
2023-11-07 13:56:31 -08:00
|
|
|
|
|
|
|
|
if let Some((_target, pos)) = under {
|
|
|
|
|
let touch = seat.get_touch().unwrap();
|
|
|
|
|
touch.motion(
|
|
|
|
|
event.time_msec(),
|
|
|
|
|
event.slot(),
|
|
|
|
|
position.as_logical() - pos.to_f64(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::TouchUp { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let serial = SERIAL_COUNTER.next_serial();
|
|
|
|
|
let touch = seat.get_touch().unwrap();
|
|
|
|
|
touch.up(serial, event.time_msec(), event.slot());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::TouchCancel { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
let touch = seat.get_touch().unwrap();
|
|
|
|
|
touch.cancel();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::TouchFrame { event: _, .. } => {}
|
2023-12-28 13:36:59 -08:00
|
|
|
InputEvent::TabletToolAxis { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
2024-02-21 13:24:56 -08:00
|
|
|
let Some(output) =
|
|
|
|
|
mapped_output_for_device(&self.common, &event.device()).cloned()
|
|
|
|
|
else {
|
2023-12-28 13:36:59 -08:00
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
let geometry = output.geometry();
|
|
|
|
|
|
|
|
|
|
let position = event
|
|
|
|
|
.position_transformed(geometry.size.as_logical())
|
|
|
|
|
.as_global()
|
|
|
|
|
+ geometry.loc.to_f64();
|
|
|
|
|
|
2024-01-17 13:12:46 -08:00
|
|
|
let under = State::surface_under(position, &output, &mut self.common.shell)
|
|
|
|
|
.map(|(target, pos)| (target, pos.as_logical()));
|
2023-12-28 13:36:59 -08:00
|
|
|
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.motion(
|
|
|
|
|
self,
|
|
|
|
|
under.clone(),
|
|
|
|
|
&MotionEvent {
|
|
|
|
|
location: position.as_logical(),
|
|
|
|
|
serial: SERIAL_COUNTER.next_serial(),
|
|
|
|
|
time: 0,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let tablet_seat = seat.tablet_seat();
|
|
|
|
|
|
|
|
|
|
let tablet = tablet_seat.get_tablet(&TabletDescriptor::from(&event.device()));
|
|
|
|
|
let tool = tablet_seat.get_tool(&event.tool());
|
|
|
|
|
|
|
|
|
|
if let (Some(tablet), Some(tool)) = (tablet, tool) {
|
|
|
|
|
if event.pressure_has_changed() {
|
|
|
|
|
tool.pressure(event.pressure());
|
|
|
|
|
}
|
|
|
|
|
if event.distance_has_changed() {
|
|
|
|
|
tool.distance(event.distance());
|
|
|
|
|
}
|
|
|
|
|
if event.tilt_has_changed() {
|
|
|
|
|
tool.tilt(event.tilt());
|
|
|
|
|
}
|
|
|
|
|
if event.slider_has_changed() {
|
|
|
|
|
tool.slider_position(event.slider_position());
|
|
|
|
|
}
|
|
|
|
|
if event.rotation_has_changed() {
|
|
|
|
|
tool.rotation(event.rotation());
|
|
|
|
|
}
|
|
|
|
|
if event.wheel_has_changed() {
|
|
|
|
|
tool.wheel(event.wheel_delta(), event.wheel_delta_discrete());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tool.motion(
|
|
|
|
|
position.as_logical(),
|
|
|
|
|
under.and_then(|(f, loc)| f.wl_surface().map(|s| (s, loc))),
|
|
|
|
|
&tablet,
|
|
|
|
|
SERIAL_COUNTER.next_serial(),
|
|
|
|
|
event.time_msec(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::TabletToolProximity { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
2024-02-21 13:24:56 -08:00
|
|
|
let Some(output) =
|
|
|
|
|
mapped_output_for_device(&self.common, &event.device()).cloned()
|
|
|
|
|
else {
|
2023-12-28 13:36:59 -08:00
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
let geometry = output.geometry();
|
|
|
|
|
|
|
|
|
|
let position = event
|
|
|
|
|
.position_transformed(geometry.size.as_logical())
|
|
|
|
|
.as_global()
|
|
|
|
|
+ geometry.loc.to_f64();
|
|
|
|
|
|
2024-01-17 13:12:46 -08:00
|
|
|
let under = State::surface_under(position, &output, &mut self.common.shell)
|
|
|
|
|
.map(|(target, pos)| (target, pos.as_logical()));
|
2023-12-28 13:36:59 -08:00
|
|
|
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
pointer.motion(
|
|
|
|
|
self,
|
|
|
|
|
under.clone(),
|
|
|
|
|
&MotionEvent {
|
|
|
|
|
location: position.as_logical(),
|
|
|
|
|
serial: SERIAL_COUNTER.next_serial(),
|
|
|
|
|
time: 0,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let tablet_seat = seat.tablet_seat();
|
|
|
|
|
|
|
|
|
|
let tablet = tablet_seat.get_tablet(&TabletDescriptor::from(&event.device()));
|
|
|
|
|
let tool = tablet_seat.get_tool(&event.tool());
|
|
|
|
|
|
|
|
|
|
if let (Some(tablet), Some(tool)) = (tablet, tool) {
|
|
|
|
|
match event.state() {
|
|
|
|
|
ProximityState::In => {
|
|
|
|
|
if let Some(under) =
|
|
|
|
|
under.and_then(|(f, loc)| f.wl_surface().map(|s| (s, loc)))
|
|
|
|
|
{
|
|
|
|
|
tool.proximity_in(
|
|
|
|
|
position.as_logical(),
|
|
|
|
|
under,
|
|
|
|
|
&tablet,
|
|
|
|
|
SERIAL_COUNTER.next_serial(),
|
|
|
|
|
event.time_msec(),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ProximityState::Out => tool.proximity_out(event.time_msec()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::TabletToolTip { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
|
|
|
|
match event.tip_state() {
|
|
|
|
|
TabletToolTipState::Down => {
|
|
|
|
|
tool.tip_down(SERIAL_COUNTER.next_serial(), event.time_msec());
|
|
|
|
|
}
|
|
|
|
|
TabletToolTipState::Up => {
|
|
|
|
|
tool.tip_up(event.time_msec());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::TabletToolButton { event, .. } => {
|
|
|
|
|
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
|
|
|
|
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
|
|
|
|
tool.button(
|
|
|
|
|
event.button(),
|
|
|
|
|
event.button_state(),
|
|
|
|
|
SERIAL_COUNTER.next_serial(),
|
|
|
|
|
event.time_msec(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
InputEvent::Special(_) => {}
|
2024-02-01 15:38:05 +01:00
|
|
|
InputEvent::SwitchToggle { event: _ } => {}
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-11 18:15:22 +02:00
|
|
|
pub fn handle_action(
|
2023-05-19 19:44:57 +02:00
|
|
|
&mut self,
|
|
|
|
|
action: Action,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
serial: Serial,
|
|
|
|
|
time: u32,
|
2023-06-28 19:20:06 +02:00
|
|
|
pattern: KeyPattern,
|
2023-05-25 17:51:53 +02:00
|
|
|
direction: Option<Direction>,
|
2023-11-22 17:42:11 +01:00
|
|
|
propagate: bool,
|
2023-05-19 19:44:57 +02:00
|
|
|
) {
|
2023-10-16 12:28:19 -07:00
|
|
|
// TODO: Detect if started from login manager or tty, and only allow
|
|
|
|
|
// `Terminate` if it will return to login manager.
|
2023-11-14 13:13:42 -08:00
|
|
|
if self.common.shell.session_lock.is_some()
|
2023-10-16 12:28:19 -07:00
|
|
|
&& !matches!(action, Action::Terminate | Action::Debug)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-10 18:42:11 +01:00
|
|
|
match action {
|
|
|
|
|
Action::Terminate => {
|
|
|
|
|
self.common.should_stop = true;
|
|
|
|
|
}
|
|
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
Action::Debug => {
|
|
|
|
|
self.common.egui.active = !self.common.egui.active;
|
2023-03-06 18:50:11 +01:00
|
|
|
puffin::set_scopes_on(self.common.egui.active);
|
2022-11-28 17:48:50 +01:00
|
|
|
for mapped in self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.spaces()
|
|
|
|
|
.flat_map(|w| w.mapped())
|
|
|
|
|
{
|
|
|
|
|
mapped.set_debug(self.common.egui.active);
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
#[cfg(not(feature = "debug"))]
|
|
|
|
|
Action::Debug => {
|
2023-02-24 17:41:52 +01:00
|
|
|
info!("Debug overlay not included in this build.")
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
Action::Close => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space_mut(¤t_output);
|
|
|
|
|
if let Some(window) = workspace.focus_stack.get(seat).last() {
|
|
|
|
|
window.send_close();
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-11 16:11:20 +00:00
|
|
|
Action::Escape => {
|
|
|
|
|
self.common
|
|
|
|
|
.shell
|
|
|
|
|
.set_overview_mode(None, self.common.event_loop_handle.clone());
|
|
|
|
|
self.common.shell.set_resize_mode(
|
|
|
|
|
None,
|
|
|
|
|
&self.common.config,
|
|
|
|
|
self.common.event_loop_handle.clone(),
|
|
|
|
|
);
|
|
|
|
|
let pointer = seat.get_pointer().unwrap();
|
|
|
|
|
let keyboard = seat.get_keyboard().unwrap();
|
|
|
|
|
if pointer.is_grabbed() {
|
|
|
|
|
pointer.unset_grab(self, serial, time);
|
|
|
|
|
}
|
|
|
|
|
if keyboard.is_grabbed() {
|
|
|
|
|
keyboard.unset_grab();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
Action::Workspace(key_num) => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = match key_num {
|
|
|
|
|
0 => 9,
|
|
|
|
|
x => x - 1,
|
|
|
|
|
};
|
2022-11-22 10:10:08 +01:00
|
|
|
let _ = self
|
2022-11-10 18:42:11 +01:00
|
|
|
.common
|
|
|
|
|
.shell
|
2022-11-22 10:10:08 +01:00
|
|
|
.activate(¤t_output, workspace as usize);
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
2023-11-22 17:42:11 +01:00
|
|
|
Action::LastWorkspace => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.len(¤t_output)
|
|
|
|
|
.saturating_sub(1);
|
|
|
|
|
let _ = self.common.shell.activate(¤t_output, workspace);
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
Action::NextWorkspace => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.active_num(¤t_output)
|
2023-05-22 20:19:11 +02:00
|
|
|
.1
|
2022-11-10 18:42:11 +01:00
|
|
|
.saturating_add(1);
|
2023-05-25 00:10:24 +02:00
|
|
|
if self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.activate(¤t_output, workspace)
|
|
|
|
|
.is_err()
|
2023-11-22 17:42:11 +01:00
|
|
|
&& propagate
|
2023-05-25 00:10:24 +02:00
|
|
|
{
|
2023-11-16 19:28:00 +01:00
|
|
|
if let Some(inferred) = pattern.inferred_direction() {
|
|
|
|
|
self.handle_action(
|
|
|
|
|
Action::SwitchOutput(inferred),
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
direction,
|
2023-11-22 17:42:11 +01:00
|
|
|
false,
|
2023-11-16 19:28:00 +01:00
|
|
|
)
|
|
|
|
|
};
|
2023-05-25 00:10:24 +02:00
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
Action::PreviousWorkspace => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.active_num(¤t_output)
|
2023-05-22 20:19:11 +02:00
|
|
|
.1
|
2022-11-10 18:42:11 +01:00
|
|
|
.saturating_sub(1);
|
2023-05-25 00:10:24 +02:00
|
|
|
if self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.activate(¤t_output, workspace)
|
|
|
|
|
.is_err()
|
2023-11-22 17:42:11 +01:00
|
|
|
&& propagate
|
2023-05-25 00:10:24 +02:00
|
|
|
{
|
2023-11-16 19:28:00 +01:00
|
|
|
if let Some(inferred) = pattern.inferred_direction() {
|
|
|
|
|
self.handle_action(
|
|
|
|
|
Action::SwitchOutput(inferred),
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
direction,
|
2023-11-22 17:42:11 +01:00
|
|
|
false,
|
2023-11-16 19:28:00 +01:00
|
|
|
)
|
|
|
|
|
};
|
2023-05-25 00:10:24 +02:00
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
2023-01-24 19:22:00 +01:00
|
|
|
x @ Action::MoveToWorkspace(_) | x @ Action::SendToWorkspace(_) => {
|
2022-11-10 18:42:11 +01:00
|
|
|
let current_output = seat.active_output();
|
2023-01-24 19:22:00 +01:00
|
|
|
let follow = matches!(x, Action::MoveToWorkspace(_));
|
|
|
|
|
let workspace = match x {
|
|
|
|
|
Action::MoveToWorkspace(0) | Action::SendToWorkspace(0) => 9,
|
|
|
|
|
Action::MoveToWorkspace(x) | Action::SendToWorkspace(x) => x - 1,
|
|
|
|
|
_ => unreachable!(),
|
2022-11-10 18:42:11 +01:00
|
|
|
};
|
2023-05-25 00:10:24 +02:00
|
|
|
let _ = Shell::move_current_window(
|
2022-11-10 18:42:11 +01:00
|
|
|
self,
|
|
|
|
|
seat,
|
|
|
|
|
¤t_output,
|
|
|
|
|
(¤t_output, Some(workspace as usize)),
|
2023-01-24 19:22:00 +01:00
|
|
|
follow,
|
2023-05-25 17:51:53 +02:00
|
|
|
None,
|
2022-11-10 18:42:11 +01:00
|
|
|
);
|
|
|
|
|
}
|
2023-11-22 17:42:11 +01:00
|
|
|
x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.len(¤t_output)
|
|
|
|
|
.saturating_sub(1);
|
|
|
|
|
let _ = Shell::move_current_window(
|
|
|
|
|
self,
|
|
|
|
|
seat,
|
|
|
|
|
¤t_output,
|
|
|
|
|
(¤t_output, Some(workspace as usize)),
|
|
|
|
|
matches!(x, Action::MoveToLastWorkspace),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-01-24 19:22:00 +01:00
|
|
|
x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => {
|
2022-11-10 18:42:11 +01:00
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.active_num(¤t_output)
|
2023-05-22 20:19:11 +02:00
|
|
|
.1
|
2022-11-10 18:42:11 +01:00
|
|
|
.saturating_add(1);
|
2023-05-25 00:10:24 +02:00
|
|
|
if Shell::move_current_window(
|
2022-11-10 18:42:11 +01:00
|
|
|
self,
|
|
|
|
|
seat,
|
|
|
|
|
¤t_output,
|
|
|
|
|
(¤t_output, Some(workspace as usize)),
|
2023-01-24 19:22:00 +01:00
|
|
|
matches!(x, Action::MoveToNextWorkspace),
|
2023-05-25 17:51:53 +02:00
|
|
|
direction,
|
2023-05-25 00:10:24 +02:00
|
|
|
)
|
|
|
|
|
.is_err()
|
2023-11-22 17:42:11 +01:00
|
|
|
&& propagate
|
2023-05-25 00:10:24 +02:00
|
|
|
{
|
2023-11-16 19:28:00 +01:00
|
|
|
if let Some(inferred) = pattern.inferred_direction() {
|
|
|
|
|
self.handle_action(
|
|
|
|
|
if matches!(x, Action::MoveToNextWorkspace) {
|
|
|
|
|
Action::MoveToOutput(inferred)
|
|
|
|
|
} else {
|
|
|
|
|
Action::SendToOutput(inferred)
|
|
|
|
|
},
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
direction,
|
2023-11-22 17:42:11 +01:00
|
|
|
false,
|
2023-11-16 19:28:00 +01:00
|
|
|
)
|
|
|
|
|
}
|
2023-05-25 00:10:24 +02:00
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
2023-01-24 19:22:00 +01:00
|
|
|
x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => {
|
2022-11-10 18:42:11 +01:00
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.workspaces
|
|
|
|
|
.active_num(¤t_output)
|
2023-05-22 20:19:11 +02:00
|
|
|
.1
|
2022-11-10 18:42:11 +01:00
|
|
|
.saturating_sub(1);
|
|
|
|
|
// TODO: Possibly move to prev output, if idx < 0
|
2023-05-25 00:10:24 +02:00
|
|
|
if Shell::move_current_window(
|
2022-11-10 18:42:11 +01:00
|
|
|
self,
|
|
|
|
|
seat,
|
|
|
|
|
¤t_output,
|
|
|
|
|
(¤t_output, Some(workspace as usize)),
|
2023-01-24 19:22:00 +01:00
|
|
|
matches!(x, Action::MoveToPreviousWorkspace),
|
2023-05-25 17:51:53 +02:00
|
|
|
direction,
|
2023-05-25 00:10:24 +02:00
|
|
|
)
|
|
|
|
|
.is_err()
|
2023-11-22 17:42:11 +01:00
|
|
|
&& propagate
|
2023-05-25 00:10:24 +02:00
|
|
|
{
|
2023-11-16 19:28:00 +01:00
|
|
|
if let Some(inferred) = pattern.inferred_direction() {
|
|
|
|
|
self.handle_action(
|
|
|
|
|
if matches!(x, Action::MoveToPreviousWorkspace) {
|
|
|
|
|
Action::MoveToOutput(inferred)
|
|
|
|
|
} else {
|
|
|
|
|
Action::SendToOutput(inferred)
|
|
|
|
|
},
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
direction,
|
2023-11-22 17:42:11 +01:00
|
|
|
false,
|
2023-11-16 19:28:00 +01:00
|
|
|
)
|
|
|
|
|
}
|
2023-05-25 00:10:24 +02:00
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
2023-11-16 19:28:00 +01:00
|
|
|
Action::SwitchOutput(direction) => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let next_output = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.next_output(¤t_output, direction)
|
|
|
|
|
.cloned();
|
|
|
|
|
|
|
|
|
|
if let Some(next_output) = next_output {
|
|
|
|
|
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
|
|
|
|
match self.common.shell.activate(&next_output, idx) {
|
|
|
|
|
Ok(Some(new_pos)) => {
|
|
|
|
|
seat.set_active_output(&next_output);
|
|
|
|
|
if let Some(ptr) = seat.get_pointer() {
|
|
|
|
|
ptr.motion(
|
|
|
|
|
self,
|
|
|
|
|
None,
|
|
|
|
|
&MotionEvent {
|
|
|
|
|
location: new_pos.to_f64().as_logical(),
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
ptr.frame(self);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(None) => {
|
|
|
|
|
seat.set_active_output(&next_output);
|
|
|
|
|
}
|
2023-11-17 19:39:37 +01:00
|
|
|
_ => {}
|
|
|
|
|
}
|
2023-11-22 17:42:11 +01:00
|
|
|
} else if propagate {
|
2024-02-08 14:25:18 -05:00
|
|
|
match (
|
|
|
|
|
direction,
|
|
|
|
|
self.common.config.cosmic_conf.workspaces.workspace_layout,
|
|
|
|
|
) {
|
2023-11-17 19:39:37 +01:00
|
|
|
(Direction::Left, WorkspaceLayout::Horizontal)
|
|
|
|
|
| (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action(
|
|
|
|
|
Action::PreviousWorkspace,
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
Some(direction),
|
2023-11-22 17:42:11 +01:00
|
|
|
false,
|
2023-11-17 19:39:37 +01:00
|
|
|
),
|
|
|
|
|
(Direction::Right, WorkspaceLayout::Horizontal)
|
|
|
|
|
| (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action(
|
|
|
|
|
Action::NextWorkspace,
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
Some(direction),
|
2023-11-22 17:42:11 +01:00
|
|
|
false,
|
2023-11-17 19:39:37 +01:00
|
|
|
),
|
|
|
|
|
|
2023-11-16 19:28:00 +01:00
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
Action::NextOutput => {
|
|
|
|
|
let current_output = seat.active_output();
|
2023-10-25 19:40:26 +02:00
|
|
|
let next_output = self
|
2022-11-10 18:42:11 +01:00
|
|
|
.common
|
|
|
|
|
.shell
|
2023-10-25 19:40:26 +02:00
|
|
|
.outputs()
|
2022-11-10 18:42:11 +01:00
|
|
|
.skip_while(|o| *o != ¤t_output)
|
|
|
|
|
.skip(1)
|
|
|
|
|
.next()
|
2023-10-25 19:40:26 +02:00
|
|
|
.cloned();
|
|
|
|
|
if let Some(next_output) = next_output {
|
2023-05-22 20:19:11 +02:00
|
|
|
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
2023-09-28 13:21:11 -06:00
|
|
|
match self.common.shell.activate(&next_output, idx) {
|
|
|
|
|
Ok(Some(new_pos)) => {
|
|
|
|
|
seat.set_active_output(&next_output);
|
|
|
|
|
if let Some(ptr) = seat.get_pointer() {
|
|
|
|
|
ptr.motion(
|
|
|
|
|
self,
|
|
|
|
|
None,
|
|
|
|
|
&MotionEvent {
|
2023-10-25 19:24:51 +02:00
|
|
|
location: new_pos.to_f64().as_logical(),
|
2023-09-28 13:21:11 -06:00
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-09-13 20:52:10 -07:00
|
|
|
ptr.frame(self);
|
2023-09-28 13:21:11 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(None) => {
|
|
|
|
|
seat.set_active_output(&next_output);
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
2023-09-28 13:21:11 -06:00
|
|
|
_ => {}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Action::PreviousOutput => {
|
|
|
|
|
let current_output = seat.active_output();
|
2023-10-25 19:40:26 +02:00
|
|
|
let prev_output = self
|
2022-11-10 18:42:11 +01:00
|
|
|
.common
|
|
|
|
|
.shell
|
2023-10-25 19:40:26 +02:00
|
|
|
.outputs()
|
2022-11-10 18:42:11 +01:00
|
|
|
.rev()
|
|
|
|
|
.skip_while(|o| *o != ¤t_output)
|
|
|
|
|
.skip(1)
|
|
|
|
|
.next()
|
2023-10-25 19:40:26 +02:00
|
|
|
.cloned();
|
|
|
|
|
if let Some(prev_output) = prev_output {
|
2023-05-22 20:19:11 +02:00
|
|
|
let idx = self.common.shell.workspaces.active_num(&prev_output).1;
|
2023-09-28 13:21:11 -06:00
|
|
|
match self.common.shell.activate(&prev_output, idx) {
|
|
|
|
|
Ok(Some(new_pos)) => {
|
|
|
|
|
seat.set_active_output(&prev_output);
|
|
|
|
|
if let Some(ptr) = seat.get_pointer() {
|
|
|
|
|
ptr.motion(
|
|
|
|
|
self,
|
|
|
|
|
None,
|
|
|
|
|
&MotionEvent {
|
2023-10-25 19:24:51 +02:00
|
|
|
location: new_pos.to_f64().as_logical(),
|
2023-09-28 13:21:11 -06:00
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-09-13 20:52:10 -07:00
|
|
|
ptr.frame(self);
|
2023-09-28 13:21:11 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(None) => {
|
|
|
|
|
seat.set_active_output(&prev_output);
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
2023-09-28 13:21:11 -06:00
|
|
|
_ => {}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-16 19:28:00 +01:00
|
|
|
action @ Action::MoveToOutput(_) | action @ Action::SendToOutput(_) => {
|
|
|
|
|
let is_move_action = matches!(action, Action::MoveToOutput(_));
|
|
|
|
|
let direction = match action {
|
|
|
|
|
Action::MoveToOutput(dir) => dir,
|
|
|
|
|
Action::SendToOutput(dir) => dir,
|
|
|
|
|
_ => unreachable!(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let next_output = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.next_output(¤t_output, direction)
|
|
|
|
|
.cloned();
|
|
|
|
|
|
|
|
|
|
if let Some(next_output) = next_output {
|
|
|
|
|
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
|
|
|
|
self,
|
|
|
|
|
seat,
|
|
|
|
|
¤t_output,
|
|
|
|
|
(&next_output, None),
|
|
|
|
|
is_move_action,
|
|
|
|
|
Some(direction),
|
|
|
|
|
) {
|
|
|
|
|
if let Some(ptr) = seat.get_pointer() {
|
|
|
|
|
ptr.motion(
|
|
|
|
|
self,
|
|
|
|
|
None,
|
|
|
|
|
&MotionEvent {
|
|
|
|
|
location: new_pos.to_f64().as_logical(),
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
ptr.frame(self);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-22 17:42:11 +01:00
|
|
|
} else if propagate {
|
2024-02-08 14:25:18 -05:00
|
|
|
match (
|
|
|
|
|
direction,
|
|
|
|
|
self.common.config.cosmic_conf.workspaces.workspace_layout,
|
|
|
|
|
) {
|
2023-11-17 19:39:37 +01:00
|
|
|
(Direction::Left, WorkspaceLayout::Horizontal)
|
|
|
|
|
| (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action(
|
|
|
|
|
Action::MoveToPreviousWorkspace,
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
Some(direction),
|
2023-11-22 17:42:11 +01:00
|
|
|
false,
|
2023-11-17 19:39:37 +01:00
|
|
|
),
|
|
|
|
|
(Direction::Right, WorkspaceLayout::Horizontal)
|
|
|
|
|
| (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action(
|
|
|
|
|
Action::MoveToNextWorkspace,
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
Some(direction),
|
2023-11-22 17:42:11 +01:00
|
|
|
false,
|
2023-11-17 19:39:37 +01:00
|
|
|
),
|
|
|
|
|
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
2023-11-16 19:28:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-05-25 00:10:24 +02:00
|
|
|
x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => {
|
2022-11-10 18:42:11 +01:00
|
|
|
let current_output = seat.active_output();
|
2023-10-25 19:40:26 +02:00
|
|
|
let next_output = self
|
2022-11-10 18:42:11 +01:00
|
|
|
.common
|
|
|
|
|
.shell
|
2023-10-25 19:40:26 +02:00
|
|
|
.outputs()
|
2022-11-10 18:42:11 +01:00
|
|
|
.skip_while(|o| *o != ¤t_output)
|
|
|
|
|
.skip(1)
|
|
|
|
|
.next()
|
2023-10-25 19:40:26 +02:00
|
|
|
.cloned();
|
|
|
|
|
if let Some(next_output) = next_output {
|
2023-05-25 00:10:24 +02:00
|
|
|
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
2022-11-22 10:10:08 +01:00
|
|
|
self,
|
|
|
|
|
seat,
|
|
|
|
|
¤t_output,
|
|
|
|
|
(&next_output, None),
|
2023-05-25 00:10:24 +02:00
|
|
|
matches!(x, Action::MoveToNextOutput),
|
2023-05-25 17:51:53 +02:00
|
|
|
direction,
|
2022-11-22 10:10:08 +01:00
|
|
|
) {
|
|
|
|
|
if let Some(ptr) = seat.get_pointer() {
|
|
|
|
|
ptr.motion(
|
|
|
|
|
self,
|
|
|
|
|
None,
|
|
|
|
|
&MotionEvent {
|
2023-10-25 19:24:51 +02:00
|
|
|
location: new_pos.to_f64().as_logical(),
|
2022-11-22 10:10:08 +01:00
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-09-13 20:52:10 -07:00
|
|
|
ptr.frame(self);
|
2022-11-22 10:10:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-05-25 00:10:24 +02:00
|
|
|
x @ Action::MoveToPreviousOutput | x @ Action::SendToPreviousOutput => {
|
2022-11-10 18:42:11 +01:00
|
|
|
let current_output = seat.active_output();
|
2023-10-25 19:40:26 +02:00
|
|
|
let prev_output = self
|
2022-11-10 18:42:11 +01:00
|
|
|
.common
|
|
|
|
|
.shell
|
2023-10-25 19:40:26 +02:00
|
|
|
.outputs()
|
2022-11-10 18:42:11 +01:00
|
|
|
.rev()
|
|
|
|
|
.skip_while(|o| *o != ¤t_output)
|
|
|
|
|
.skip(1)
|
|
|
|
|
.next()
|
2023-10-25 19:40:26 +02:00
|
|
|
.cloned();
|
|
|
|
|
if let Some(prev_output) = prev_output {
|
2023-05-25 00:10:24 +02:00
|
|
|
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
2022-11-22 10:10:08 +01:00
|
|
|
self,
|
|
|
|
|
seat,
|
|
|
|
|
¤t_output,
|
|
|
|
|
(&prev_output, None),
|
2023-05-25 00:10:24 +02:00
|
|
|
matches!(x, Action::MoveToPreviousOutput),
|
2023-05-25 17:51:53 +02:00
|
|
|
direction,
|
2022-11-22 10:10:08 +01:00
|
|
|
) {
|
|
|
|
|
if let Some(ptr) = seat.get_pointer() {
|
|
|
|
|
ptr.motion(
|
|
|
|
|
self,
|
|
|
|
|
None,
|
|
|
|
|
&MotionEvent {
|
2023-10-25 19:24:51 +02:00
|
|
|
location: new_pos.to_f64().as_logical(),
|
2022-11-22 10:10:08 +01:00
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-09-13 20:52:10 -07:00
|
|
|
ptr.frame(self);
|
2022-11-22 10:10:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-11-20 21:19:47 +01:00
|
|
|
Action::MigrateWorkspaceToNextOutput => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let active = self.common.shell.active_space(¤t_output).handle;
|
|
|
|
|
let next_output = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.outputs()
|
|
|
|
|
.skip_while(|o| *o != ¤t_output)
|
|
|
|
|
.skip(1)
|
|
|
|
|
.next()
|
|
|
|
|
.cloned();
|
|
|
|
|
if let Some(next_output) = next_output {
|
|
|
|
|
self.common
|
|
|
|
|
.shell
|
|
|
|
|
.migrate_workspace(¤t_output, &next_output, &active);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Action::MigrateWorkspaceToPreviousOutput => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let active = self.common.shell.active_space(¤t_output).handle;
|
|
|
|
|
let prev_output = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.outputs()
|
|
|
|
|
.rev()
|
|
|
|
|
.skip_while(|o| *o != ¤t_output)
|
|
|
|
|
.skip(1)
|
|
|
|
|
.next()
|
|
|
|
|
.cloned();
|
|
|
|
|
if let Some(prev_output) = prev_output {
|
|
|
|
|
self.common
|
|
|
|
|
.shell
|
|
|
|
|
.migrate_workspace(¤t_output, &prev_output, &active);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Action::MigrateWorkspaceToOutput(direction) => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let active = self.common.shell.active_space(¤t_output).handle;
|
|
|
|
|
let next_output = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.next_output(¤t_output, direction)
|
|
|
|
|
.cloned();
|
|
|
|
|
|
|
|
|
|
if let Some(next_output) = next_output {
|
|
|
|
|
self.common
|
|
|
|
|
.shell
|
|
|
|
|
.migrate_workspace(¤t_output, &next_output, &active);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
Action::Focus(focus) => {
|
2024-01-17 13:12:46 -08:00
|
|
|
let result = self.common.shell.next_focus(focus, seat);
|
2023-02-13 20:35:11 +01:00
|
|
|
|
|
|
|
|
match result {
|
2022-11-10 18:42:11 +01:00
|
|
|
FocusResult::None => {
|
2023-11-17 19:39:37 +01:00
|
|
|
let dir = match focus {
|
|
|
|
|
FocusDirection::Down => Some(Direction::Down),
|
|
|
|
|
FocusDirection::Up => Some(Direction::Up),
|
|
|
|
|
FocusDirection::Left => Some(Direction::Left),
|
|
|
|
|
FocusDirection::Right => Some(Direction::Right),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if let Some(direction) = dir {
|
|
|
|
|
self.handle_action(
|
|
|
|
|
Action::SwitchOutput(direction),
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
Some(direction),
|
2023-11-22 17:42:11 +01:00
|
|
|
true,
|
2023-11-17 19:39:37 +01:00
|
|
|
)
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FocusResult::Handled => {}
|
|
|
|
|
FocusResult::Some(target) => {
|
|
|
|
|
Common::set_focus(self, Some(&target), seat, None);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Action::Move(direction) => {
|
2023-12-22 15:48:05 +00:00
|
|
|
match self.common.shell.move_current_element(direction, seat) {
|
2023-11-17 19:39:37 +01:00
|
|
|
MoveResult::MoveFurther(_move_further) => self.handle_action(
|
|
|
|
|
Action::MoveToOutput(direction),
|
|
|
|
|
seat,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
pattern,
|
|
|
|
|
Some(direction),
|
2023-11-22 17:42:11 +01:00
|
|
|
true,
|
2023-11-17 19:39:37 +01:00
|
|
|
),
|
2023-06-12 17:23:54 +02:00
|
|
|
MoveResult::ShiftFocus(shift) => {
|
|
|
|
|
Common::set_focus(self, Some(&shift), seat, None);
|
2023-05-19 19:44:57 +02:00
|
|
|
}
|
2023-09-20 18:57:58 +02:00
|
|
|
_ => {
|
2023-12-22 15:48:05 +00:00
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space(¤t_output);
|
2023-06-12 17:23:54 +02:00
|
|
|
if let Some(focused_window) = workspace.focus_stack.get(seat).last() {
|
|
|
|
|
if workspace.is_tiled(focused_window) {
|
2023-08-11 18:15:22 +02:00
|
|
|
self.common.shell.set_overview_mode(
|
|
|
|
|
Some(Trigger::KeyboardMove(pattern.modifiers)),
|
|
|
|
|
self.common.event_loop_handle.clone(),
|
|
|
|
|
);
|
2023-06-12 17:23:54 +02:00
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-11 18:15:22 +02:00
|
|
|
Action::SwapWindow => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space_mut(¤t_output);
|
2023-10-25 19:41:30 +02:00
|
|
|
if workspace.get_fullscreen().is_some() {
|
2023-08-11 18:15:22 +02:00
|
|
|
return; // TODO, is this what we want? Maybe disengage fullscreen instead?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let keyboard_handle = seat.get_keyboard().unwrap();
|
|
|
|
|
if let Some(focus) = keyboard_handle.current_focus() {
|
|
|
|
|
if let Some(descriptor) = workspace.node_desc(focus) {
|
|
|
|
|
let grab = SwapWindowGrab::new(seat.clone(), descriptor.clone());
|
|
|
|
|
keyboard_handle.set_grab(grab, serial);
|
|
|
|
|
self.common.shell.set_overview_mode(
|
|
|
|
|
Some(Trigger::KeyboardSwap(pattern, descriptor)),
|
|
|
|
|
self.common.event_loop_handle.clone(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-27 13:47:59 +01:00
|
|
|
Action::Minimize => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space_mut(¤t_output);
|
|
|
|
|
let focus_stack = workspace.focus_stack.get(seat);
|
|
|
|
|
let focused_window = focus_stack.last().cloned();
|
|
|
|
|
if let Some(window) = focused_window {
|
|
|
|
|
self.common.shell.minimize_request(&window);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
Action::Maximize => {
|
|
|
|
|
let current_output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space_mut(¤t_output);
|
|
|
|
|
let focus_stack = workspace.focus_stack.get(seat);
|
2023-12-20 20:45:47 +00:00
|
|
|
let focused_window = focus_stack.last().cloned();
|
|
|
|
|
if let Some(window) = focused_window {
|
2024-02-23 17:25:40 +01:00
|
|
|
self.common.shell.maximize_toggle(&window, seat);
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-07-05 23:57:38 +02:00
|
|
|
Action::Resizing(direction) => self.common.shell.set_resize_mode(
|
|
|
|
|
Some((pattern, direction)),
|
|
|
|
|
&self.common.config,
|
|
|
|
|
self.common.event_loop_handle.clone(),
|
|
|
|
|
),
|
|
|
|
|
Action::_ResizingInternal(direction, edge, state) => {
|
|
|
|
|
if state == KeyState::Pressed {
|
2023-07-06 18:20:10 +02:00
|
|
|
self.common.shell.resize(seat, direction, edge);
|
2023-07-05 23:57:38 +02:00
|
|
|
} else {
|
2023-07-06 18:20:10 +02:00
|
|
|
self.common.shell.finish_resize(direction, edge);
|
2023-07-05 23:57:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
Action::ToggleOrientation => {
|
|
|
|
|
let output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space_mut(&output);
|
2023-05-30 21:02:19 +02:00
|
|
|
workspace.tiling_layer.update_orientation(None, &seat);
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
Action::Orientation(orientation) => {
|
|
|
|
|
let output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space_mut(&output);
|
2023-05-30 21:02:19 +02:00
|
|
|
workspace
|
|
|
|
|
.tiling_layer
|
|
|
|
|
.update_orientation(Some(orientation), &seat);
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
2023-06-05 17:52:47 +02:00
|
|
|
Action::ToggleStacking => {
|
2023-12-20 20:48:19 +00:00
|
|
|
if let Some(new_focus) = self.common.shell.toggle_stacking_focused(seat) {
|
2023-12-07 19:36:03 +00:00
|
|
|
Common::set_focus(self, Some(&new_focus), seat, Some(serial));
|
|
|
|
|
}
|
2023-06-05 17:52:47 +02:00
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
Action::ToggleTiling => {
|
2024-02-08 14:25:18 -05:00
|
|
|
if matches!(
|
|
|
|
|
self.common.config.cosmic_conf.autotile_behavior,
|
|
|
|
|
TileBehavior::Global
|
|
|
|
|
) {
|
|
|
|
|
let autotile = !self.common.config.cosmic_conf.autotile;
|
|
|
|
|
self.common.config.cosmic_conf.autotile = autotile;
|
|
|
|
|
let seats: Vec<_> = self.common.seats().cloned().collect();
|
|
|
|
|
let mut guard = self.common.shell.workspace_state.update();
|
|
|
|
|
self.common.shell.workspaces.update_autotile(
|
|
|
|
|
self.common.config.cosmic_conf.autotile,
|
|
|
|
|
&mut guard,
|
|
|
|
|
seats,
|
|
|
|
|
);
|
|
|
|
|
let config = self.common.config.cosmic_helper.clone();
|
|
|
|
|
thread::spawn(move || {
|
|
|
|
|
if let Err(err) = config.set("autotile", autotile) {
|
|
|
|
|
error!(?err, "Failed to update autotile key");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
let output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.workspaces.active_mut(&output);
|
|
|
|
|
let mut guard = self.common.shell.workspace_state.update();
|
|
|
|
|
workspace.toggle_tiling(seat, &mut guard);
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
Action::ToggleWindowFloating => {
|
|
|
|
|
let output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space_mut(&output);
|
2023-12-07 19:34:03 +00:00
|
|
|
workspace.toggle_floating_window_focused(seat);
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
2023-12-20 20:21:04 +00:00
|
|
|
Action::ToggleSticky => {
|
|
|
|
|
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
|
|
|
|
self.common.shell.toggle_sticky_current(seats.iter(), seat);
|
|
|
|
|
}
|
2022-11-10 18:42:11 +01:00
|
|
|
Action::Spawn(command) => {
|
2023-11-07 18:46:25 +01:00
|
|
|
let (token, data) = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.xdg_activation_state
|
|
|
|
|
.create_external_token(None);
|
|
|
|
|
let (token, data) = (token.clone(), data.clone());
|
|
|
|
|
|
|
|
|
|
let seat = self.common.last_active_seat();
|
|
|
|
|
let output = seat.active_output();
|
|
|
|
|
let workspace = self.common.shell.active_space_mut(&output);
|
|
|
|
|
workspace.pending_tokens.insert(token.clone());
|
|
|
|
|
let handle = workspace.handle;
|
|
|
|
|
data.user_data
|
|
|
|
|
.insert_if_missing(move || ActivationContext::Workspace(handle));
|
2023-05-24 16:12:44 +02:00
|
|
|
|
2023-11-07 18:46:25 +01:00
|
|
|
let wayland_display = self.common.socket.clone();
|
2023-05-24 16:12:44 +02:00
|
|
|
let display = self
|
|
|
|
|
.common
|
2023-11-22 12:44:11 +01:00
|
|
|
.shell
|
2023-05-24 16:12:44 +02:00
|
|
|
.xwayland_state
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| format!(":{}", s.display))
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
2023-11-07 18:46:25 +01:00
|
|
|
let mut cmd = std::process::Command::new("/bin/sh");
|
2023-05-24 16:12:44 +02:00
|
|
|
|
2023-11-07 18:46:25 +01:00
|
|
|
cmd.arg("-c")
|
|
|
|
|
.arg(command.clone())
|
|
|
|
|
.env("WAYLAND_DISPLAY", &wayland_display)
|
|
|
|
|
.env("DISPLAY", &display)
|
|
|
|
|
.env("XDG_ACTIVATION_TOKEN", &*token)
|
|
|
|
|
.env("DESKTOP_STARTUP_ID", &*token)
|
|
|
|
|
.env_remove("COSMIC_SESSION_SOCK");
|
2023-05-24 16:12:44 +02:00
|
|
|
|
2023-11-07 18:46:25 +01:00
|
|
|
std::thread::spawn(move || match cmd.spawn() {
|
|
|
|
|
Ok(mut child) => {
|
|
|
|
|
let _res = child.wait();
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
tracing::warn!(?err, "Failed to spawn \"{}\"", command);
|
2023-05-24 16:12:44 +02:00
|
|
|
}
|
|
|
|
|
});
|
2022-11-10 18:42:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 20:14:09 +01:00
|
|
|
pub fn surface_under(
|
2023-10-25 19:24:51 +02:00
|
|
|
global_pos: Point<f64, Global>,
|
2021-12-22 20:14:09 +01:00
|
|
|
output: &Output,
|
2023-12-20 20:24:13 +00:00
|
|
|
shell: &mut Shell,
|
2023-10-25 19:24:51 +02:00
|
|
|
) -> Option<(PointerFocusTarget, Point<i32, Global>)> {
|
2023-12-20 20:24:13 +00:00
|
|
|
let session_lock = shell.session_lock.as_ref();
|
2023-10-25 19:24:51 +02:00
|
|
|
let relative_pos = global_pos.to_local(output);
|
|
|
|
|
let output_geo = output.geometry();
|
|
|
|
|
|
2023-10-16 12:28:19 -07:00
|
|
|
if let Some(session_lock) = session_lock {
|
|
|
|
|
return session_lock.surfaces.get(output).map(|surface| {
|
|
|
|
|
(
|
|
|
|
|
PointerFocusTarget::LockSurface(surface.clone()),
|
|
|
|
|
output_geo.loc,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-20 20:24:13 +00:00
|
|
|
if let Some(window) = shell.workspaces.active_mut(output).get_fullscreen() {
|
2023-07-21 16:08:55 +02:00
|
|
|
let layers = layer_map_for_output(output);
|
2023-10-25 19:24:51 +02:00
|
|
|
if let Some(layer) = layers.layer_under(WlrLayer::Overlay, relative_pos.as_logical()) {
|
2022-04-22 15:18:28 +02:00
|
|
|
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
|
2022-11-11 23:23:38 +01:00
|
|
|
if layer
|
2023-10-25 19:24:51 +02:00
|
|
|
.surface_under(
|
|
|
|
|
relative_pos.as_logical() - layer_loc.to_f64(),
|
|
|
|
|
WindowSurfaceType::ALL,
|
|
|
|
|
)
|
2022-11-11 23:23:38 +01:00
|
|
|
.is_some()
|
|
|
|
|
{
|
2023-10-25 19:24:51 +02:00
|
|
|
return Some((layer.clone().into(), output_geo.loc + layer_loc.as_global()));
|
2022-11-11 23:23:38 +01:00
|
|
|
}
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
2023-12-20 20:24:13 +00:00
|
|
|
if let Some(or) = shell.override_redirect_windows.iter().find(|or| {
|
2023-10-25 19:24:51 +02:00
|
|
|
or.is_in_input_region(&(global_pos.as_logical() - or.geometry().loc.to_f64()))
|
|
|
|
|
}) {
|
|
|
|
|
return Some((or.clone().into(), or.geometry().loc.as_global()));
|
2023-01-27 19:51:23 +01:00
|
|
|
}
|
2022-11-11 23:23:38 +01:00
|
|
|
Some((window.clone().into(), output_geo.loc))
|
2021-12-22 20:14:09 +01:00
|
|
|
} else {
|
2022-04-22 15:18:28 +02:00
|
|
|
{
|
2023-07-21 16:08:55 +02:00
|
|
|
let layers = layer_map_for_output(output);
|
|
|
|
|
if let Some(layer) = layers
|
2023-10-25 19:24:51 +02:00
|
|
|
.layer_under(WlrLayer::Overlay, relative_pos.as_logical())
|
|
|
|
|
.or_else(|| layers.layer_under(WlrLayer::Top, relative_pos.as_logical()))
|
2022-11-11 23:23:38 +01:00
|
|
|
{
|
2023-07-21 16:08:55 +02:00
|
|
|
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
|
|
|
|
|
if layer
|
2023-10-25 19:24:51 +02:00
|
|
|
.surface_under(
|
|
|
|
|
relative_pos.as_logical() - layer_loc.to_f64(),
|
|
|
|
|
WindowSurfaceType::ALL,
|
|
|
|
|
)
|
2023-07-21 16:08:55 +02:00
|
|
|
.is_some()
|
|
|
|
|
{
|
2023-10-25 19:24:51 +02:00
|
|
|
return Some((
|
|
|
|
|
layer.clone().into(),
|
|
|
|
|
output_geo.loc + layer_loc.as_global(),
|
|
|
|
|
));
|
2023-07-21 16:08:55 +02:00
|
|
|
}
|
2022-11-11 23:23:38 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-12-20 20:24:13 +00:00
|
|
|
if let Some(or) = shell.override_redirect_windows.iter().find(|or| {
|
2023-10-25 19:24:51 +02:00
|
|
|
or.is_in_input_region(&(global_pos.as_logical() - or.geometry().loc.to_f64()))
|
|
|
|
|
}) {
|
|
|
|
|
return Some((or.clone().into(), or.geometry().loc.as_global()));
|
2023-01-23 20:32:37 +01:00
|
|
|
}
|
2023-12-20 20:24:13 +00:00
|
|
|
if let Some((target, loc)) = shell.element_under(global_pos, output) {
|
2023-10-25 19:24:51 +02:00
|
|
|
return Some((target, loc));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
let layers = layer_map_for_output(output);
|
|
|
|
|
if let Some(layer) = layers
|
|
|
|
|
.layer_under(WlrLayer::Bottom, relative_pos.as_logical())
|
|
|
|
|
.or_else(|| layers.layer_under(WlrLayer::Background, relative_pos.as_logical()))
|
2022-11-11 23:23:38 +01:00
|
|
|
{
|
2023-10-25 19:24:51 +02:00
|
|
|
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
|
|
|
|
|
if layer
|
|
|
|
|
.surface_under(
|
|
|
|
|
relative_pos.as_logical() - layer_loc.to_f64(),
|
|
|
|
|
WindowSurfaceType::ALL,
|
|
|
|
|
)
|
|
|
|
|
.is_some()
|
2023-07-21 16:08:55 +02:00
|
|
|
{
|
2023-10-25 19:24:51 +02:00
|
|
|
return Some((
|
|
|
|
|
layer.clone().into(),
|
|
|
|
|
output_geo.loc + layer_loc.as_global(),
|
|
|
|
|
));
|
2023-07-21 16:08:55 +02:00
|
|
|
}
|
2022-11-11 23:23:38 +01:00
|
|
|
}
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
2022-11-11 23:23:38 +01:00
|
|
|
None
|
2021-12-22 20:14:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
|
|
|
|
|
fn sessions_for_output(state: &Common, output: &Output) -> impl Iterator<Item = Session> {
|
|
|
|
|
let workspace = state.shell.active_space(&output);
|
2023-10-25 19:41:30 +02:00
|
|
|
let maybe_fullscreen = workspace.get_fullscreen();
|
2022-11-03 18:51:27 +01:00
|
|
|
workspace
|
|
|
|
|
.screencopy_sessions
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|s| (&**s).clone())
|
|
|
|
|
.chain(
|
|
|
|
|
maybe_fullscreen
|
2023-09-18 18:29:13 +02:00
|
|
|
.as_ref()
|
|
|
|
|
.and_then(|w| {
|
2023-10-25 19:41:30 +02:00
|
|
|
if let Some(sessions) = w.user_data().get::<ScreencopySessions>() {
|
2023-09-18 18:29:13 +02:00
|
|
|
Some(
|
|
|
|
|
sessions
|
|
|
|
|
.0
|
|
|
|
|
.borrow()
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|s| (&**s).clone())
|
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
})
|
|
|
|
|
.into_iter()
|
|
|
|
|
.flatten(),
|
|
|
|
|
)
|
|
|
|
|
.chain(
|
|
|
|
|
output
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<ScreencopySessions>()
|
|
|
|
|
.map(|sessions| {
|
|
|
|
|
sessions
|
|
|
|
|
.0
|
|
|
|
|
.borrow()
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|s| (&**s).clone())
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
})
|
|
|
|
|
.into_iter()
|
|
|
|
|
.into_iter()
|
|
|
|
|
.flatten(),
|
|
|
|
|
)
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.into_iter()
|
|
|
|
|
}
|
2023-12-28 13:36:59 -08:00
|
|
|
|
|
|
|
|
// TODO Is it possible to determine mapping for external touchscreen?
|
|
|
|
|
// Support map_to_region like sway?
|
|
|
|
|
fn mapped_output_for_device<'a, D: Device + 'static>(
|
|
|
|
|
state: &'a Common,
|
|
|
|
|
device: &D,
|
|
|
|
|
) -> Option<&'a Output> {
|
|
|
|
|
let map_to_output = if let Some(device) = <dyn Any>::downcast_ref::<InputDevice>(device) {
|
|
|
|
|
state
|
|
|
|
|
.config
|
|
|
|
|
.map_to_output(device)
|
|
|
|
|
.and_then(|name| state.shell.outputs().find(|output| output.name() == name))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
map_to_output.or_else(|| state.shell.builtin_output())
|
|
|
|
|
}
|