smithay/wayland/input_method/
mod.rs1use wayland_server::{
69 backend::GlobalId, protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle,
70 GlobalDispatch, New,
71};
72
73use wayland_protocols_misc::zwp_input_method_v2::server::{
74 zwp_input_method_manager_v2::{self, ZwpInputMethodManagerV2},
75 zwp_input_method_v2::ZwpInputMethodV2,
76};
77
78use crate::{
79 input::{Seat, SeatHandler},
80 utils::{Logical, Rectangle},
81};
82
83pub use input_method_handle::{InputMethodHandle, InputMethodUserData};
84pub use input_method_keyboard_grab::{InputMethodKeyboardGrab, InputMethodKeyboardUserData};
85pub use input_method_popup_surface::InputMethodPopupSurfaceUserData;
86
87use super::text_input::TextInputHandle;
88
89const MANAGER_VERSION: u32 = 1;
90
91pub const INPUT_POPUP_SURFACE_ROLE: &str = "zwp_input_popup_surface_v2";
93
94mod input_method_handle;
95mod input_method_keyboard_grab;
96mod input_method_popup_surface;
97pub use input_method_popup_surface::{PopupParent, PopupSurface};
98
99pub trait InputMethodHandler {
101 fn new_popup(&mut self, surface: PopupSurface);
103
104 fn dismiss_popup(&mut self, surface: PopupSurface);
106
107 fn popup_repositioned(&mut self, surface: PopupSurface);
109
110 fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical>;
112}
113
114pub trait InputMethodSeat {
116 fn input_method(&self) -> &InputMethodHandle;
118}
119
120impl<D: SeatHandler + 'static> InputMethodSeat for Seat<D> {
121 fn input_method(&self) -> &InputMethodHandle {
122 let user_data = self.user_data();
123 user_data.insert_if_missing(InputMethodHandle::default);
124 user_data.get::<InputMethodHandle>().unwrap()
125 }
126}
127
128#[allow(missing_debug_implementations)]
130pub struct InputMethodManagerGlobalData {
131 filter: Box<dyn for<'c> Fn(&'c Client) -> bool + Send + Sync>,
132}
133
134#[derive(Debug)]
136pub struct InputMethodManagerState {
137 global: GlobalId,
138}
139
140impl InputMethodManagerState {
141 pub fn new<D, F>(display: &DisplayHandle, filter: F) -> Self
143 where
144 D: GlobalDispatch<ZwpInputMethodManagerV2, InputMethodManagerGlobalData>,
145 D: Dispatch<ZwpInputMethodManagerV2, ()>,
146 D: Dispatch<ZwpInputMethodV2, InputMethodUserData<D>>,
147 D: SeatHandler,
148 D: 'static,
149 F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static,
150 {
151 let data = InputMethodManagerGlobalData {
152 filter: Box::new(filter),
153 };
154 let global = display.create_global::<D, ZwpInputMethodManagerV2, _>(MANAGER_VERSION, data);
155
156 Self { global }
157 }
158
159 pub fn global(&self) -> GlobalId {
161 self.global.clone()
162 }
163}
164
165impl<D> GlobalDispatch<ZwpInputMethodManagerV2, InputMethodManagerGlobalData, D> for InputMethodManagerState
166where
167 D: GlobalDispatch<ZwpInputMethodManagerV2, InputMethodManagerGlobalData>,
168 D: Dispatch<ZwpInputMethodManagerV2, ()>,
169 D: Dispatch<ZwpInputMethodV2, InputMethodUserData<D>>,
170 D: SeatHandler,
171 D: 'static,
172{
173 fn bind(
174 _: &mut D,
175 _: &DisplayHandle,
176 _: &Client,
177 resource: New<ZwpInputMethodManagerV2>,
178 _: &InputMethodManagerGlobalData,
179 data_init: &mut DataInit<'_, D>,
180 ) {
181 data_init.init(resource, ());
182 }
183
184 fn can_view(client: Client, global_data: &InputMethodManagerGlobalData) -> bool {
185 (global_data.filter)(&client)
186 }
187}
188
189impl<D> Dispatch<ZwpInputMethodManagerV2, (), D> for InputMethodManagerState
190where
191 D: Dispatch<ZwpInputMethodManagerV2, ()>,
192 D: Dispatch<ZwpInputMethodV2, InputMethodUserData<D>>,
193 D: SeatHandler + InputMethodHandler,
194 D: 'static,
195{
196 fn request(
197 _state: &mut D,
198 _client: &Client,
199 _: &ZwpInputMethodManagerV2,
200 request: zwp_input_method_manager_v2::Request,
201 _: &(),
202 _dh: &DisplayHandle,
203 data_init: &mut DataInit<'_, D>,
204 ) {
205 match request {
206 zwp_input_method_manager_v2::Request::GetInputMethod { seat, input_method } => {
207 let seat = Seat::<D>::from_resource(&seat).unwrap();
208
209 let user_data = seat.user_data();
210 user_data.insert_if_missing(TextInputHandle::default);
211 user_data.insert_if_missing(InputMethodHandle::default);
212 let handle = user_data.get::<InputMethodHandle>().unwrap();
213 let text_input_handle = user_data.get::<TextInputHandle>().unwrap();
214 text_input_handle.with_focused_text_input(|ti, surface| {
215 ti.enter(surface);
216 });
217 let keyboard_handle = seat.get_keyboard().unwrap();
218 let instance = data_init.init(
219 input_method,
220 InputMethodUserData {
221 handle: handle.clone(),
222 text_input_handle: text_input_handle.clone(),
223 keyboard_handle,
224 popup_geometry_callback: D::parent_geometry,
225 popup_repositioned: D::popup_repositioned,
226 new_popup: D::new_popup,
227 dismiss_popup: D::dismiss_popup,
228 },
229 );
230 handle.add_instance(&instance);
231 }
232 zwp_input_method_manager_v2::Request::Destroy => {
233 }
235 _ => unreachable!(),
236 }
237 }
238}
239
240#[allow(missing_docs)] #[macro_export]
242macro_rules! delegate_input_method_manager {
243 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
244 $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
245 $crate::reexports::wayland_protocols_misc::zwp_input_method_v2::server::zwp_input_method_manager_v2::ZwpInputMethodManagerV2:
246 $crate::wayland::input_method::InputMethodManagerGlobalData
247 ] => $crate::wayland::input_method::InputMethodManagerState);
248
249 $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
250 $crate::reexports::wayland_protocols_misc::zwp_input_method_v2::server::zwp_input_method_manager_v2::ZwpInputMethodManagerV2: ()
251 ] => $crate::wayland::input_method::InputMethodManagerState);
252 $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
253 $crate::reexports::wayland_protocols_misc::zwp_input_method_v2::server::zwp_input_method_v2::ZwpInputMethodV2:
254 $crate::wayland::input_method::InputMethodUserData<Self>
255 ] => $crate::wayland::input_method::InputMethodManagerState);
256 $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
257 $crate::reexports::wayland_protocols_misc::zwp_input_method_v2::server::zwp_input_method_keyboard_grab_v2::ZwpInputMethodKeyboardGrabV2:
258 $crate::wayland::input_method::InputMethodKeyboardUserData<Self>
259 ] => $crate::wayland::input_method::InputMethodManagerState);
260 $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
261 $crate::reexports::wayland_protocols_misc::zwp_input_method_v2::server::zwp_input_popup_surface_v2::ZwpInputPopupSurfaceV2:
262 $crate::wayland::input_method::InputMethodPopupSurfaceUserData
263 ] => $crate::wayland::input_method::InputMethodManagerState);
264 };
265}