hboard/src/wayland/ime_v1.rs

169 lines
5.8 KiB
Rust

use smithay_client_toolkit::{
error::GlobalError,
globals::{GlobalData, ProvidesBoundGlobal},
reexports::{
client::{
globals::{BindError, GlobalList},
Connection, Dispatch, QueueHandle,
},
protocols::wp::{
input_method::zv1::client::{
zwp_input_method_context_v1::{self, ZwpInputMethodContextV1},
zwp_input_method_v1::{self, ZwpInputMethodV1},
},
text_input::zv1::client::zwp_text_input_v1::{ContentHint, ContentPurpose},
},
},
};
pub trait ImeContextV1Handler {
fn reset(&mut self);
fn preferred_language(&mut self, lang: &str);
fn content_type(&mut self, hint: ContentHint, purpose: ContentPurpose);
fn commit_state(&mut self, serial: u32);
/// button: e.g. BTN_LEFT / BTN_RIGHT
/// index = position in preedit
fn invoke_action(&mut self, button: u32, index: u32);
fn set_surrounding_text(&mut self, text: &str, cursor: u32, anchor: u32);
}
pub trait ImeV1Handler {
fn activate(&mut self, ctx: ImeContextV1);
fn deactivate(&mut self, ctx: ImeContextV1);
}
#[derive(Debug)]
pub struct ImeV1 {
wl_ime: ZwpInputMethodV1,
}
#[derive(Debug)]
pub struct ImeContextV1 {
wl_ime_ctx: ZwpInputMethodContextV1,
}
impl From<ZwpInputMethodContextV1> for ImeContextV1 {
fn from(wl_ime: ZwpInputMethodContextV1) -> Self {
Self { wl_ime_ctx: wl_ime }
}
}
impl ImeV1 {
pub fn bind<State>(globals: &GlobalList, qh: &QueueHandle<State>) -> Result<Self, BindError>
where
State: Dispatch<ZwpInputMethodV1, GlobalData, State> + ImeContextV1Handler + 'static,
{
let wl_ime = globals.bind(qh, 1..=1, GlobalData)?;
// Compositors must advertise Argb8888 and Xrgb8888, so let's reserve space for those formats.
Ok(Self { wl_ime })
}
#[allow(unused)]
pub fn wl_ime(&self) -> &ZwpInputMethodV1 {
&self.wl_ime
}
}
impl ImeContextV1 {
#[allow(unused)]
pub fn wl_ime_ctx(&self) -> &ZwpInputMethodContextV1 {
&self.wl_ime_ctx
}
}
impl ProvidesBoundGlobal<ZwpInputMethodV1, 1> for ImeV1 {
fn bound_global(&self) -> Result<ZwpInputMethodV1, GlobalError> {
Ok(self.wl_ime.clone())
}
}
#[macro_export]
macro_rules! delegate_ime_v1 {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
smithay_client_toolkit::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
[
smithay_client_toolkit::reexports::protocols::wp::input_method::zv1::client::zwp_input_method_v1::ZwpInputMethodV1: smithay_client_toolkit::globals::GlobalData
] => $crate::wayland::ime_v1::ImeV1
);
};
}
#[macro_export]
macro_rules! delegate_ime_context_v1 {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
smithay_client_toolkit::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty:
[
smithay_client_toolkit::reexports::protocols::wp::input_method::zv1::client::zwp_input_method_context_v1::ZwpInputMethodContextV1: smithay_client_toolkit::globals::GlobalData// $crate::wayland::ime_v1::ImeContextV1Data
] => $crate::wayland::ime_v1::ImeContextV1
);
};
}
impl<D> Dispatch<ZwpInputMethodContextV1, GlobalData, D> for ImeContextV1
where
D: Dispatch<ZwpInputMethodContextV1, GlobalData> + ImeContextV1Handler,
{
fn event(
state: &mut D,
_proxy: &ZwpInputMethodContextV1,
event: zwp_input_method_context_v1::Event,
_: &GlobalData,
_: &Connection,
_: &QueueHandle<D>,
) {
log::debug!(target: "zwp_input_method_context_v1", "received {event:?}");
match event {
zwp_input_method_context_v1::Event::Reset => {
state.reset();
}
zwp_input_method_context_v1::Event::ContentType { hint, purpose } => {
let Some(hint) = ContentHint::from_bits(hint) else {
log::debug!(target: "zwp_input_method_context_v1", "unknown hint: {hint:?}");
return;
};
let Ok(purpose) = ContentPurpose::try_from(purpose) else {
log::debug!(target: "zwp_input_method_context_v1", "unknown purpose: {purpose:?}");
return;
};
state.content_type(hint, purpose);
}
zwp_input_method_context_v1::Event::CommitState { serial } => {
state.commit_state(serial);
}
zwp_input_method_context_v1::Event::InvokeAction { button, index } => {
state.invoke_action(button, index);
}
zwp_input_method_context_v1::Event::SurroundingText {
text,
cursor,
anchor,
} => {
state.set_surrounding_text(&text, cursor, anchor);
}
zwp_input_method_context_v1::Event::PreferredLanguage { language } => {
state.preferred_language(&language);
}
_ => log::debug!(target: "zwp_input_method_context_v1", "unknown event"),
}
}
}
impl<D> Dispatch<ZwpInputMethodV1, GlobalData, D> for ImeV1
where
D: Dispatch<ZwpInputMethodV1, GlobalData> + ImeV1Handler,
{
fn event(
state: &mut D,
_proxy: &ZwpInputMethodV1,
event: zwp_input_method_v1::Event,
_data: &GlobalData,
_conn: &Connection,
_qh: &QueueHandle<D>,
) {
match event {
zwp_input_method_v1::Event::Activate { id } => state.activate(id.into()),
zwp_input_method_v1::Event::Deactivate { context } => state.deactivate(context.into()),
_ => log::debug!(target: "zwp_input_method_v1", "unknown event"),
}
}
}