diff --git a/Cargo.lock b/Cargo.lock index e5501d76..089b7e3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4480,12 +4480,6 @@ dependencies = [ "regex", ] -[[package]] -name = "scan_fmt" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b53b0a5db882a8e2fdaae0a43f7b39e7e9082389e978398bdf223a55b581248" - [[package]] name = "scoped-tls" version = "1.0.1" @@ -4703,7 +4697,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay" version = "0.3.0" -source = "git+https://github.com/smithay//smithay?rev=f364c73#f364c73cae953aebfa189075e9f118f9008e100b" +source = "git+https://github.com/smithay//smithay?rev=08d31e1#08d31e17ea4ac47cddeb56e2ac18ee50b331911b" dependencies = [ "appendlist", "ash 0.38.0+1.3.281", @@ -4723,7 +4717,6 @@ dependencies = [ "glow 0.12.3", "indexmap 2.3.0", "input", - "lazy_static", "libc", "libloading 0.8.5", "libseat", @@ -4733,7 +4726,6 @@ dependencies = [ "profiling", "rand", "rustix", - "scan_fmt", "scopeguard", "smallvec", "tempfile", diff --git a/Cargo.toml b/Cargo.toml index 2e865a35..bb623462 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -116,4 +116,4 @@ inherits = "release" lto = "fat" [patch."https://github.com/Smithay/smithay.git"] -smithay = { git = "https://github.com/smithay//smithay", rev = "f364c73" } +smithay = { git = "https://github.com/smithay//smithay", rev = "08d31e1" } diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 279cacb7..7073b88b 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -165,7 +165,7 @@ fn init_libinput( state.backend.kms().input_devices.remove(device.name()); } - state.process_input_event(event, true); + state.process_input_event(event); for output in state.common.shell.read().unwrap().outputs() { state.backend.kms().schedule_render(output); diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 97f6d833..1bf3f527 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -320,7 +320,7 @@ impl State { render_ping.ping(); } WinitEvent::Redraw => render_ping.ping(), - WinitEvent::Input(event) => self.process_input_event(event, false), + WinitEvent::Input(event) => self.process_input_event(event), WinitEvent::CloseRequested => { self.common.should_stop = true; } diff --git a/src/backend/x11.rs b/src/backend/x11.rs index 50d0e03c..75096edd 100644 --- a/src/backend/x11.rs +++ b/src/backend/x11.rs @@ -515,7 +515,7 @@ impl State { _ => {} }; - self.process_input_event(event, false); + self.process_input_event(event); // TODO actually figure out the output for output in self.common.shell.read().unwrap().outputs() { self.backend.x11().schedule_render(output); diff --git a/src/config/mod.rs b/src/config/mod.rs index 73b0d346..4baef38c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -264,7 +264,9 @@ impl Config { .shell .write() .unwrap() - .update_tiling_exceptions(state.common.config.tiling_exceptions.iter()); + .update_tiling_exceptions( + state.common.config.tiling_exceptions.iter(), + ); } _ => (), } diff --git a/src/input/mod.rs b/src/input/mod.rs index 0e608117..3bcb3036 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -12,7 +12,10 @@ use crate::{ shell::{ focus::target::{KeyboardFocusTarget, PointerFocusTarget}, grabs::{ReleaseMode, ResizeEdge}, - layout::{floating::ResizeGrabMarker, tiling::TilingLayout}, + layout::{ + floating::ResizeGrabMarker, + tiling::{NodeDesc, TilingLayout}, + }, SeatExt, Trigger, }, utils::{prelude::*, quirks::workspace_overview_is_open}, @@ -32,16 +35,16 @@ use smithay::{ backend::input::{ AbsolutePositionEvent, Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend, - InputEvent, KeyState, PointerAxisEvent, ProximityState, TabletToolButtonEvent, - TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, - TouchEvent, + InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, ProximityState, + TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, + TabletToolTipState, TouchEvent, }, desktop::{ layer_map_for_output, space::SpaceElement, utils::under_from_surface_tree, WindowSurfaceType, }, input::{ - keyboard::{FilterResult, KeysymHandle}, + keyboard::{FilterResult, KeysymHandle, ModifiersState}, pointer::{ AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, @@ -156,11 +159,8 @@ impl ModifiersShortcutQueue { } impl State { - pub fn process_input_event( - &mut self, - event: InputEvent, - needs_key_repetition: bool, - ) where + pub fn process_input_event(&mut self, event: InputEvent) + where ::Device: 'static, { use smithay::backend::input::Event; @@ -196,8 +196,6 @@ impl State { InputEvent::Keyboard { event, .. } => { use smithay::backend::input::KeyboardKeyEvent; - let loop_handle = self.common.event_loop_handle.clone(); - let maybe_seat = self .common .shell @@ -209,18 +207,6 @@ impl State { if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - let current_focus = seat.get_keyboard().unwrap().current_focus(); - //this should fall back to active output since there may not be a focused output - let focused_output = seat.focused_or_active_output(); - - let shortcuts_inhibited = current_focus.is_some_and(|f| { - f.wl_surface() - .and_then(|surface| { - seat.keyboard_shortcuts_inhibitor_for_surface(&surface) - .map(|inhibitor| inhibitor.is_active()) - }) - .unwrap_or(false) - }); let keycode = event.key_code(); let state = event.state(); trace!(?keycode, ?state, "key"); @@ -228,314 +214,29 @@ impl State { let serial = SERIAL_COUNTER.next_serial(); let time = Event::time_msec(&event); let keyboard = seat.get_keyboard().unwrap(); - let pointer = seat.get_pointer().unwrap(); - let is_grabbed = keyboard.is_grabbed() || pointer.is_grabbed(); - let current_focus = keyboard.current_focus(); - let shell_ref = self.common.shell.clone(); - let mut shell = shell_ref.write().unwrap(); if let Some((action, pattern)) = keyboard - .input( - self, - keycode, - state, - serial, - time, - |data, modifiers, handle| { - // Leave move overview mode, if any modifier was released - if let Some(Trigger::KeyboardMove(action_modifiers)) = - shell.overview_mode().0.active_trigger() - { - if (action_modifiers.ctrl && !modifiers.ctrl) - || (action_modifiers.alt && !modifiers.alt) - || (action_modifiers.logo && !modifiers.logo) - || (action_modifiers.shift && !modifiers.shift) - { - shell.set_overview_mode(None, data.common.event_loop_handle.clone()); - } - } - // Leave swap overview mode, if any key was released - if let Some(Trigger::KeyboardSwap(action_pattern, old_descriptor)) = - shell.overview_mode().0.active_trigger() - { - 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) - || (action_pattern.key.is_some() && handle.raw_syms().contains(&action_pattern.key.unwrap()) && state == KeyState::Released) - { - shell.set_overview_mode(None, data.common.event_loop_handle.clone()); - - if let Some(focus) = current_focus { - if let Some(new_descriptor) = shell.workspaces.active(&focused_output).1.node_desc(focus) { - let mut spaces = shell.workspaces.spaces_mut(); - if old_descriptor.handle != new_descriptor.handle { - let (mut old_w, mut other_w) = spaces.partition::, _>(|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_descriptor.handle) { - { - let mut stack = new_workspace.focus_stack.get_mut(&seat); - for elem in old_descriptor.focus_stack.iter().flat_map(|node_id| { - old_workspace.tiling_layer.element_for_node(node_id) - }) { - stack.append(elem); - } - } - { - let mut stack = old_workspace.focus_stack.get_mut(&seat); - for elem in new_descriptor.focus_stack.iter().flat_map(|node_id| { - new_workspace.tiling_layer.element_for_node(node_id) - }) { - stack.append(elem); - } - } - if let Some(focus) = TilingLayout::swap_trees(&mut old_workspace.tiling_layer, Some(&mut new_workspace.tiling_layer), &old_descriptor, &new_descriptor) { - let seat = seat.clone(); - data.common.event_loop_handle.insert_idle(move |state| { - Shell::set_focus(state, Some(&focus), &seat, None,true); - }); - } - old_workspace.refresh_focus_stack(); - new_workspace.refresh_focus_stack(); - } - } - } else { - 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) { - std::mem::drop(spaces); - let seat = seat.clone(); - data.common.event_loop_handle.insert_idle(move |state| { - Shell::set_focus(state, Some(&focus), &seat, None,true); - }); - } - workspace.refresh_focus_stack(); - } - } - } - } else { - let new_workspace = shell.workspaces.active(&focused_output).1.handle; - if new_workspace != old_descriptor.handle { - let spaces = shell.workspaces.spaces_mut(); - let (mut old_w, mut other_w) = spaces.partition::, _>(|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() { - { - let mut stack = new_workspace.focus_stack.get_mut(&seat); - for elem in old_descriptor.focus_stack.iter().flat_map(|node_id| { - old_workspace.tiling_layer.element_for_node(node_id) - }) { - stack.append(elem); - } - } - 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.clone(), None) { - let seat = seat.clone(); - data.common.event_loop_handle.insert_idle(move |state| { - Shell::set_focus(state, Some(&focus), &seat, None,true); - }); - } - old_workspace.refresh_focus_stack(); - } - } - } - } - } - } - } - - // Leave or update resize mode, if modifiers changed or initial key was released - if let Some(action_pattern) = - shell.resize_mode().0.active_binding() - { - if action_pattern.key.is_some() && state == KeyState::Released - && handle.raw_syms().contains(&action_pattern.key.unwrap()) - { - shell.set_resize_mode(None, &data.common.config, data.common.event_loop_handle.clone()); - } else if !cosmic_modifiers_eq_smithay(&action_pattern.modifiers, modifiers) { - let mut new_pattern = action_pattern.clone(); - new_pattern.modifiers = cosmic_modifiers_from_smithay(modifiers.clone()); - let enabled = data - .common - .config - .shortcuts - .iter() - .find_map(move |(binding, action)| { - if binding == &new_pattern - && matches!(action, shortcuts::Action::Resizing(_)) - { - let shortcuts::Action::Resizing(direction) = action else { unreachable!() }; - Some((new_pattern.clone(), *direction)) - } else { - None - } - }); - shell.set_resize_mode(enabled, &data.common.config, data.common.event_loop_handle.clone()); - } - } - - // Special case resizing with regards to arrow keys - if let Some(direction) = - shell.resize_mode().0.active_direction() - { - let resize_edge = match handle.modified_sym() { - 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), - _ => None, - }; - - if let Some(mut edge) = resize_edge { - if direction == ResizeDirection::Inwards { - edge.flip_direction(); - } - let action = Action::Private(PrivateAction::Resizing(direction, edge.into(), cosmic_keystate_from_smithay(state))); - let key_pattern = shortcuts::Binding { - modifiers: cosmic_modifiers_from_smithay(modifiers.clone()), - key: Some(Keysym::new(handle.raw_code().raw())), - description: None, - }; - - if state == KeyState::Released { - if let Some(tokens) = seat.supressed_keys().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(); - loop_handle.insert_source(Timer::from_duration(Duration::from_millis(200)), move |current, _, state| { - let duration = current.duration_since(start).as_millis(); - state.handle_action(action_clone.clone(), &seat_clone, serial, time.overflowing_add(duration as u32).0, key_pattern_clone.clone(), None, true); - calloop::timer::TimeoutAction::ToDuration(Duration::from_millis(25)) - }).ok() - } else { None }; - - seat.supressed_keys() - .add(&handle, token); - } - return FilterResult::Intercept(Some(( - action, - key_pattern - ))); - } - } - - std::mem::drop(shell); - - // cancel grabs - if is_grabbed - && handle.modified_sym() == Keysym::Escape - && state == KeyState::Pressed - && !modifiers.alt - && !modifiers.ctrl - && !modifiers.logo - && !modifiers.shift - { - seat.supressed_keys() - .add(&handle, None); - return FilterResult::Intercept(Some(( - Action::Private(PrivateAction::Escape), - shortcuts::Binding { - modifiers: shortcuts::Modifiers::default(), - key: Some(Keysym::Escape), - description: None, - } - ))); - } - - // Skip released events for initially surpressed keys - if state == KeyState::Released { - if let Some(tokens) = seat.supressed_keys().filter(&handle) { - for token in tokens { - loop_handle.remove(token); - } - return FilterResult::Intercept(None); - } - } - - // Handle VT switches - if state == KeyState::Pressed - && (Keysym::XF86_Switch_VT_1.raw() ..= Keysym::XF86_Switch_VT_12.raw()) - .contains(&handle.modified_sym().raw()) - { - if let Err(err) = data.backend.kms().switch_vt( - (handle.modified_sym().raw() - Keysym::XF86_Switch_VT_1.raw() - + 1) - as i32, - ) { - error!(?err, "Failed switching virtual terminal."); - } - seat.supressed_keys().add(&handle, None); - return FilterResult::Intercept(None); - } - - // handle the rest of the global shortcuts - let mut clear_queue = true; - if !shortcuts_inhibited { - let modifiers_queue = seat.modifiers_shortcut_queue(); - - for (binding, action) in - data.common.config.shortcuts.iter() - { - if *action == shortcuts::Action::Disable { - continue; - } - - // is this a released (triggered) modifier-only binding? - if binding.key.is_none() - && state == KeyState::Released - && !cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers) - && modifiers_queue.take(binding) - { - modifiers_queue.clear(); - return FilterResult::Intercept(Some(( - Action::Shortcut(action.clone()), - binding.clone(), - ))); - } - - // could this potentially become a modifier-only binding? - if binding.key.is_none() && state == KeyState::Pressed && cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers) { - modifiers_queue.set(binding.clone()); - clear_queue = false; - } - - // is this a normal binding? - if binding.key.is_some() - && state == KeyState::Pressed - && handle.raw_syms().contains(&binding.key.unwrap()) - && cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers) - { - modifiers_queue.clear(); - seat.supressed_keys().add(&handle, None); - return FilterResult::Intercept(Some(( - Action::Shortcut(action.clone()), - binding.clone(), - ))); - } - } - } - - // no binding - if clear_queue { - seat.modifiers_shortcut_queue().clear(); - } - // keys are passed through to apps - FilterResult::Forward - }, - ) - .flatten() - { - if pattern.key.is_none() && state == KeyState::Released { - // we still want to send release-events and not have apps stuck on some modifiers. - keyboard.input(self, keycode, state, serial, time, |_, _, _| FilterResult::<()>::Forward); - } - self.handle_action(action, &seat, serial, time, pattern, None, true) + .input( + self, + keycode, + state, + serial, + time, + |data, modifiers, handle| { + Self::filter_keyboard_input( + data, &event, &seat, modifiers, handle, serial, + ) + }, + ) + .flatten() + { + if pattern.key.is_none() && state == KeyState::Released { + // we still want to send release-events and not have apps stuck on some modifiers. + keyboard.input(self, keycode, state, serial, time, |_, _, _| { + FilterResult::<()>::Forward + }); } + self.handle_action(action, &seat, serial, time, pattern, None, true) + } } } @@ -1721,6 +1422,386 @@ impl State { } } + /// Determine is key event should be intercepted as a key binding, or forwarded to surface + pub fn filter_keyboard_input>( + &mut self, + event: &E, + seat: &Seat, + modifiers: &ModifiersState, + handle: KeysymHandle<'_>, + serial: Serial, + ) -> FilterResult> { + let mut shell = self.common.shell.write().unwrap(); + + let keyboard = seat.get_keyboard().unwrap(); + let pointer = seat.get_pointer().unwrap(); + let is_grabbed = keyboard.is_grabbed() || pointer.is_grabbed(); + + let current_focus = keyboard.current_focus(); + //this should fall back to active output since there may not be a focused output + let focused_output = seat.focused_or_active_output(); + + let shortcuts_inhibited = current_focus.as_ref().is_some_and(|f| { + f.wl_surface() + .and_then(|surface| { + seat.keyboard_shortcuts_inhibitor_for_surface(&surface) + .map(|inhibitor| inhibitor.is_active()) + }) + .unwrap_or(false) + }); + + // Leave move overview mode, if any modifier was released + if let Some(Trigger::KeyboardMove(action_modifiers)) = + shell.overview_mode().0.active_trigger() + { + if (action_modifiers.ctrl && !modifiers.ctrl) + || (action_modifiers.alt && !modifiers.alt) + || (action_modifiers.logo && !modifiers.logo) + || (action_modifiers.shift && !modifiers.shift) + { + shell.set_overview_mode(None, self.common.event_loop_handle.clone()); + } + } + // Leave swap overview mode, if any key was released + if let Some(Trigger::KeyboardSwap(action_pattern, old_descriptor)) = + shell.overview_mode().0.active_trigger() + { + 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) + || (action_pattern.key.is_some() + && handle.raw_syms().contains(&action_pattern.key.unwrap()) + && event.state() == KeyState::Released) + { + shell.set_overview_mode(None, self.common.event_loop_handle.clone()); + + self.keyboard_swap( + seat, + &mut shell, + old_descriptor, + current_focus, + &focused_output, + ); + } + } + + // Leave or update resize mode, if modifiers changed or initial key was released + if let Some(action_pattern) = shell.resize_mode().0.active_binding() { + if action_pattern.key.is_some() + && event.state() == KeyState::Released + && handle.raw_syms().contains(&action_pattern.key.unwrap()) + { + shell.set_resize_mode( + None, + &self.common.config, + self.common.event_loop_handle.clone(), + ); + } else if !cosmic_modifiers_eq_smithay(&action_pattern.modifiers, modifiers) { + let mut new_pattern = action_pattern.clone(); + new_pattern.modifiers = cosmic_modifiers_from_smithay(modifiers.clone()); + let enabled = + self.common + .config + .shortcuts + .iter() + .find_map(move |(binding, action)| { + if binding == &new_pattern + && matches!(action, shortcuts::Action::Resizing(_)) + { + let shortcuts::Action::Resizing(direction) = action else { + unreachable!() + }; + Some((new_pattern.clone(), *direction)) + } else { + None + } + }); + shell.set_resize_mode( + enabled, + &self.common.config, + self.common.event_loop_handle.clone(), + ); + } + } + + // Special case resizing with regards to arrow keys + if let Some(direction) = shell.resize_mode().0.active_direction() { + let resize_edge = match handle.modified_sym() { + 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), + _ => None, + }; + + if let Some(mut edge) = resize_edge { + if direction == ResizeDirection::Inwards { + edge.flip_direction(); + } + let action = Action::Private(PrivateAction::Resizing( + direction, + edge.into(), + cosmic_keystate_from_smithay(event.state()), + )); + let key_pattern = shortcuts::Binding { + modifiers: cosmic_modifiers_from_smithay(modifiers.clone()), + key: Some(handle.modified_sym()), + description: None, + }; + + if event.state() == KeyState::Released { + if let Some(tokens) = seat.supressed_keys().filter(&handle) { + for token in tokens { + self.common.event_loop_handle.remove(token); + } + } + } else { + let seat_clone = seat.clone(); + let action_clone = action.clone(); + let key_pattern_clone = key_pattern.clone(); + let start = Instant::now(); + let time = event.time_msec(); + let token = self + .common + .event_loop_handle + .insert_source( + Timer::from_duration(Duration::from_millis(200)), + move |current, _, state| { + let duration = current.duration_since(start).as_millis(); + state.handle_action( + action_clone.clone(), + &seat_clone, + serial, + time.overflowing_add(duration as u32).0, + key_pattern_clone.clone(), + None, + true, + ); + calloop::timer::TimeoutAction::ToDuration(Duration::from_millis(25)) + }, + ) + .ok(); + + seat.supressed_keys().add(&handle, token); + } + return FilterResult::Intercept(Some((action, key_pattern))); + } + } + + std::mem::drop(shell); + + // cancel grabs + if is_grabbed + && handle.modified_sym() == Keysym::Escape + && event.state() == KeyState::Pressed + && !modifiers.alt + && !modifiers.ctrl + && !modifiers.logo + && !modifiers.shift + { + seat.supressed_keys().add(&handle, None); + return FilterResult::Intercept(Some(( + Action::Private(PrivateAction::Escape), + shortcuts::Binding { + modifiers: shortcuts::Modifiers::default(), + key: Some(Keysym::Escape), + description: None, + }, + ))); + } + + // Skip released events for initially surpressed keys + if event.state() == KeyState::Released { + if let Some(tokens) = seat.supressed_keys().filter(&handle) { + for token in tokens { + self.common.event_loop_handle.remove(token); + } + return FilterResult::Intercept(None); + } + } + + // Handle VT switches + if event.state() == KeyState::Pressed + && (Keysym::XF86_Switch_VT_1.raw()..=Keysym::XF86_Switch_VT_12.raw()) + .contains(&handle.modified_sym().raw()) + { + if let Err(err) = self.backend.kms().switch_vt( + (handle.modified_sym().raw() - Keysym::XF86_Switch_VT_1.raw() + 1) as i32, + ) { + error!(?err, "Failed switching virtual terminal."); + } + seat.supressed_keys().add(&handle, None); + return FilterResult::Intercept(None); + } + + // handle the rest of the global shortcuts + let mut clear_queue = true; + if !shortcuts_inhibited { + let modifiers_queue = seat.modifiers_shortcut_queue(); + + for (binding, action) in self.common.config.shortcuts.iter() { + if *action == shortcuts::Action::Disable { + continue; + } + + // is this a released (triggered) modifier-only binding? + if binding.key.is_none() + && event.state() == KeyState::Released + && !cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers) + && modifiers_queue.take(binding) + { + modifiers_queue.clear(); + return FilterResult::Intercept(Some(( + Action::Shortcut(action.clone()), + binding.clone(), + ))); + } + + // could this potentially become a modifier-only binding? + if binding.key.is_none() + && event.state() == KeyState::Pressed + && cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers) + { + modifiers_queue.set(binding.clone()); + clear_queue = false; + } + + // is this a normal binding? + if binding.key.is_some() + && event.state() == KeyState::Pressed + && handle.raw_syms().contains(&binding.key.unwrap()) + && cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers) + { + modifiers_queue.clear(); + seat.supressed_keys().add(&handle, None); + return FilterResult::Intercept(Some(( + Action::Shortcut(action.clone()), + binding.clone(), + ))); + } + } + } + + // no binding + if clear_queue { + seat.modifiers_shortcut_queue().clear(); + } + // keys are passed through to apps + FilterResult::Forward + } + + fn keyboard_swap( + &self, + seat: &Seat, + shell: &mut Shell, + old_descriptor: &NodeDesc, + current_focus: Option, + focused_output: &Output, + ) { + if let Some(focus) = current_focus { + if let Some(new_descriptor) = + shell.workspaces.active(&focused_output).1.node_desc(focus) + { + let mut spaces = shell.workspaces.spaces_mut(); + if old_descriptor.handle != new_descriptor.handle { + let (mut old_w, mut other_w) = + spaces.partition::, _>(|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_descriptor.handle) + { + { + let mut stack = new_workspace.focus_stack.get_mut(&seat); + for elem in old_descriptor.focus_stack.iter().flat_map(|node_id| { + old_workspace.tiling_layer.element_for_node(node_id) + }) { + stack.append(elem); + } + } + { + let mut stack = old_workspace.focus_stack.get_mut(&seat); + for elem in new_descriptor.focus_stack.iter().flat_map(|node_id| { + new_workspace.tiling_layer.element_for_node(node_id) + }) { + stack.append(elem); + } + } + if let Some(focus) = TilingLayout::swap_trees( + &mut old_workspace.tiling_layer, + Some(&mut new_workspace.tiling_layer), + &old_descriptor, + &new_descriptor, + ) { + let seat = seat.clone(); + self.common.event_loop_handle.insert_idle(move |state| { + Shell::set_focus(state, Some(&focus), &seat, None, true); + }); + } + old_workspace.refresh_focus_stack(); + new_workspace.refresh_focus_stack(); + } + } + } else { + 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, + ) { + std::mem::drop(spaces); + let seat = seat.clone(); + self.common.event_loop_handle.insert_idle(move |state| { + Shell::set_focus(state, Some(&focus), &seat, None, true); + }); + } + workspace.refresh_focus_stack(); + } + } + } + } else { + let new_workspace = shell.workspaces.active(&focused_output).1.handle; + if new_workspace != old_descriptor.handle { + let spaces = shell.workspaces.spaces_mut(); + let (mut old_w, mut other_w) = + spaces.partition::, _>(|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() { + { + let mut stack = new_workspace.focus_stack.get_mut(&seat); + for elem in old_descriptor.focus_stack.iter().flat_map(|node_id| { + old_workspace.tiling_layer.element_for_node(node_id) + }) { + stack.append(elem); + } + } + 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.clone(), + None, + ) { + let seat = seat.clone(); + self.common.event_loop_handle.insert_idle(move |state| { + Shell::set_focus(state, Some(&focus), &seat, None, true); + }); + } + old_workspace.refresh_focus_stack(); + } + } + } + } + } + } + // TODO: Try to get rid of the *mutable* Shell references (needed for hovered_stack in floating_layout) pub fn surface_under( global_pos: Point, diff --git a/src/shell/layout/mod.rs b/src/shell/layout/mod.rs index 93e5f677..852a75ce 100644 --- a/src/shell/layout/mod.rs +++ b/src/shell/layout/mod.rs @@ -63,7 +63,7 @@ pub struct TilingExceptions { impl TilingExceptions { pub fn new<'a, I>(exceptions_config: I) -> Self where - I: Iterator + I: Iterator, { let mut app_ids = Vec::new(); let mut titles = Vec::new(); diff --git a/src/shell/layout/tiling/grabs/swap.rs b/src/shell/layout/tiling/grabs/swap.rs index a0004eef..28036ced 100644 --- a/src/shell/layout/tiling/grabs/swap.rs +++ b/src/shell/layout/tiling/grabs/swap.rs @@ -1,6 +1,6 @@ use cosmic_settings_config::shortcuts; use smithay::{ - backend::input::KeyState, + backend::input::{KeyState, Keycode}, input::{ keyboard::{ GrabStartData as KeyboardGrabStartData, KeyboardGrab, KeyboardInnerHandle, @@ -10,7 +10,6 @@ use smithay::{ }, utils::Serial, }; -use xkbcommon::xkb::Keysym; use crate::{ config::key_bindings::cosmic_modifiers_from_smithay, @@ -34,7 +33,7 @@ impl KeyboardGrab for SwapWindowGrab { &mut self, data: &mut State, handle: &mut KeyboardInnerHandle<'_, State>, - keycode: u32, + keycode: Keycode, state: KeyState, modifiers: Option, serial: Serial, @@ -81,7 +80,7 @@ impl KeyboardGrab for SwapWindowGrab { modifiers: modifiers .map(cosmic_modifiers_from_smithay) .unwrap_or_default(), - key: Some(Keysym::new(keycode)), + key: Some(handle.keysym_handle(keycode).modified_sym()), description: None, }, None,