input method: Initialize the protocol and pretend to handle a few things
This commit is contained in:
35
src/imservice.c
Normal file
35
src/imservice.c
Normal file
@ -0,0 +1,35 @@
|
||||
#include "imservice.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
void imservice_handle_text_change_cause(void *data, struct zwp_input_method_v2 *input_method) {}
|
||||
void imservice_handle_content_type(void *data, struct zwp_input_method_v2 *input_method) {}
|
||||
void imservice_handle_unavailable(void *data, struct zwp_input_method_v2 *input_method) {}
|
||||
|
||||
|
||||
static const struct zwp_input_method_v2_listener input_method_listener = {
|
||||
.activate = imservice_handle_input_method_activate,
|
||||
.deactivate = imservice_handle_input_method_deactivate,
|
||||
.surrounding_text = imservice_handle_surrounding_text,
|
||||
.text_change_cause = imservice_handle_text_change_cause,
|
||||
.content_type = imservice_handle_content_type,
|
||||
.done = imservice_handle_commit_state,
|
||||
.unavailable = imservice_handle_unavailable,
|
||||
};
|
||||
|
||||
struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager,
|
||||
struct wl_seat *seat) {
|
||||
struct zwp_input_method_v2 *im = zwp_input_method_manager_v2_get_input_method(manager, seat);
|
||||
struct imservice *imservice = imservice_new(im);
|
||||
zwp_input_method_v2_add_listener(im,
|
||||
&input_method_listener, imservice);
|
||||
return imservice;
|
||||
}
|
||||
|
||||
void imservice_make_visible(struct imservice *imservice) {
|
||||
g_log("squeek", G_LOG_LEVEL_DEBUG, "Visibiling");
|
||||
}
|
||||
void imservice_try_hide(struct imservice *imservice) {
|
||||
g_log("squeek", G_LOG_LEVEL_DEBUG, "Hiding");
|
||||
}
|
||||
21
src/imservice.h
Normal file
21
src/imservice.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __IMSERVICE_H
|
||||
#define __IMSERVICE_H
|
||||
|
||||
#include "input-method-unstable-v2-client-protocol.h"
|
||||
|
||||
struct imservice;
|
||||
|
||||
struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager,
|
||||
struct wl_seat *seat);
|
||||
void imservice_make_visible(struct imservice *imservice);
|
||||
void imservice_try_hide(struct imservice *imservice);
|
||||
|
||||
// Defined in Rust
|
||||
struct imservice* imservice_new(struct zwp_input_method_v2 *im);
|
||||
void imservice_handle_input_method_activate(void *data, struct zwp_input_method_v2 *input_method);
|
||||
void imservice_handle_input_method_deactivate(void *data, struct zwp_input_method_v2 *input_method);
|
||||
void imservice_handle_surrounding_text(void *data, struct zwp_input_method_v2 *input_method,
|
||||
const char *text, uint32_t cursor, uint32_t anchor);
|
||||
void imservice_handle_commit_state(void *data, struct zwp_input_method_v2 *input_method);
|
||||
|
||||
#endif
|
||||
128
src/imservice.rs
Normal file
128
src/imservice.rs
Normal file
@ -0,0 +1,128 @@
|
||||
use std::boxed::Box;
|
||||
use std::ffi::CString;
|
||||
use std::num::Wrapping;
|
||||
use std::string::String;
|
||||
|
||||
|
||||
/// Gathers stuff defined in C or called by C
|
||||
pub mod c {
|
||||
use super::*;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
|
||||
fn into_cstring(s: *const c_char) -> Result<CString, std::ffi::NulError> {
|
||||
CString::new(
|
||||
unsafe {CStr::from_ptr(s)}.to_bytes()
|
||||
)
|
||||
}
|
||||
|
||||
// The following defined in C
|
||||
|
||||
/// struct zwp_input_method_v2 *input_method
|
||||
#[repr(transparent)]
|
||||
pub struct InputMethod(*const c_void);
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" {
|
||||
fn imservice_make_visible(imservice: *mut IMService);
|
||||
fn imservice_try_hide(imservice: *mut IMService);
|
||||
}
|
||||
|
||||
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C"
|
||||
fn imservice_new(im: *const InputMethod) -> *mut IMService {
|
||||
Box::<IMService>::into_raw(Box::new(
|
||||
IMService {
|
||||
im: im,
|
||||
pending: IMProtocolState::default(),
|
||||
current: IMProtocolState::default(),
|
||||
preedit_string: String::new(),
|
||||
serial: Wrapping(0u32),
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: is unsafe needed here?
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C"
|
||||
fn imservice_handle_input_method_activate(imservice: *mut IMService,
|
||||
_im: *const InputMethod)
|
||||
{
|
||||
let imservice = &mut *imservice;
|
||||
imservice.preedit_string = String::new();
|
||||
imservice.pending = IMProtocolState {
|
||||
active: true,
|
||||
..IMProtocolState::default()
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C"
|
||||
fn imservice_handle_input_method_deactivate(imservice: *mut IMService,
|
||||
_im: *const InputMethod)
|
||||
{
|
||||
let imservice = &mut *imservice;
|
||||
imservice.pending = IMProtocolState {
|
||||
active: false,
|
||||
..imservice.pending.clone()
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C"
|
||||
fn imservice_handle_surrounding_text(imservice: *mut IMService,
|
||||
_im: *const InputMethod,
|
||||
text: *const c_char, cursor: u32, _anchor: u32)
|
||||
{
|
||||
let imservice = &mut *imservice;
|
||||
imservice.pending = IMProtocolState {
|
||||
surrounding_text: into_cstring(text).expect("Received invalid string"),
|
||||
surrounding_cursor: cursor,
|
||||
..imservice.pending
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C"
|
||||
fn imservice_handle_commit_state(imservice_ptr: *mut IMService,
|
||||
_im: *const InputMethod)
|
||||
{
|
||||
let imservice = &mut *imservice_ptr;
|
||||
let active_changed = imservice.current.active ^ imservice.pending.active;
|
||||
|
||||
imservice.serial += Wrapping(1u32);
|
||||
imservice.current = imservice.pending.clone();
|
||||
imservice.pending = IMProtocolState {
|
||||
active: imservice.current.active,
|
||||
..IMProtocolState::default()
|
||||
};
|
||||
if active_changed {
|
||||
if imservice.current.active {
|
||||
imservice_make_visible(imservice_ptr);
|
||||
} else {
|
||||
imservice_try_hide(imservice_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: destroy
|
||||
}
|
||||
|
||||
/// Describes the desired state of the input method as requested by the server
|
||||
#[derive(Default, Clone)]
|
||||
struct IMProtocolState {
|
||||
surrounding_text: CString,
|
||||
surrounding_cursor: u32,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
pub struct IMService {
|
||||
im: *const c::InputMethod,
|
||||
pending: IMProtocolState,
|
||||
current: IMProtocolState, // turn into an idiomatic representation?
|
||||
preedit_string: String,
|
||||
serial: Wrapping<u32>,
|
||||
}
|
||||
@ -5,6 +5,7 @@ dbus_src = gnome.gdbus_codegen(
|
||||
)
|
||||
|
||||
sources = [
|
||||
'imservice.c',
|
||||
'server-context-service.c',
|
||||
'server-main.c',
|
||||
'wayland.c',
|
||||
@ -61,6 +62,7 @@ deps = [
|
||||
# Replacement for eekboard-server
|
||||
squeekboard = executable('squeekboard',
|
||||
sources,
|
||||
link_with: library('rslib', 'imservice.rs'),
|
||||
include_directories: [include_directories('..'), include_directories('../eek')],
|
||||
dependencies: deps,
|
||||
install: true,
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
|
||||
#include "eekboard/eekboard-service.h"
|
||||
#include "eek/eek.h"
|
||||
#include "imservice.h"
|
||||
#include "server-context-service.h"
|
||||
#include "wayland.h"
|
||||
|
||||
@ -43,6 +44,7 @@
|
||||
struct squeekboard {
|
||||
struct squeek_wayland wayland;
|
||||
EekboardContextService *context;
|
||||
struct imservice *imservice;
|
||||
};
|
||||
|
||||
|
||||
@ -114,6 +116,9 @@ registry_handle_global (void *data,
|
||||
} else if (!strcmp (interface, zwp_virtual_keyboard_manager_v1_interface.name)) {
|
||||
instance->wayland.virtual_keyboard_manager = wl_registry_bind(registry, name,
|
||||
&zwp_virtual_keyboard_manager_v1_interface, 1);
|
||||
} else if (!strcmp (interface, zwp_input_method_manager_v2_interface.name)) {
|
||||
instance->wayland.input_method_manager = wl_registry_bind(registry, name,
|
||||
&zwp_input_method_manager_v2_interface, 1);
|
||||
} else if (!strcmp (interface, "wl_output")) {
|
||||
struct wl_output *output = wl_registry_bind (registry, name,
|
||||
&wl_output_interface, 2);
|
||||
@ -244,6 +249,17 @@ main (int argc, char **argv)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
struct imservice *imservice = NULL;
|
||||
if (instance.wayland.input_method_manager) {
|
||||
imservice = get_imservice(instance.wayland.input_method_manager,
|
||||
instance.wayland.seat);
|
||||
if (imservice) {
|
||||
instance.imservice = imservice;
|
||||
} else {
|
||||
g_warning("Failed to register as an input method");
|
||||
}
|
||||
}
|
||||
|
||||
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
g_signal_connect (service, "destroyed", G_CALLBACK(on_destroyed), loop);
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
||||
#include "input-method-unstable-v2-client-protocol.h"
|
||||
|
||||
#include <gmodule.h>
|
||||
|
||||
@ -10,6 +11,7 @@
|
||||
struct squeek_wayland {
|
||||
struct zwlr_layer_shell_v1 *layer_shell;
|
||||
struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
|
||||
struct zwp_input_method_manager_v2 *input_method_manager;
|
||||
GPtrArray *outputs; // *wl_output
|
||||
struct wl_seat *seat;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user