feat: support authorized input methods

This commit is contained in:
Samuel Onoja committed 2026-09-25 01:07:44 +01:00
1 parent 6dc2a5300e
commit f6dce3316a
4 files changed
+87 -1

No files matched your search

+12 -1
View File
@@ -3,7 +3,7 @@
Ferese is an experimental Wayland tiling compositor written in Rust with Ferese is an experimental Wayland tiling compositor written in Rust with
Smithay. The nested M0–M3 path is complete, including tiling, workspaces, and Smithay. The nested M0–M3 path is complete, including tiling, workspaces, and
timestamp-driven animated geometry. Development now targets the M4 early timestamp-driven animated geometry. Development now targets the M4 early
hardware-session milestone in the hardware-session acceptance pass and M5 native interoperability in the
[window-manager specification](docs/ferese-window-manager-spec.md). [window-manager specification](docs/ferese-window-manager-spec.md).
## Development ## Development
@@ -23,6 +23,17 @@ cargo run -p ferese -- foot
Set `RUST_LOG=ferese=debug` for detailed compositor logging. Set `RUST_LOG=ferese=debug` for detailed compositor logging.
Text-input-v3 is available to applications by default. Input-method-v2 is
hidden unless the session explicitly opts in, because an input method can
request privileged keyboard access. Enable it only when launching a trusted
IME for the session:
```bash
FERESE_ENABLE_INPUT_METHOD=1 cargo run -p ferese
```
`Ctrl+Alt+Escape` always releases an active client shortcut inhibitor.
### Direct DRM session ### Direct DRM session
Run the hardware backend from a spare TTY, outside another graphical session: Run the hardware backend from a spare TTY, outside another graphical session:
+61
View File
@@ -0,0 +1,61 @@
use smithay::{
desktop::{PopupKind, WindowSurfaceType, layer_map_for_output},
reexports::wayland_server::protocol::wl_surface::WlSurface,
utils::{Logical, Rectangle},
wayland::input_method::{InputMethodHandler, PopupSurface},
};
use crate::Ferese;
impl InputMethodHandler for Ferese {
fn new_popup(&mut self, surface: PopupSurface) {
if let Err(error) = self
.popups
.track_popup(PopupKind::InputMethod(surface.clone()))
{
tracing::warn!(?error, "failed to track input method popup");
}
crate::backends::direct::render_all(self);
}
fn dismiss_popup(&mut self, _surface: PopupSurface) {
self.popups.cleanup();
crate::backends::direct::render_all(self);
}
fn popup_repositioned(&mut self, _surface: PopupSurface) {
crate::backends::direct::render_all(self);
}
fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical> {
if let Some(geometry) = self.space.elements().find_map(|window| {
window
.toplevel()
.is_some_and(|toplevel| toplevel.wl_surface() == parent)
.then(|| self.space.element_geometry(window))
.flatten()
}) {
return geometry;
}
let Some(layer) = self
.space
.layer_for_surface(parent, WindowSurfaceType::TOPLEVEL)
else {
return Rectangle::default();
};
self.space
.outputs()
.find_map(|output| {
let output_geometry = self.space.output_geometry(output)?;
let layer_geometry = layer_map_for_output(output).layer_geometry(&layer)?;
Some(Rectangle::new(
output_geometry.loc + layer_geometry.loc,
layer_geometry.size,
))
})
.unwrap_or_default()
}
}
+3
View File
@@ -1,5 +1,6 @@
mod activation; mod activation;
mod compositor; mod compositor;
mod input_method;
mod layer_shell; mod layer_shell;
mod xdg_shell; mod xdg_shell;
@@ -237,6 +238,7 @@ smithay::delegate_data_device!(Ferese);
smithay::delegate_fractional_scale!(Ferese); smithay::delegate_fractional_scale!(Ferese);
smithay::delegate_idle_inhibit!(Ferese); smithay::delegate_idle_inhibit!(Ferese);
smithay::delegate_idle_notify!(Ferese); smithay::delegate_idle_notify!(Ferese);
smithay::delegate_input_method_manager!(Ferese);
smithay::delegate_keyboard_shortcuts_inhibit!(Ferese); smithay::delegate_keyboard_shortcuts_inhibit!(Ferese);
smithay::delegate_layer_shell!(Ferese); smithay::delegate_layer_shell!(Ferese);
smithay::delegate_output!(Ferese); smithay::delegate_output!(Ferese);
@@ -247,6 +249,7 @@ smithay::delegate_relative_pointer!(Ferese);
smithay::delegate_seat!(Ferese); smithay::delegate_seat!(Ferese);
smithay::delegate_shm!(Ferese); smithay::delegate_shm!(Ferese);
smithay::delegate_single_pixel_buffer!(Ferese); smithay::delegate_single_pixel_buffer!(Ferese);
smithay::delegate_text_input_manager!(Ferese);
smithay::delegate_viewporter!(Ferese); smithay::delegate_viewporter!(Ferese);
smithay::delegate_xdg_activation!(Ferese); smithay::delegate_xdg_activation!(Ferese);
smithay::delegate_xdg_decoration!(Ferese); smithay::delegate_xdg_decoration!(Ferese);
+11
View File
@@ -37,6 +37,7 @@ use smithay::{
fractional_scale::FractionalScaleManagerState, fractional_scale::FractionalScaleManagerState,
idle_inhibit::IdleInhibitManagerState, idle_inhibit::IdleInhibitManagerState,
idle_notify::IdleNotifierState, idle_notify::IdleNotifierState,
input_method::InputMethodManagerState,
keyboard_shortcuts_inhibit::{KeyboardShortcutsInhibitState, KeyboardShortcutsInhibitor}, keyboard_shortcuts_inhibit::{KeyboardShortcutsInhibitState, KeyboardShortcutsInhibitor},
output::OutputManagerState, output::OutputManagerState,
pointer_constraints::PointerConstraintsState, pointer_constraints::PointerConstraintsState,
@@ -50,6 +51,7 @@ use smithay::{
shm::ShmState, shm::ShmState,
single_pixel_buffer::SinglePixelBufferState, single_pixel_buffer::SinglePixelBufferState,
socket::ListeningSocketSource, socket::ListeningSocketSource,
text_input::TextInputManagerState,
viewporter::ViewporterState, viewporter::ViewporterState,
xdg_activation::XdgActivationState, xdg_activation::XdgActivationState,
xdg_foreign::XdgForeignState, xdg_foreign::XdgForeignState,
@@ -84,6 +86,7 @@ pub struct Ferese {
pub fractional_scale_state: FractionalScaleManagerState, pub fractional_scale_state: FractionalScaleManagerState,
pub idle_inhibit_state: IdleInhibitManagerState, pub idle_inhibit_state: IdleInhibitManagerState,
pub idle_notifier_state: IdleNotifierState<Self>, pub idle_notifier_state: IdleNotifierState<Self>,
pub input_method_manager_state: InputMethodManagerState,
pub keyboard_shortcuts_inhibit_state: KeyboardShortcutsInhibitState, pub keyboard_shortcuts_inhibit_state: KeyboardShortcutsInhibitState,
pub output_manager_state: OutputManagerState, pub output_manager_state: OutputManagerState,
pub pointer_constraints_state: PointerConstraintsState, pub pointer_constraints_state: PointerConstraintsState,
@@ -93,6 +96,7 @@ pub struct Ferese {
pub seat_state: SeatState<Self>, pub seat_state: SeatState<Self>,
pub shm_state: ShmState, pub shm_state: ShmState,
pub single_pixel_buffer_state: SinglePixelBufferState, pub single_pixel_buffer_state: SinglePixelBufferState,
pub text_input_manager_state: TextInputManagerState,
pub viewporter_state: ViewporterState, pub viewporter_state: ViewporterState,
pub layer_shell_state: WlrLayerShellState, pub layer_shell_state: WlrLayerShellState,
pub xdg_activation_state: XdgActivationState, pub xdg_activation_state: XdgActivationState,
@@ -113,10 +117,15 @@ impl Ferese {
let fractional_scale_state = FractionalScaleManagerState::new::<Self>(&display_handle); let fractional_scale_state = FractionalScaleManagerState::new::<Self>(&display_handle);
let idle_inhibit_state = IdleInhibitManagerState::new::<Self>(&display_handle); let idle_inhibit_state = IdleInhibitManagerState::new::<Self>(&display_handle);
let idle_notifier_state = IdleNotifierState::new(&display_handle, event_loop.handle()); let idle_notifier_state = IdleNotifierState::new(&display_handle, event_loop.handle());
let input_method_enabled =
std::env::var_os("FERESE_ENABLE_INPUT_METHOD").is_some_and(|value| value == "1");
let input_method_manager_state =
InputMethodManagerState::new::<Self, _>(&display_handle, move |_| input_method_enabled);
let keyboard_shortcuts_inhibit_state = let keyboard_shortcuts_inhibit_state =
KeyboardShortcutsInhibitState::new::<Self>(&display_handle); KeyboardShortcutsInhibitState::new::<Self>(&display_handle);
let shm_state = ShmState::new::<Self>(&display_handle, Vec::new()); let shm_state = ShmState::new::<Self>(&display_handle, Vec::new());
let single_pixel_buffer_state = SinglePixelBufferState::new::<Self>(&display_handle); let single_pixel_buffer_state = SinglePixelBufferState::new::<Self>(&display_handle);
let text_input_manager_state = TextInputManagerState::new::<Self>(&display_handle);
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle); let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
let pointer_constraints_state = PointerConstraintsState::new::<Self>(&display_handle); let pointer_constraints_state = PointerConstraintsState::new::<Self>(&display_handle);
let presentation_state = let presentation_state =
@@ -167,6 +176,7 @@ impl Ferese {
fractional_scale_state, fractional_scale_state,
idle_inhibit_state, idle_inhibit_state,
idle_notifier_state, idle_notifier_state,
input_method_manager_state,
keyboard_shortcuts_inhibit_state, keyboard_shortcuts_inhibit_state,
output_manager_state, output_manager_state,
pointer_constraints_state, pointer_constraints_state,
@@ -176,6 +186,7 @@ impl Ferese {
seat_state, seat_state,
shm_state, shm_state,
single_pixel_buffer_state, single_pixel_buffer_state,
text_input_manager_state,
viewporter_state, viewporter_state,
layer_shell_state, layer_shell_state,
xdg_activation_state, xdg_activation_state,