services: Split out layout management from EekboardContextService

Layout management was pointlessly bound with the EekboardContextService with inheritance. Splitting it out will make it easier to further break apart layout state management, settings, and input method in the future.
This commit is contained in:
Dorota Czaplejewicz
2020-01-09 20:49:27 +00:00
parent 58b087e35a
commit 92c9572ac2
10 changed files with 116 additions and 68 deletions

View File

@ -69,6 +69,10 @@ struct _EekboardContextServicePrivate {
GSettings *settings; // Owned reference
uint32_t hint;
uint32_t purpose;
// Maybe TODO: it's used only for fetching layout type.
// Maybe let UI push the type to this structure?
ServerContextService *ui; // unowned reference
};
G_DEFINE_TYPE_WITH_PRIVATE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT);
@ -218,13 +222,13 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ
LevelKeyboard *previous_keyboard = context->priv->keyboard;
context->priv->keyboard = keyboard;
g_object_notify (G_OBJECT(context), "keyboard");
// The keymap will get set even if the window is hidden.
// It's not perfect,
// but simpler than adding a check in the window showing procedure
eekboard_context_service_set_keymap(context, keyboard);
g_object_notify (G_OBJECT(context), "keyboard");
// replacing the keyboard above will cause the previous keyboard to get destroyed from the UI side (eek_gtk_keyboard_dispose)
if (previous_keyboard) {
level_keyboard_free(previous_keyboard);
@ -232,7 +236,12 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ
}
static void update_layout_and_type(EekboardContextService *context) {
eekboard_context_service_update_layout(context, server_context_service_get_layout_type(context));
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
enum squeek_arrangement_kind layout_kind = ARRANGEMENT_KIND_BASE;
if (priv->ui) {
layout_kind = server_context_service_get_layout_type(priv->ui);
}
eekboard_context_service_update_layout(context, layout_kind);
}
static gboolean
@ -384,3 +393,8 @@ const char*
eekboard_context_service_get_overlay(EekboardContextService *context) {
return context->priv->overlay;
}
EekboardContextService *eekboard_context_service_new()
{
return g_object_new (EEKBOARD_TYPE_CONTEXT_SERVICE, NULL);
}

View File

@ -77,8 +77,6 @@ struct _EekboardContextServiceClass {
const gchar *keyboard_type);
/* signals */
void (*enabled) (EekboardContextService *self);
void (*disabled) (EekboardContextService *self);
void (*destroyed) (EekboardContextService *self);
/*< private >*/
@ -86,8 +84,10 @@ struct _EekboardContextServiceClass {
gpointer pdummy[24];
};
EekboardContextService *eekboard_context_service_new();
GType eekboard_context_service_get_type
(void) G_GNUC_CONST;
EekboardContextService *eekboard_context_service_new(void);
void eekboard_context_service_destroy (EekboardContextService *context);
LevelKeyboard *eekboard_context_service_get_keyboard(EekboardContextService *context);

View File

@ -110,7 +110,7 @@ dbus_handler_new (GDBusConnection *connection,
}
void
dbus_handler_set_context(DBusHandler *service,
dbus_handler_set_ui_context(DBusHandler *service,
ServerContextService *context)
{
g_return_if_fail (!service->context);

View File

@ -41,7 +41,7 @@ typedef struct _DBusHandler
DBusHandler * dbus_handler_new (GDBusConnection *connection,
const gchar *object_path);
void dbus_handler_set_context(DBusHandler *service,
void dbus_handler_set_ui_context(DBusHandler *service,
ServerContextService *context);
void dbus_handler_destroy(DBusHandler*);
G_END_DECLS

View File

@ -12,11 +12,11 @@ static const struct zwp_input_method_v2_listener input_method_listener = {
.unavailable = imservice_handle_unavailable,
};
struct imservice* get_imservice(ServerContextService *context,
struct zwp_input_method_manager_v2 *manager,
struct wl_seat *seat) {
struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager,
struct wl_seat *seat,
EekboardContextService *state) {
struct zwp_input_method_v2 *im = zwp_input_method_manager_v2_get_input_method(manager, seat);
struct imservice *imservice = imservice_new(im, context);
struct imservice *imservice = imservice_new(im, state);
/* Add a listener, passing the imservice instance to make it available to
callbacks. */

View File

@ -7,13 +7,14 @@
struct imservice;
struct imservice* get_imservice(ServerContextService *context,
struct zwp_input_method_manager_v2 *manager,
struct wl_seat *seat);
struct imservice* get_imservice(struct zwp_input_method_manager_v2 *manager,
struct wl_seat *seat,
EekboardContextService *state);
// Defined in Rust
struct imservice* imservice_new(struct zwp_input_method_v2 *im,
ServerContextService *context);
struct imservice* imservice_new(struct zwp_input_method_v2 *im, EekboardContextService *state);
void imservice_set_ui(struct imservice *self, ServerContextService *ui_context);
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,

View File

@ -21,14 +21,18 @@ pub mod c {
#[repr(transparent)]
pub struct InputMethod(*const c_void);
/// EekboardContextService*
/// ServerContextService*
#[repr(transparent)]
pub struct UIManager(*const c_void);
/// EekboardContextService*
#[repr(transparent)]
pub struct StateManager(*const c_void);
#[no_mangle]
extern "C" {
fn imservice_destroy_im(im: *mut c::InputMethod);
fn eekboard_context_service_set_hint_purpose(imservice: *const UIManager, hint: u32, purpose: u32);
fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32);
fn server_context_service_show_keyboard(imservice: *const UIManager);
fn server_context_service_hide_keyboard(imservice: *const UIManager);
}
@ -36,12 +40,16 @@ pub mod c {
// 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, ui_manager: *const UIManager) -> *mut IMService {
pub extern "C"
fn imservice_new(
im: *const InputMethod,
state_manager: *const StateManager
) -> *mut IMService {
Box::<IMService>::into_raw(Box::new(
IMService {
im: im,
ui_manager: ui_manager,
state_manager: state_manager,
ui_manager: None,
pending: IMProtocolState::default(),
current: IMProtocolState::default(),
preedit_string: String::new(),
@ -49,6 +57,20 @@ pub mod c {
}
))
}
#[no_mangle]
pub extern "C"
fn imservice_set_ui(imservice: *mut IMService, ui_manager: *const UIManager) {
if imservice.is_null() {
panic!("Null imservice pointer");
}
let imservice: &mut IMService = unsafe { &mut *imservice };
imservice.ui_manager = if ui_manager.is_null() {
None
} else {
Some(ui_manager)
};
}
// TODO: is unsafe needed here?
#[no_mangle]
@ -148,15 +170,20 @@ pub mod c {
active: imservice.current.active,
..IMProtocolState::default()
};
if active_changed {
if imservice.current.active {
server_context_service_show_keyboard(imservice.ui_manager);
if let Some(ui) = imservice.ui_manager {
server_context_service_show_keyboard(ui);
}
eekboard_context_service_set_hint_purpose(
imservice.ui_manager,
imservice.state_manager,
imservice.current.content_hint.bits(),
imservice.current.content_purpose.clone() as u32);
} else {
server_context_service_hide_keyboard(imservice.ui_manager);
if let Some(ui) = imservice.ui_manager {
server_context_service_hide_keyboard(ui);
}
}
}
}
@ -173,7 +200,9 @@ pub mod c {
// the keyboard is already decommissioned
imservice.current.active = false;
server_context_service_hide_keyboard(imservice.ui_manager);
if let Some(ui) = imservice.ui_manager {
server_context_service_hide_keyboard(ui);
}
}
// FIXME: destroy and deallocate
@ -320,7 +349,9 @@ pub struct IMService {
/// Owned reference (still created and destroyed in C)
pub im: *const c::InputMethod,
/// Unowned reference. Be careful, it's shared with C at large
ui_manager: *const c::UIManager,
ui_manager: Option<*const c::UIManager>,
/// Unowned reference. Be careful, it's shared with C at large
state_manager: *const c::StateManager,
pending: IMProtocolState,
current: IMProtocolState, // turn current into an idiomatic representation?

View File

@ -38,7 +38,9 @@ enum {
typedef struct _ServerContextServiceClass ServerContextServiceClass;
struct _ServerContextService {
EekboardContextService parent;
GObject parent;
EekboardContextService *state; // unowned
gboolean visible;
PhoshLayerSurface *window;
@ -52,10 +54,10 @@ struct _ServerContextService {
};
struct _ServerContextServiceClass {
EekboardContextServiceClass parent_class;
GObjectClass parent_class;
};
G_DEFINE_TYPE (ServerContextService, server_context_service, EEKBOARD_TYPE_CONTEXT_SERVICE);
G_DEFINE_TYPE(ServerContextService, server_context_service, G_TYPE_OBJECT);
static void
on_destroy (GtkWidget *widget, gpointer user_data)
@ -67,7 +69,7 @@ on_destroy (GtkWidget *widget, gpointer user_data)
context->window = NULL;
context->widget = NULL;
eekboard_context_service_destroy (EEKBOARD_CONTEXT_SERVICE (context));
//eekboard_context_service_destroy (EEKBOARD_CONTEXT_SERVICE (context));
}
static void
@ -220,7 +222,7 @@ make_widget (ServerContextService *context)
context->widget = NULL;
}
LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
LevelKeyboard *keyboard = eekboard_context_service_get_keyboard (context->state);
context->widget = eek_gtk_keyboard_new (keyboard);
@ -284,11 +286,6 @@ server_context_service_hide_keyboard (ServerContextService *context)
}
}
static void
server_context_service_real_destroyed (EekboardContextService *_context)
{
}
static void
server_context_service_set_property (GObject *object,
guint prop_id,
@ -352,12 +349,9 @@ server_context_service_dispose (GObject *object)
static void
server_context_service_class_init (ServerContextServiceClass *klass)
{
EekboardContextServiceClass *context_class = EEKBOARD_CONTEXT_SERVICE_CLASS(klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
context_class->destroyed = server_context_service_real_destroyed;
gobject_class->set_property = server_context_service_set_property;
gobject_class->get_property = server_context_service_get_property;
gobject_class->dispose = server_context_service_dispose;
@ -396,21 +390,23 @@ server_context_service_class_init (ServerContextServiceClass *klass)
}
static void
server_context_service_init (ServerContextService *context)
{
g_signal_connect (context,
"notify::keyboard",
G_CALLBACK(on_notify_keyboard),
context);
server_context_service_init (ServerContextService *state) {
(void)state;
}
ServerContextService *
server_context_service_new ()
server_context_service_new (EekboardContextService *state)
{
return g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
ui->state = state;
g_signal_connect (state,
"notify::keyboard",
G_CALLBACK(on_notify_keyboard),
ui);
return ui;
}
enum squeek_arrangement_kind server_context_service_get_layout_type(EekboardContextService *service)
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *service)
{
return SERVER_CONTEXT_SERVICE(service)->last_type;
return service->last_type;
}

View File

@ -29,14 +29,14 @@ G_BEGIN_DECLS
#define SERVER_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SERVER_TYPE_CONTEXT_SERVICE))
#define SERVER_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SERVER_TYPE_CONTEXT_SERVICE, ServerContextServiceClass))
/** Manages the liecycle of the window displaying layouts. */
/** Manages the lifecycle of the window displaying layouts. */
typedef struct _ServerContextService ServerContextService;
GType server_context_service_get_type
(void) G_GNUC_CONST;
ServerContextService *server_context_service_new();
enum squeek_arrangement_kind server_context_service_get_layout_type(EekboardContextService*);
ServerContextService *server_context_service_new(EekboardContextService *state);
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
void server_context_service_show_keyboard (ServerContextService *context);
void server_context_service_hide_keyboard (ServerContextService *context);
G_END_DECLS

View File

@ -39,7 +39,9 @@
/// Global application state
struct squeekboard {
struct squeek_wayland wayland;
ServerContextService *context;
DBusHandler *dbus_handler;
EekboardContextService *settings_context;
ServerContextService *ui_context;
struct imservice *imservice;
};
@ -71,14 +73,6 @@ on_name_lost (GDBusConnection *connection,
exit (1);
}
static ServerContextService *create_context() {
ServerContextService *context = server_context_service_new ();
g_object_set_data_full (G_OBJECT(context),
"owner", g_strdup ("sender"),
(GDestroyNotify)g_free);
return context;
}
// Wayland
static void
@ -199,7 +193,7 @@ main (int argc, char **argv)
exit(1);
}
instance.context = create_context();
instance.settings_context = eekboard_context_service_new();
// set up dbus
@ -252,9 +246,8 @@ main (int argc, char **argv)
if (service == NULL) {
g_printerr ("Can't create dbus server\n");
exit (1);
} else {
dbus_handler_set_context(service, instance.context);
}
instance.dbus_handler = service;
guint owner_id = g_bus_own_name_on_connection (connection,
DBUS_SERVICE_INTERFACE,
@ -270,9 +263,9 @@ main (int argc, char **argv)
struct imservice *imservice = NULL;
if (instance.wayland.input_method_manager) {
imservice = get_imservice(instance.context,
instance.wayland.input_method_manager,
instance.wayland.seat);
imservice = get_imservice(instance.wayland.input_method_manager,
instance.wayland.seat,
instance.settings_context);
if (imservice) {
instance.imservice = imservice;
} else {
@ -280,6 +273,19 @@ main (int argc, char **argv)
}
}
ServerContextService *ui_context = server_context_service_new(instance.settings_context);
if (!ui_context) {
g_error("Could not initialize GUI");
exit(1);
}
instance.ui_context = ui_context;
if (instance.imservice) {
imservice_set_ui(instance.imservice, instance.ui_context);
}
if (instance.dbus_handler) {
dbus_handler_set_ui_context(instance.dbus_handler, instance.ui_context);
}
session_register();
GMainLoop *loop = g_main_loop_new (NULL, FALSE);