Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/handlers/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,34 @@ impl CompositorHandler for State {
return;
}

for popup in self
.niri
.input_method_v1_popups
.iter()
.filter(|p| p.alive())
{
let mut popup_root = popup.wl_surface().clone();
while let Some(parent) = get_parent(&popup_root) {
popup_root = parent;
}

if popup_root != root_surface {
continue;
}

if let Some(parent) = popup.get_parent().map(|parent| parent.surface.clone()) {
let mut parent_root = parent;
while let Some(next) = get_parent(&parent_root) {
parent_root = next;
}

if let Some(output) = self.niri.output_for_root(&parent_root) {
self.niri.queue_redraw(&output.clone());
return;
}
}
}

// This might be a layer-shell surface.
if self.layer_shell_handle_commit(surface) {
return;
Expand Down
111 changes: 105 additions & 6 deletions src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ use smithay::wayland::fractional_scale::FractionalScaleHandler;
use smithay::wayland::idle_inhibit::IdleInhibitHandler;
use smithay::wayland::idle_notify::{IdleNotifierHandler, IdleNotifierState};
use smithay::wayland::input_method::{InputMethodHandler, PopupSurface};
use smithay::wayland::input_method_v1::{
InputMethodV1Handler, PopupSurface as InputMethodPopupSurfaceV1,
};
use smithay::wayland::keyboard_shortcuts_inhibit::{
KeyboardShortcutsInhibitHandler, KeyboardShortcutsInhibitState, KeyboardShortcutsInhibitor,
};
Expand Down Expand Up @@ -64,11 +67,12 @@ use smithay::{
delegate_cursor_shape, delegate_data_control, delegate_data_device, delegate_dmabuf,
delegate_drm_lease, delegate_ext_data_control, delegate_fractional_scale,
delegate_idle_inhibit, delegate_idle_notify, delegate_input_method_manager,
delegate_keyboard_shortcuts_inhibit, delegate_output, delegate_pointer_constraints,
delegate_pointer_gestures, delegate_presentation, delegate_primary_selection,
delegate_relative_pointer, delegate_seat, delegate_security_context, delegate_session_lock,
delegate_single_pixel_buffer, delegate_tablet_manager, delegate_text_input_manager,
delegate_viewporter, delegate_xdg_activation,
delegate_input_method_manager_v1, delegate_keyboard_shortcuts_inhibit, delegate_output,
delegate_pointer_constraints, delegate_pointer_gestures, delegate_presentation,
delegate_primary_selection, delegate_relative_pointer, delegate_seat,
delegate_security_context, delegate_session_lock, delegate_single_pixel_buffer,
delegate_tablet_manager, delegate_text_input_manager, delegate_viewporter,
delegate_xdg_activation,
};

pub use crate::handlers::xdg_shell::KdeDecorationsModeState;
Expand Down Expand Up @@ -249,14 +253,108 @@ impl InputMethodHandler for State {
}

fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical> {
let mut root = parent.clone();
while let Some(next) = get_parent(&root) {
root = next;
}

self.niri
.layout
.find_window_and_output(parent)
.find_window_and_output(&root)
.map(|(mapped, _)| mapped.window.geometry())
.unwrap_or_default()
}
}

impl InputMethodV1Handler for State {
fn new_popup(&mut self, surface: InputMethodPopupSurfaceV1) {
if let Some(parent) = surface.get_parent().map(|parent| parent.surface.clone()) {
let mut root = parent;
while let Some(next) = get_parent(&root) {
root = next;
}

if let Some(output) = self.niri.output_for_root(&root) {
let scale = output.current_scale();
let transform = output.current_transform();
let wl_surface = surface.wl_surface();
with_states(wl_surface, |data| {
send_scale_transform(wl_surface, data, scale, transform);
});
}
}

self.niri
.input_method_v1_popups
.retain(|p| p.alive() && p.wl_surface() != surface.wl_surface());
self.niri.input_method_v1_popups.push(surface);
self.niri.queue_redraw_all();
}

fn popup_repositioned(&mut self, surface: InputMethodPopupSurfaceV1) {
self.niri
.input_method_v1_popups
.retain(|p| p.alive() && p.wl_surface() != surface.wl_surface());
self.niri.input_method_v1_popups.push(surface);
self.niri.queue_redraw_all();
}

fn dismiss_popup(&mut self, surface: InputMethodPopupSurfaceV1) {
self.niri
.input_method_v1_popups
.retain(|p| p.wl_surface() != surface.wl_surface());
self.niri.queue_redraw_all();
}

fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical> {
self.input_method_parent_geometry(parent)
}
}

impl State {
fn input_method_parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical> {
let mut root = parent.clone();
while let Some(next) = get_parent(&root) {
root = next;
}

let Some((mapped, output)) = self.niri.layout.find_window_and_output(&root) else {
return Rectangle::default();
};

let window_geometry = mapped.window.geometry();
let window = mapped.window.clone();
let Some(output) = output.cloned() else {
return window_geometry;
};

let Some(mon) = self.niri.layout.monitor_for_output(&output) else {
return window_geometry;
};
let Some((ws, ws_geo)) = mon
.workspaces_with_render_geo()
.find(|(ws, _)| ws.has_window(&window))
else {
return window_geometry;
};
let Some((tile, tile_offset, _)) = ws
.tiles_with_render_positions()
.find(|(tile, _, _)| tile.window().window == window)
else {
return window_geometry;
};

let zoom = mon.overview_zoom();
let Some(output_geo) = self.niri.global_space.output_geometry(&output) else {
return window_geometry;
};

let loc =
output_geo.loc.to_f64() + ws_geo.loc + tile_offset.upscale(zoom) + tile.window_loc();
Rectangle::new(loc.to_i32_round(), window_geometry.size)
}
}

impl KeyboardShortcutsInhibitHandler for State {
fn keyboard_shortcuts_inhibit_state(&mut self) -> &mut KeyboardShortcutsInhibitState {
&mut self.niri.keyboard_shortcuts_inhibit_state
Expand All @@ -278,6 +376,7 @@ impl KeyboardShortcutsInhibitHandler for State {
}

delegate_input_method_manager!(State);
delegate_input_method_manager_v1!(State);
delegate_keyboard_shortcuts_inhibit!(State);

impl SelectionHandler for State {
Expand Down
39 changes: 38 additions & 1 deletion src/niri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ use smithay::utils::{
Transform, SERIAL_COUNTER,
};
use smithay::wayland::compositor::{
with_states, with_surface_tree_downward, CompositorClientState, CompositorHandler,
get_parent, with_states, with_surface_tree_downward, CompositorClientState, CompositorHandler,
CompositorState, HookId, SurfaceData, TraversalAction,
};
use smithay::wayland::cursor_shape::CursorShapeManagerState;
Expand All @@ -80,6 +80,8 @@ use smithay::wayland::fractional_scale::FractionalScaleManagerState;
use smithay::wayland::idle_inhibit::IdleInhibitManagerState;
use smithay::wayland::idle_notify::IdleNotifierState;
use smithay::wayland::input_method::InputMethodManagerState;
use smithay::wayland::input_method_v1::InputMethodV1ManagerState;
use smithay::wayland::input_method_v1::PopupSurface as InputMethodPopupSurfaceV1;
use smithay::wayland::keyboard_shortcuts_inhibit::{
KeyboardShortcutsInhibitState, KeyboardShortcutsInhibitor,
};
Expand Down Expand Up @@ -286,6 +288,7 @@ pub struct Niri {
pub tablet_state: TabletManagerState,
pub text_input_state: TextInputManagerState,
pub input_method_state: InputMethodManagerState,
pub input_method_v1_state: InputMethodV1ManagerState,
pub keyboard_shortcuts_inhibit_state: KeyboardShortcutsInhibitState,
pub virtual_keyboard_state: VirtualKeyboardManagerState,
pub virtual_pointer_state: VirtualPointerManagerState,
Expand All @@ -299,6 +302,7 @@ pub struct Niri {
pub wlr_data_control_state: WlrDataControlState,
pub ext_data_control_state: ExtDataControlState,
pub popups: PopupManager,
pub input_method_v1_popups: Vec<InputMethodPopupSurfaceV1>,
pub popup_grab: Option<PopupGrabState>,
pub presentation_state: PresentationState,
pub security_context_state: SecurityContextState,
Expand Down Expand Up @@ -2269,6 +2273,8 @@ impl Niri {
let text_input_state = TextInputManagerState::new::<State>(&display_handle);
let input_method_state =
InputMethodManagerState::new::<State, _>(&display_handle, client_is_unrestricted);
let input_method_v1_state =
InputMethodV1ManagerState::new::<State, _>(&display_handle, client_is_unrestricted);
let keyboard_shortcuts_inhibit_state =
KeyboardShortcutsInhibitState::new::<State>(&display_handle);
let virtual_keyboard_state =
Expand Down Expand Up @@ -2471,6 +2477,7 @@ impl Niri {
xdg_foreign_state,
text_input_state,
input_method_state,
input_method_v1_state,
keyboard_shortcuts_inhibit_state,
virtual_keyboard_state,
virtual_pointer_state,
Expand All @@ -2490,6 +2497,7 @@ impl Niri {
wlr_data_control_state,
ext_data_control_state,
popups: PopupManager::default(),
input_method_v1_popups: Vec::new(),
popup_grab: None,
suppressed_keys: HashSet::new(),
suppressed_buttons: HashSet::new(),
Expand Down Expand Up @@ -4074,6 +4082,35 @@ impl Niri {
self.render_pointer(renderer, output, &mut |elem| push(elem.into()));
}

// input-method-v1 popups (candidate window / panel), below the pointer.
for popup in self.input_method_v1_popups.iter().filter(|p| p.alive()) {
let Some(parent) = popup.get_parent() else {
continue;
};

let mut root = parent.surface.clone();
while let Some(next) = get_parent(&root) {
root = next;
}

if self.output_for_root(&root) != Some(output) {
continue;
}

let location = (parent.location.loc + popup.location())
.to_f64()
.to_physical_precise_round(output_scale);
push_elements_from_surface_tree(
renderer,
popup.wl_surface(),
location,
output_scale,
1.,
Kind::ScanoutCandidate,
&mut |elem| push(elem.into()),
);
}

// Next, the screen transition texture.
{
let state = self.output_state.get(output).unwrap();
Expand Down
104 changes: 1 addition & 103 deletions src/protocols/virtual_keyboard.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
use smithay::backend::input::{
Device, DeviceCapability, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, Keycode,
UnusedEvent,
};
use smithay::backend::input::{Device, DeviceCapability};
use smithay::delegate_virtual_keyboard_manager;
use smithay::input::keyboard::xkb::ModMask;
use smithay::input::keyboard::KeyboardHandle;
use smithay::wayland::virtual_keyboard::VirtualKeyboardHandler;

use crate::niri::State;

pub struct VirtualKeyboardInputBackend;

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct VirtualKeyboard;

Expand All @@ -35,98 +27,4 @@ impl Device for VirtualKeyboard {
None
}
}

pub struct VirtualKeyboardKeyEvent {
pub keycode: Keycode,
pub state: KeyState,
pub time: u32,
}

impl Event<VirtualKeyboardInputBackend> for VirtualKeyboardKeyEvent {
fn time(&self) -> u64 {
self.time as u64 * 1000 // millis to micros
}

fn device(&self) -> VirtualKeyboard {
VirtualKeyboard
}
}

impl KeyboardKeyEvent<VirtualKeyboardInputBackend> for VirtualKeyboardKeyEvent {
fn key_code(&self) -> Keycode {
self.keycode
}

fn state(&self) -> KeyState {
self.state
}

fn count(&self) -> u32 {
0 // Not used by niri
}
}

impl InputBackend for VirtualKeyboardInputBackend {
type Device = VirtualKeyboard;

type KeyboardKeyEvent = VirtualKeyboardKeyEvent;
type PointerAxisEvent = UnusedEvent;
type PointerButtonEvent = UnusedEvent;
type PointerMotionEvent = UnusedEvent;
type PointerMotionAbsoluteEvent = UnusedEvent;

type GestureSwipeBeginEvent = UnusedEvent;
type GestureSwipeUpdateEvent = UnusedEvent;
type GestureSwipeEndEvent = UnusedEvent;
type GesturePinchBeginEvent = UnusedEvent;
type GesturePinchUpdateEvent = UnusedEvent;
type GesturePinchEndEvent = UnusedEvent;
type GestureHoldBeginEvent = UnusedEvent;
type GestureHoldEndEvent = UnusedEvent;

type TouchDownEvent = UnusedEvent;
type TouchUpEvent = UnusedEvent;
type TouchMotionEvent = UnusedEvent;
type TouchCancelEvent = UnusedEvent;
type TouchFrameEvent = UnusedEvent;
type TabletToolAxisEvent = UnusedEvent;
type TabletToolProximityEvent = UnusedEvent;
type TabletToolTipEvent = UnusedEvent;
type TabletToolButtonEvent = UnusedEvent;

type SwitchToggleEvent = UnusedEvent;

type SpecialEvent = UnusedEvent;
}

impl VirtualKeyboardHandler for State {
fn on_keyboard_event(
&mut self,
keycode: Keycode,
state: KeyState,
time: u32,
_keyboard: KeyboardHandle<Self>,
) {
// The virtual keyboard impl in Smithay changes the keymap, so we'll need to reset it on
// the next real keyboard event.
self.niri.reset_keymap = true;

let event = VirtualKeyboardKeyEvent {
keycode,
state,
time,
};
self.process_input_event(InputEvent::<VirtualKeyboardInputBackend>::Keyboard { event });
}

// We handle modifiers when the key event is sent.
fn on_keyboard_modifiers(
&mut self,
_depressed_mods: ModMask,
_latched_mods: ModMask,
_locked_mods: ModMask,
_keyboard: KeyboardHandle<Self>,
) {
}
}
delegate_virtual_keyboard_manager!(State);