diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e2b2d5c9..3050fbcd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ stages: before_script: - apt-get -y update - - apt-get -y install gnome-common gtk-doc-tools libglib2.0-dev-bin gobject-introspection libglib2.0-dev libpango1.0-dev libgtk-3-dev libcroco3-dev meson + - apt-get -y install gnome-common gtk-doc-tools libglib2.0-dev-bin gobject-introspection libglib2.0-dev libpango1.0-dev libgtk-3-dev libcroco3-dev libxkbcommon-dev meson build_meson: stage: build diff --git a/README.md b/README.md index 6a09d1fa..9b66938f 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,6 @@ Features - Use Wayland virtual keyboard protocol - Use Wayland text input protocol - Use Wayland input method protocol -- Become a Wayland layer shell -- Remove eekboard-client -- Use sm.puri.OSK0 DBus interface - Pick up DBus interface files from /usr/share Building diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index d6e77047..61f9a32a 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -425,15 +425,6 @@ eek_gtk_keyboard_new (EekKeyboard *keyboard) return g_object_new (EEK_TYPE_GTK_KEYBOARD, "keyboard", keyboard, NULL); } -static EekColor * -color_from_gdk_color (GdkColor *gdk_color) -{ - return eek_color_new (gdk_color->red / (gdouble)0xFFFF, - gdk_color->green / (gdouble)0xFFFF, - gdk_color->blue / (gdouble)0xFFFF, - 1.0); -} - static void magnify_bounds (GtkWidget *self, EekBounds *bounds, @@ -585,7 +576,7 @@ on_key_cancelled (EekKey *key, if (!priv->renderer) return; - render_released_key (self, key); + render_released_key (GTK_WIDGET(self), key); } static void diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index a45e82b7..bb79f5a5 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -256,18 +256,15 @@ set_modifiers_with_key (EekKeyboard *self, void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestamp) { EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(keyboard); - EekSymbol *symbol; - EekModifierType modifier; eek_key_set_pressed(key, TRUE); - key = EEK_KEY(key); priv->pressed_keys = g_list_prepend (priv->pressed_keys, key); - symbol = eek_key_get_symbol_with_fallback (key, 0, 0); + EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0); if (!symbol) return; - modifier = eek_symbol_get_modifier_mask (symbol); + EekModifierType modifier = eek_symbol_get_modifier_mask (symbol); if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) { set_modifiers_with_key (keyboard, key, priv->modifiers | modifier); set_level_from_modifiers (keyboard); @@ -277,11 +274,8 @@ void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestam guint keycode = eek_key_get_keycode (key); guint modifiers = eek_keyboard_get_modifiers (keyboard); - // Insert - EekboardContext ec = {0}; - Client c = {&ec, 0, {0}}; - emit_key_activated(&ec, keycode, symbol, modifiers, &c, TRUE, timestamp); + emit_key_activated(keyboard->manager, keyboard, keycode, symbol, modifiers, TRUE, timestamp); } void eek_keyboard_release_key( EekKeyboard *keyboard, @@ -328,11 +322,8 @@ void eek_keyboard_release_key( EekKeyboard *keyboard, guint keycode = eek_key_get_keycode (key); guint modifiers = eek_keyboard_get_modifiers (keyboard); - // Insert - EekboardContext ec = {0}; - Client c = {&ec, 0, {0}}; - emit_key_activated(&ec, keycode, symbol, modifiers, &c, FALSE, timestamp); + emit_key_activated(keyboard->manager, keyboard, keycode, symbol, modifiers, FALSE, timestamp); } static void diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index 65995e76..8759f077 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -26,6 +26,7 @@ #define EEK_KEYBOARD_H 1 #include +#include #include "eek-container.h" #include "eek-types.h" #include "eek-layout.h" @@ -56,6 +57,11 @@ struct _EekKeyboard EekContainer parent; EekKeyboardPrivate *priv; + struct xkb_keymap *keymap; + int keymap_fd; // keymap formatted as XKB string + size_t keymap_len; // length of the data inside keymap_fd + + EekboardContextService *manager; // unowned reference }; /** @@ -115,12 +121,13 @@ struct _EekModifierKey { }; typedef struct _EekModifierKey EekModifierKey; -GType eek_keyboard_get_type - (void) G_GNUC_CONST; -EekKeyboard *eek_keyboard_new (EekLayout *layout, +EekKeyboard *eek_keyboard_new (EekboardContextService *manager, + EekLayout *layout, gdouble initial_width, gdouble initial_height); +GType eek_keyboard_get_type + (void) G_GNUC_CONST; EekLayout *eek_keyboard_get_layout (EekKeyboard *keyboard); void eek_keyboard_get_size diff --git a/eek/eek-layout.c b/eek/eek-layout.c index cc13f8ec..d2e2780b 100644 --- a/eek/eek-layout.c +++ b/eek/eek-layout.c @@ -32,6 +32,7 @@ #include "eek-layout.h" #include "eek-keyboard.h" +#include "eekboard/eekboard-context-service.h" G_DEFINE_ABSTRACT_TYPE (EekLayout, eek_layout, G_TYPE_OBJECT); @@ -55,14 +56,16 @@ eek_layout_init (EekLayout *self) * Create a new #EekKeyboard based on @layout. */ EekKeyboard * -eek_keyboard_new (EekLayout *layout, +eek_keyboard_new (EekboardContextService *manager, + EekLayout *layout, gdouble initial_width, gdouble initial_height) { g_assert (EEK_IS_LAYOUT(layout)); g_assert (EEK_LAYOUT_GET_CLASS(layout)->create_keyboard); - return EEK_LAYOUT_GET_CLASS(layout)->create_keyboard (layout, + return EEK_LAYOUT_GET_CLASS(layout)->create_keyboard (manager, + layout, initial_width, initial_height); } diff --git a/eek/eek-layout.h b/eek/eek-layout.h index 80771775..1cf44cf7 100644 --- a/eek/eek-layout.h +++ b/eek/eek-layout.h @@ -56,7 +56,8 @@ struct _EekLayoutClass GObjectClass parent_class; /*< public >*/ - EekKeyboard* (* create_keyboard) (EekLayout *self, + EekKeyboard* (* create_keyboard) (EekboardContextService *manager, + EekLayout *self, gdouble initial_width, gdouble initial_height); diff --git a/eek/eek-types.h b/eek/eek-types.h index 749c2614..5bf73aec 100644 --- a/eek/eek-types.h +++ b/eek/eek-types.h @@ -150,6 +150,8 @@ typedef struct _EekBounds EekBounds; typedef struct _EekOutline EekOutline; typedef struct _EekColor EekColor; +typedef struct _EekboardContextService EekboardContextService; + /** * EekPoint: * @x: X coordinate of the point diff --git a/eek/eek-xkb-layout.c b/eek/eek-xkb-layout.c index 2ad5d49e..f4da4cf1 100644 --- a/eek/eek-xkb-layout.c +++ b/eek/eek-xkb-layout.c @@ -320,21 +320,24 @@ create_keyboard (EekXkbLayout *layout, EekKeyboard *keyboard) } static EekKeyboard * -eek_xkb_layout_real_create_keyboard (EekLayout *self, +eek_xkb_layout_real_create_keyboard (EekboardContextService *manager, + EekLayout *self, gdouble initial_width, gdouble initial_height) { - EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self); - EekBounds bounds; - EekKeyboard *keyboard; + EekKeyboard *keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL); + keyboard->manager = manager; - keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", self, NULL); - bounds.x = bounds.y = 0.0; - bounds.width = initial_width; - bounds.height = initial_height; + EekBounds bounds = { + .x = 0.0, + .y = 0.0, + .width = initial_width, + .height = initial_height + }; eek_element_set_bounds (EEK_ELEMENT(keyboard), &bounds); /* resolve modifiers dynamically assigned at run time */ + EekXkbLayoutPrivate *priv = EEK_XKB_LAYOUT_GET_PRIVATE (self); eek_keyboard_set_num_lock_mask (keyboard, XkbKeysymToModifiers (priv->display, XK_Num_Lock)); diff --git a/eek/eek-xml-layout.c b/eek/eek-xml-layout.c index aa2efce2..ccee00be 100644 --- a/eek/eek-xml-layout.c +++ b/eek/eek-xml-layout.c @@ -896,27 +896,25 @@ static const GMarkupParser prerequisites_parser = { }; static EekKeyboard * -eek_xml_layout_real_create_keyboard (EekLayout *self, +eek_xml_layout_real_create_keyboard (EekboardContextService *manager, + EekLayout *self, gdouble initial_width, gdouble initial_height) { EekXmlLayout *layout = EEK_XML_LAYOUT (self); - EekKeyboard *keyboard; - gchar *filename, *path; - GList *loaded; - GError *error; gboolean retval; /* Create an empty keyboard to which geometry and symbols information are applied. */ - keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", layout, NULL); + EekKeyboard *keyboard = g_object_new (EEK_TYPE_KEYBOARD, "layout", layout, NULL); + keyboard->manager = manager; /* Read geometry information. */ - filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry); - path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL); + gchar *filename = g_strdup_printf ("%s.xml", layout->priv->desc->geometry); + gchar *path = g_build_filename (layout->priv->keyboards_dir, "geometry", filename, NULL); g_free (filename); - error = NULL; + GError *error = NULL; retval = parse_geometry (path, keyboard, &error); g_free (path); if (!retval) { @@ -929,7 +927,7 @@ eek_xml_layout_real_create_keyboard (EekLayout *self, } /* Read symbols information. */ - loaded = NULL; + GList *loaded = NULL; retval = parse_symbols_with_prerequisites (layout->priv->keyboards_dir, layout->priv->desc->symbols, keyboard, diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index f16f5a84..83325d0d 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -29,8 +29,17 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ -#include "eekboard/key-emitter.h" #include "eekboard/eekboard-context-service.h" + +#include +#include +#include +#include +#include // TODO: this is Linux-specific +#include + +#include "eekboard/key-emitter.h" +#include "wayland.h" //#include "eekboard/eekboard-xklutil.h" //#include "eek/eek-xkl.h" @@ -116,8 +125,9 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self, g_warning ("can't create keyboard %s: %s", keyboard_type, error->message); g_error_free (error); + keyboard_type = "us"; error = NULL; - layout = eek_xml_layout_new ("us", &error); + layout = eek_xml_layout_new (keyboard_type, &error); if (layout == NULL) { g_error ("failed to create fallback layout: %s", error->message); g_error_free (error); @@ -125,9 +135,54 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self, } } } - keyboard = eek_keyboard_new (layout, CSW, CSH); + keyboard = eek_keyboard_new (self, layout, CSW, CSH); g_object_unref (layout); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + g_error("No context created"); + } + + struct xkb_rule_names rules = { 0 }; + rules.layout = strdup(keyboard_type); + struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, &rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + g_error("Bad keymap"); + } + keyboard->keymap = keymap; + char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); + int f = open("km", O_CREAT|O_WRONLY); + write(f, keymap_str, strlen(keymap_str) + 1); + if (!keymap_str) { + g_error("Keymap was not serialized"); + } + keyboard->keymap_len = strlen(keymap_str) + 1; + char *path = strdup("/eek_keymap-XXXXXX"); + char *r = &path[strlen(path) - 6]; + getrandom(r, 6, GRND_NONBLOCK); + for (uint i = 0; i < 6; i++) { + r[i] = (r[i] & 0b1111111) | 0b1000000; // A-z + r[i] = r[i] > 'z' ? '?' : r[i]; // The randomizer doesn't need to be good... + } + int keymap_fd = shm_open(path, O_RDWR | O_CREAT | O_EXCL, 0600); + if (keymap_fd < 0) { + g_error("Failed to set up keymap fd"); + } + keyboard->keymap_fd = keymap_fd; + shm_unlink(path); + if (ftruncate(keymap_fd, (off_t)keyboard->keymap_len)) { + g_error("Failed to increase keymap fd size"); + } + char *ptr = mmap(NULL, keyboard->keymap_len, PROT_WRITE, MAP_SHARED, + keymap_fd, 0); + if ((void*)ptr == (void*)-1) { + g_error("Failed to set up mmap"); + } + strcpy(ptr, keymap_str); + munmap(ptr, keyboard->keymap_len); + free(keymap_str); + return keyboard; } @@ -233,14 +288,10 @@ settings_get_layout(GSettings *settings, char **type, char **layout) g_variant_iter_free(iter); } - static void settings_update_layout(EekboardContextService *context) { - EekboardContextServiceClass *klass = EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context); - static guint keyboard_id = 0; g_autofree gchar *keyboard_type = NULL; g_autofree gchar *keyboard_layout = NULL; - settings_get_layout(context->priv->settings, &keyboard_type, &keyboard_layout); if (!keyboard_type) { @@ -250,10 +301,13 @@ settings_update_layout(EekboardContextService *context) { keyboard_layout = g_strdup("undefined"); } + // generic part follows + static guint keyboard_id = 0; EekKeyboard *keyboard = g_hash_table_lookup(context->priv->keyboard_hash, GUINT_TO_POINTER(keyboard_id)); // create a keyboard if (!keyboard) { + EekboardContextServiceClass *klass = EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context); keyboard = klass->create_keyboard (context, keyboard_layout); eek_keyboard_set_modifier_behavior (keyboard, EEK_MODIFIER_BEHAVIOR_LATCH); @@ -270,7 +324,6 @@ settings_update_layout(EekboardContextService *context) { context->priv->keyboard = keyboard; // TODO: this used to save the group, why? //group = eek_element_get_group (EEK_ELEMENT(context->priv->keyboard)); - g_object_notify (G_OBJECT(context), "keyboard"); } @@ -278,16 +331,24 @@ static gboolean settings_handle_layout_changed(GSettings *s, gpointer keys, gint n_keys, gpointer user_data) { + (void)s; + (void)keys; + (void)n_keys; EekboardContextService *context = user_data; settings_update_layout(context); return TRUE; } - static void eekboard_context_service_constructed (GObject *object) { EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE (object); + context->virtual_keyboard = zwp_virtual_keyboard_manager_v1_create_virtual_keyboard( + squeek_wayland->virtual_keyboard_manager, + squeek_wayland->seat); + if (!context->virtual_keyboard) { + g_error("Programmer error: Failed to receive a virtual keyboard instance"); + } settings_update_layout(context); } @@ -563,3 +624,11 @@ eekboard_context_service_get_fullscreen (EekboardContextService *context) { return context->priv->fullscreen; } + +void eekboard_context_service_set_keymap(EekboardContextService *context, + const EekKeyboard *keyboard) +{ + zwp_virtual_keyboard_v1_keymap(context->virtual_keyboard, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + keyboard->keymap_fd, keyboard->keymap_len); +} diff --git a/eekboard/eekboard-context-service.h b/eekboard/eekboard-context-service.h index 50ade0b1..3fb5d237 100644 --- a/eekboard/eekboard-context-service.h +++ b/eekboard/eekboard-context-service.h @@ -36,14 +36,15 @@ G_BEGIN_DECLS #define EEKBOARD_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE)) #define EEKBOARD_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass)) -typedef struct _EekboardContextService EekboardContextService; + typedef struct _EekboardContextServiceClass EekboardContextServiceClass; typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate; /** * EekboardContextService: * - * TODO: Restrict to managing keyboard layouts, and maybe button rerpeats. + * TODO: Restrict to managing keyboard layouts, and maybe button repeats, + * and the virtual keyboard protocol. * * The #EekboardContextService structure contains only private data * and should only be accessed using the provided API. @@ -52,6 +53,8 @@ struct _EekboardContextService { GObject parent; EekboardContextServicePrivate *priv; + + struct zwp_virtual_keyboard_v1 *virtual_keyboard; }; /** @@ -96,5 +99,8 @@ EekKeyboard *eekboard_context_service_get_keyboard gboolean eekboard_context_service_get_fullscreen (EekboardContextService *context); +void eekboard_context_service_set_keymap(EekboardContextService *context, + const EekKeyboard *keyboard); + G_END_DECLS #endif /* EEKBOARD_CONTEXT_SERVICE_H */ diff --git a/eekboard/eekboard-service.h b/eekboard/eekboard-service.h index d94c97d0..05f63ae1 100644 --- a/eekboard/eekboard-service.h +++ b/eekboard/eekboard-service.h @@ -41,6 +41,8 @@ typedef struct _EekboardServicePrivate EekboardServicePrivate; /** * EekboardService: * + * Manages DBus interaction. + * * The #EekboardService structure contains only private data and * should only be accessed using the provided API. */ diff --git a/eekboard/key-emitter.c b/eekboard/key-emitter.c index a59d6e81..ea88f9b3 100644 --- a/eekboard/key-emitter.c +++ b/eekboard/key-emitter.c @@ -20,9 +20,24 @@ /* This file is responsible for managing keycode data and emitting keycodes. */ #include "eekboard/key-emitter.h" +#include "eekboard/keymap.h" #include +#include "eekboard/eekboard-context-service.h" + +// TODO: decide whether it's this struct that carries the keyboard around in key-emitter or if the whole manager should be dragged around +// if this is the carrier, then it should be made part of the manager +// hint: check which fields need to be persisted between keypresses; which between keyboards +typedef struct { + struct zwp_virtual_keyboard_v1 *virtual_keyboard; // unowned copy + struct xkb_keymap *keymap; // unowned copy + XkbDescRec *xkb; + guint modifier_keycodes[8]; + gint group; +} SeatEmitter; + + /* The following functions for keyboard mapping change are direct translation of the code in Caribou (in libcaribou/xadapter.vala): @@ -33,7 +48,7 @@ /* Find an unused keycode where a keysym can be assigned. Restricted to Level 1 */ static guint -get_replaced_keycode (Client *client) +get_replaced_keycode (SeatEmitter *client) { guint keycode; return 0; // FIXME: no xkb allocated yet @@ -58,7 +73,7 @@ return 0; // FIXME: no xkb allocated yet non-zero keycode), it simply changes the current map with the specified KEYCODE and KEYSYM. */ static gboolean -replace_keycode (Client *client, +replace_keycode (SeatEmitter *emitter, guint keycode, guint *keysym) { @@ -68,8 +83,8 @@ replace_keycode (Client *client, int keysyms_per_keycode; KeySym *syms; return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine - g_return_val_if_fail (client->xkb->min_key_code <= keycode && - keycode <= client->xkb->max_key_code, + g_return_val_if_fail (emitter->xkb->min_key_code <= keycode && + keycode <= emitter->xkb->max_key_code, FALSE); g_return_val_if_fail (keysym != NULL, FALSE); /* @@ -87,20 +102,19 @@ return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine } static gboolean -get_keycode_from_gdk_keymap (Client *client, +get_keycode_from_gdk_keymap (SeatEmitter *emitter, guint keysym, guint *keycode, guint *modifiers) { - GdkKeymap *keymap = gdk_keymap_get_default (); GdkKeymapKey *keys, *best_match = NULL; - gint n_keys, i; + guint n_keys, i; - if (!gdk_keymap_get_entries_for_keyval (keymap, keysym, &keys, &n_keys)) + if (!squeek_keymap_get_entries_for_keyval (emitter->keymap, keysym, &keys, &n_keys)) return FALSE; for (i = 0; i < n_keys; i++) - if (keys[i].group == client->context->group) + if (keys[i].group == emitter->group) best_match = &keys[i]; if (!best_match) { @@ -115,69 +129,63 @@ get_keycode_from_gdk_keymap (Client *client, return TRUE; } -int WaylandFakeKeyEvent( - Display* dpy, +int send_virtual_keyboard_key( + struct zwp_virtual_keyboard_v1 *keyboard, unsigned int keycode, - Bool is_press, + unsigned is_press, uint32_t timestamp ) { - printf("%d: Sending fake event %d press %d\n", timestamp, keycode, is_press); + zwp_virtual_keyboard_v1_key(keyboard, timestamp, keycode, (unsigned)is_press); return 0; } static void -send_fake_modifier_key_event (Client *client, +send_fake_modifier_key_event (SeatEmitter *emitter, EekModifierType modifiers, gboolean is_pressed, uint32_t timestamp) { - GdkDisplay *display = gdk_display_get_default (); - Display *xdisplay = NULL; //GDK_DISPLAY_XDISPLAY (display); unsigned long i; - for (i = 0; i < G_N_ELEMENTS(client->modifier_keycodes); i++) { + for (i = 0; i < G_N_ELEMENTS(emitter->modifier_keycodes); i++) { if (modifiers & (1 << i)) { - guint keycode = client->modifier_keycodes[i]; + guint keycode = emitter->modifier_keycodes[i]; printf("Trying to send a modifier %ld press %d\n", i, is_pressed); g_return_if_fail (keycode > 0); - WaylandFakeKeyEvent (xdisplay, - keycode, - is_pressed, - timestamp); + send_virtual_keyboard_key (emitter->virtual_keyboard, + keycode, + is_pressed, + timestamp); } } } static void -send_fake_key_event (Client *client, +send_fake_key_event (SeatEmitter *emitter, guint xkeysym, guint keyboard_modifiers, gboolean pressed, uint32_t timestamp) { - GdkDisplay *display = gdk_display_get_default (); - Display *xdisplay = NULL; // GDK_DISPLAY_XDISPLAY (display); EekModifierType modifiers; - guint keycode; guint old_keysym = xkeysym; g_return_if_fail (xkeysym > 0); - modifiers = 0; - if (!get_keycode_from_gdk_keymap (client, xkeysym, &keycode, &modifiers)) { - keycode = get_replaced_keycode (client); + guint keycode; + if (!get_keycode_from_gdk_keymap (emitter, xkeysym, &keycode, &modifiers)) { + keycode = get_replaced_keycode (emitter); if (keycode == 0) { g_warning ("no available keycode to replace"); return; } - if (!replace_keycode (client, keycode, &old_keysym)) { + if (!replace_keycode (emitter, keycode, &old_keysym)) { g_warning ("failed to lookup X keysym %X", xkeysym); return; } } - /* Clear level shift modifiers */ keyboard_modifiers &= (unsigned)~EEK_SHIFT_MASK; keyboard_modifiers &= (unsigned)~EEK_LOCK_MASK; @@ -190,16 +198,18 @@ send_fake_key_event (Client *client, modifiers |= keyboard_modifiers; - send_fake_modifier_key_event (client, modifiers, TRUE, timestamp); - WaylandFakeKeyEvent (xdisplay, keycode, pressed, timestamp); - send_fake_modifier_key_event (client, modifiers, FALSE, timestamp); + send_fake_modifier_key_event (emitter, modifiers, TRUE, timestamp); + + // There's something magical about subtracting/adding 8 to keycodes for some reason + send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp); + send_fake_modifier_key_event (emitter, modifiers, FALSE, timestamp); if (old_keysym != xkeysym) - replace_keycode (client, keycode, &old_keysym); + replace_keycode (emitter, keycode, &old_keysym); } static void -send_fake_key_events (Client *client, +send_fake_key_events (SeatEmitter *emitter, EekSymbol *symbol, guint keyboard_modifiers, gboolean pressed, @@ -239,16 +249,16 @@ send_fake_key_events (Client *client, if (EEK_IS_KEYSYM(symbol)) { guint xkeysym = eek_keysym_get_xkeysym (EEK_KEYSYM(symbol)); - send_fake_key_event (client, xkeysym, keyboard_modifiers, pressed, timestamp); + send_fake_key_event (emitter, xkeysym, keyboard_modifiers, pressed, timestamp); } } void -emit_key_activated (EekboardContext *context, +emit_key_activated (EekboardContextService *manager, + EekKeyboard *keyboard, guint keycode, EekSymbol *symbol, guint modifiers, - Client *client, gboolean pressed, uint32_t timestamp) { @@ -279,12 +289,15 @@ emit_key_activated (EekboardContext *context, return; } */ - send_fake_key_events (client, symbol, modifiers, pressed, timestamp); + SeatEmitter emitter = {0}; + emitter.virtual_keyboard = manager->virtual_keyboard; + emitter.keymap = keyboard->keymap; + send_fake_key_events (&emitter, symbol, modifiers, pressed, timestamp); } /* Finds the first key code for each modifier and saves it in modifier_keycodes */ static void -update_modifier_keycodes (Client *client) +update_modifier_keycodes (SeatEmitter *client) { GdkDisplay *display = gdk_display_get_default (); Display *xdisplay = NULL; // GDK_DISPLAY_XDISPLAY (display); @@ -307,7 +320,7 @@ update_modifier_keycodes (Client *client) } gboolean -client_enable_xtest (Client *client) +client_enable_xtest (SeatEmitter *client) { //GdkDisplay *display = gdk_display_get_default (); //Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); @@ -340,7 +353,7 @@ client_enable_xtest (Client *client) } void -client_disable_xtest (Client *client) +client_disable_xtest (SeatEmitter *client) { //if (client->xkb) { // XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */ diff --git a/eekboard/key-emitter.h b/eekboard/key-emitter.h index 66e06a87..cc79e265 100644 --- a/eekboard/key-emitter.h +++ b/eekboard/key-emitter.h @@ -7,26 +7,12 @@ #include "eek/eek.h" -typedef struct { - gint group; -} EekboardContext; - -typedef struct { - EekboardContext *context; - XkbDescRec *xkb; - guint modifier_keycodes[8]; -} Client; +#include "virtual-keyboard-unstable-v1-client-protocol.h" void -emit_key_activated (EekboardContext *context, +emit_key_activated (EekboardContextService *manager, EekKeyboard *keyboard, guint keycode, EekSymbol *symbol, guint modifiers, - Client *client, gboolean pressed, uint32_t timestamp); - -gboolean -client_enable_xtest (Client *client); - -void -client_disable_xtest (Client *client); + gboolean pressed, uint32_t timestamp); #endif // KEYEMITTER_H diff --git a/eekboard/keymap.c b/eekboard/keymap.c new file mode 100644 index 00000000..2aab1485 --- /dev/null +++ b/eekboard/keymap.c @@ -0,0 +1,66 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2000 Red Hat, Inc. + * Copyright (C) 2019 Purism, SPC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ +/* + * Modified for squeekboard based on GTK + */ + +#include "keymap.h" + +gboolean +squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap, + guint keyval, + GdkKeymapKey **keys, + guint *n_keys) +{ + GArray *retval; + guint keycode; + xkb_keycode_t min_keycode, max_keycode; + retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey)); + min_keycode = xkb_keymap_min_keycode (xkb_keymap); + max_keycode = xkb_keymap_max_keycode (xkb_keymap); + for (keycode = min_keycode; keycode < max_keycode; keycode++) + { + xkb_layout_index_t num_layouts, layout; + num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, keycode); + for (layout = 0; layout < num_layouts; layout++) + { + xkb_layout_index_t num_levels, level; + num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout); + for (level = 0; level < num_levels; level++) + { + const xkb_keysym_t *syms; + gint num_syms, sym; + num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms); + for (sym = 0; sym < num_syms; sym++) + { + if (syms[sym] == keyval) + { + GdkKeymapKey key; + key.keycode = keycode; + key.group = (gint)layout; + key.level = (gint)level; + g_array_append_val (retval, key); + } + } + } + } + } + *n_keys = retval->len; + *keys = (GdkKeymapKey*) g_array_free (retval, FALSE); + return TRUE; +} diff --git a/eekboard/keymap.h b/eekboard/keymap.h new file mode 100644 index 00000000..e33c502e --- /dev/null +++ b/eekboard/keymap.h @@ -0,0 +1,8 @@ +#include +#include + +gboolean +squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap, + guint keyval, + GdkKeymapKey **keys, + guint *n_keys); diff --git a/protocols/meson.build b/protocols/meson.build index 4839b07f..9f5dd496 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -12,6 +12,7 @@ gen_scanner_client_code = generator(wl_scanner, wl_protos = [ wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml', 'wlr-layer-shell-unstable-v1.xml', + 'virtual-keyboard-unstable-v1.xml', ] wl_proto_sources = [] foreach proto: wl_protos diff --git a/protocols/virtual-keyboard-unstable-v1.xml b/protocols/virtual-keyboard-unstable-v1.xml new file mode 100644 index 00000000..df4d01ce --- /dev/null +++ b/protocols/virtual-keyboard-unstable-v1.xml @@ -0,0 +1,113 @@ + + + + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2013 Intel Corporation + Copyright © 2012-2013 Collabora, Ltd. + Copyright © 2018 Purism SPC + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + The virtual keyboard provides an application with requests which emulate + the behaviour of a physical keyboard. + + This interface can be used by clients on its own to provide raw input + events, or it can accompany the input method protocol. + + + + + Provide a file descriptor to the compositor which can be + memory-mapped to provide a keyboard mapping description. + + Format carries a value from the keymap_format enumeration. + + + + + + + + + + + + + A key was pressed or released. + The time argument is a timestamp with millisecond granularity, with an + undefined base. All requests regarding a single object must share the + same clock. + + Keymap must be set before issuing this request. + + State carries a value from the key_state enumeration. + + + + + + + + + Notifies the compositor that the modifier and/or group state has + changed, and it should update state. + + The client should use wl_keyboard.modifiers event to synchronize its + internal state with seat state. + + Keymap must be set before issuing this request. + + + + + + + + + + + + + + + A virtual keyboard manager allows an application to provide keyboard + input events as if they came from a physical keyboard. + + + + + + + + + Creates a new virtual keyboard associated to a seat. + + If the compositor enables a keyboard to perform arbitrary actions, it + should present an error when an untrusted client requests a new + keyboard. + + + + + + diff --git a/src/client-main.c b/src/client-main.c index 4e6bbf2b..d6e04115 100644 --- a/src/client-main.c +++ b/src/client-main.c @@ -88,7 +88,7 @@ enum FocusListenerType { }; static gboolean -set_keyboards (Client *client, +set_keyboards (SeatEmitter *client, const gchar * const *keyboards) { if (g_strv_length ((gchar **)keyboards) == 0) { @@ -110,7 +110,7 @@ set_keyboards (Client *client, int main (int argc, char **argv) { - Client *client = NULL; + SeatEmitter *client = NULL; EekboardClient *eekboard; EekboardContext *context; GBusType bus_type; diff --git a/src/client.c b/src/client.c index 1ace244d..106e26ca 100644 --- a/src/client.c +++ b/src/client.c @@ -101,7 +101,7 @@ struct _ClientClass { GObjectClass parent_class; }; -G_DEFINE_TYPE (Client, client, G_TYPE_OBJECT); +G_DEFINE_TYPE (SeatEmitter, client, G_TYPE_OBJECT); #if ENABLE_FOCUS_LISTENER #define IS_KEYBOARD_VISIBLE(client) (!client->follows_focus) @@ -128,10 +128,10 @@ static void focus_listener_cb (const AtspiEvent *event, static gboolean keystroke_listener_cb (const AtspiDeviceEvent *stroke, void *user_data); #endif /* HAVE_ATSPI */ -static gboolean set_keyboards (Client *client, +static gboolean set_keyboards (SeatEmitter *client, const gchar * const *keyboard); static gboolean set_keyboards_from_xkl - (Client *client); + (SeatEmitter *client); #ifdef HAVE_XTEST static void update_modifier_keycodes (Client *client); @@ -143,7 +143,7 @@ client_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - Client *client = CLIENT(object); + SeatEmitter *client = CLIENT(object); GDBusConnection *connection; gchar **keyboards; @@ -188,7 +188,7 @@ client_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - Client *client = CLIENT(object); + SeatEmitter *client = CLIENT(object); switch (prop_id) { case PROP_EEKBOARD: @@ -206,7 +206,7 @@ client_get_property (GObject *object, static void client_dispose (GObject *object) { - Client *client = CLIENT(object); + SeatEmitter *client = CLIENT(object); client_disable_xkl (client); @@ -246,7 +246,7 @@ client_dispose (GObject *object) static void client_finalize (GObject *object) { - Client *client = CLIENT(object); + SeatEmitter *client = CLIENT(object); g_slist_free (client->keyboards); G_OBJECT_CLASS (client_parent_class)->finalize (object); @@ -301,13 +301,13 @@ client_class_init (ClientClass *klass) } static void -client_init (Client *client) +client_init (SeatEmitter *client) { client->settings = g_settings_new ("org.fedorahosted.eekboard"); } gboolean -client_set_keyboards (Client *client, +client_set_keyboards (SeatEmitter *client, const gchar * const *keyboards) { gboolean retval; @@ -318,7 +318,7 @@ client_set_keyboards (Client *client, } gboolean -client_enable_xkl (Client *client) +client_enable_xkl (SeatEmitter *client) { GdkDisplay *display = gdk_display_get_default (); gboolean retval; @@ -361,7 +361,7 @@ client_enable_xkl (Client *client) } void -client_disable_xkl (Client *client) +client_disable_xkl (SeatEmitter *client) { if (client->xkl_engine) { xkl_engine_stop_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE); @@ -618,7 +618,7 @@ add_match_rule (GDBusConnection *connection, } static gboolean -on_hide_keyboard_timeout (Client *client) +on_hide_keyboard_timeout (SeatEmitter *client) { eekboard_client_hide_keyboard (client->eekboard, NULL); client->hide_keyboard_timeout_id = 0; @@ -631,7 +631,7 @@ focus_message_filter (GDBusConnection *connection, gboolean incoming, gpointer user_data) { - Client *client = user_data; + SeatEmitter *client = user_data; if (incoming && g_strcmp0 (g_dbus_message_get_interface (message), @@ -661,7 +661,7 @@ focus_message_filter (GDBusConnection *connection, static void _ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data) { - Client *client = user_data; + SeatEmitter *client = user_data; add_match_rule (connection, "type='method_call'," @@ -679,7 +679,7 @@ _ibus_connect_focus_handlers (GDBusConnection *connection, gpointer user_data) } gboolean -client_enable_ibus_focus (Client *client) +client_enable_ibus_focus (SeatEmitter *client) { if (client->ibus_connection == NULL) { const gchar *ibus_address; @@ -711,7 +711,7 @@ client_enable_ibus_focus (Client *client) } void -client_disable_ibus_focus (Client *client) +client_disable_ibus_focus (SeatEmitter *client) { client->follows_focus = FALSE; @@ -725,10 +725,10 @@ client_disable_ibus_focus (Client *client) } } -Client * +SeatEmitter * client_new (GDBusConnection *connection) { - Client *client = g_object_new (TYPE_CLIENT, + SeatEmitter *client = g_object_new (TYPE_CLIENT, "connection", connection, NULL); if (client->context) @@ -741,7 +741,7 @@ filter_xkl_event (GdkXEvent *xev, GdkEvent *event, gpointer user_data) { - Client *client = user_data; + SeatEmitter *client = user_data; XEvent *xevent = (XEvent *)xev; xkl_engine_filter_events (client->xkl_engine, xevent); @@ -752,7 +752,7 @@ static void on_xkl_config_changed (XklEngine *xklengine, gpointer user_data) { - Client *client = user_data; + SeatEmitter *client = user_data; gboolean retval; retval = set_keyboards_from_xkl (client); @@ -764,7 +764,7 @@ on_xkl_config_changed (XklEngine *xklengine, } static gboolean -set_keyboards (Client *client, +set_keyboards (SeatEmitter *client, const gchar * const *keyboards) { guint keyboard_id; @@ -805,7 +805,7 @@ set_keyboards (Client *client, } static gboolean -set_keyboards_from_xkl (Client *client) +set_keyboards_from_xkl (SeatEmitter *client) { XklConfigRec *rec; gchar *layout, *keyboard; @@ -837,7 +837,7 @@ on_xkl_state_changed (XklEngine *xklengine, gboolean restore, gpointer user_data) { - Client *client = user_data; + SeatEmitter *client = user_data; if (type == GROUP_CHANGED) eekboard_context_set_group (client->context, value, NULL); @@ -851,7 +851,7 @@ on_xkl_state_changed (XklEngine *xklengine, - get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match) */ static guint -get_replaced_keycode (Client *client) +get_replaced_keycode (SeatEmitter *client) { guint keycode; @@ -876,7 +876,7 @@ get_replaced_keycode (Client *client) non-zero keycode), it simply changes the current map with the specified KEYCODE and KEYSYM. */ static gboolean -replace_keycode (Client *client, +replace_keycode (SeatEmitter *client, guint keycode, guint *keysym) { @@ -904,7 +904,7 @@ return TRUE; // FIXME: no xkb allocated at the moment, pretending all is fine } static gboolean -get_keycode_from_gdk_keymap (Client *client, +get_keycode_from_gdk_keymap (SeatEmitter *client, guint keysym, guint *keycode, guint *modifiers) @@ -932,7 +932,7 @@ get_keycode_from_gdk_keymap (Client *client, return TRUE; } -int WaylandFakeKeyEvent( +int send_virtual_keyboard_key( Display* dpy, unsigned int keycode, Bool is_press, @@ -943,7 +943,7 @@ int WaylandFakeKeyEvent( /* never actually used? */ static void -send_fake_modifier_key_event (Client *client, +send_fake_modifier_key_event (SeatEmitter *client, EekModifierType modifiers, gboolean is_pressed) { @@ -957,7 +957,7 @@ send_fake_modifier_key_event (Client *client, printf("Trying to send a modifier %d press %d\n", i, is_pressed); g_return_if_fail (keycode > 0); - WaylandFakeKeyEvent (xdisplay, + send_virtual_keyboard_key (xdisplay, keycode, is_pressed, CurrentTime); @@ -967,7 +967,7 @@ send_fake_modifier_key_event (Client *client, } static void -send_fake_key_event (Client *client, +send_fake_key_event (SeatEmitter *client, guint xkeysym, guint keyboard_modifiers) { @@ -1006,9 +1006,9 @@ send_fake_key_event (Client *client, modifiers |= keyboard_modifiers; send_fake_modifier_key_event (client, modifiers, TRUE); - WaylandFakeKeyEvent (xdisplay, keycode, TRUE, 20); + send_virtual_keyboard_key (xdisplay, keycode, TRUE, 20); //XSync (xdisplay, False); - WaylandFakeKeyEvent (xdisplay, keycode, FALSE, 20); + send_virtual_keyboard_key (xdisplay, keycode, FALSE, 20); // XSync (xdisplay, False); send_fake_modifier_key_event (client, modifiers, FALSE); @@ -1017,7 +1017,7 @@ send_fake_key_event (Client *client, } static void -send_fake_key_events (Client *client, +send_fake_key_events (SeatEmitter *client, EekSymbol *symbol, guint keyboard_modifiers) { @@ -1063,7 +1063,7 @@ on_key_activated (EekboardContext *context, guint modifiers, gpointer user_data) { - Client *client = user_data; + SeatEmitter *client = user_data; if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) { client->keyboards_head = g_slist_next (client->keyboards_head); @@ -1119,7 +1119,7 @@ update_modifier_keycodes (Client *client) } #endif gboolean -client_enable_xtest (Client *client) +client_enable_xtest (SeatEmitter *client) { //GdkDisplay *display = gdk_display_get_default (); //Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); @@ -1156,7 +1156,7 @@ client_enable_xtest (Client *client) } void -client_disable_xtest (Client *client) +client_disable_xtest (SeatEmitter *client) { //if (client->xkb) { // XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */ diff --git a/src/client.h b/src/client.h index 63099223..749b779d 100644 --- a/src/client.h +++ b/src/client.h @@ -29,27 +29,27 @@ G_BEGIN_DECLS #define IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLIENT)) #define CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLIENT, ClientClass)) -typedef struct _Client Client; +typedef struct _Client SeatEmitter; -Client *client_new (GDBusConnection *connection); +SeatEmitter *client_new (GDBusConnection *connection); -gboolean client_set_keyboards (Client *client, +gboolean client_set_keyboards (SeatEmitter *client, const gchar * const *keyboard); -gboolean client_enable_xkl (Client *client); -void client_disable_xkl (Client *client); +gboolean client_enable_xkl (SeatEmitter *client); +void client_disable_xkl (SeatEmitter *client); -gboolean client_enable_atspi_focus (Client *client); -void client_disable_atspi_focus (Client *client); +gboolean client_enable_atspi_focus (SeatEmitter *client); +void client_disable_atspi_focus (SeatEmitter *client); -gboolean client_enable_atspi_keystroke (Client *client); -void client_disable_atspi_keystroke (Client *client); +gboolean client_enable_atspi_keystroke (SeatEmitter *client); +void client_disable_atspi_keystroke (SeatEmitter *client); -gboolean client_enable_xtest (Client *client); -void client_disable_xtest (Client *client); +gboolean client_enable_xtest (SeatEmitter *client); +void client_disable_xtest (SeatEmitter *client); -gboolean client_enable_ibus_focus (Client *client); -void client_disable_ibus_focus (Client *client); +gboolean client_enable_ibus_focus (SeatEmitter *client); +void client_disable_ibus_focus (SeatEmitter *client); G_END_DECLS #endif /* CLIENT_H */ diff --git a/src/meson.build b/src/meson.build index 83654e21..787edc94 100644 --- a/src/meson.build +++ b/src/meson.build @@ -34,6 +34,7 @@ sources = [ enums, keysym_entries, marshalers, + '../eekboard/keymap.c', '../eekboard/key-emitter.c', '../eekboard/eekboard-context-service.c', '../eekboard/eekboard-context.c', @@ -51,7 +52,9 @@ deps = [ dependency('gtk+-3.0', version: '>=3.0'), dependency('libcroco-0.6'), dependency('wayland-client', version: '>=1.14'), + dependency('xkbcommon'), cc.find_library('m'), + cc.find_library('rt'), # dependency('libxklavier'), # FIXME remove ] diff --git a/src/server-context-service.c b/src/server-context-service.c index 05315a5e..32e3b078 100644 --- a/src/server-context-service.c +++ b/src/server-context-service.c @@ -95,6 +95,17 @@ on_notify_keyboard (GObject *object, const EekKeyboard *keyboard; keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context)); + + if (!keyboard) { + g_error("Programmer error: keyboard layout was unset!"); + } + + // 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(EEKBOARD_CONTEXT_SERVICE(context), + keyboard); + if (context->window) { if (keyboard == NULL) { gtk_widget_hide (context->window); @@ -106,8 +117,9 @@ on_notify_keyboard (GObject *object, g_signal_handler_block (context->window, context->notify_visible_handler); update_widget (context); - if (was_visible) + if (was_visible) { gtk_widget_show_all (context->window); + } g_signal_handler_unblock (context->window, context->notify_visible_handler); } @@ -492,9 +504,9 @@ server_context_service_init (ServerContextService *context) context); } -ServerContextService * +EekboardContextService * server_context_service_new () { - return g_object_new (SERVER_TYPE_CONTEXT_SERVICE, - NULL); + return EEKBOARD_CONTEXT_SERVICE(g_object_new (SERVER_TYPE_CONTEXT_SERVICE, + NULL)); } diff --git a/src/server-context-service.h b/src/server-context-service.h index 49745dc1..6a20b62c 100644 --- a/src/server-context-service.h +++ b/src/server-context-service.h @@ -32,7 +32,7 @@ G_BEGIN_DECLS /** Manages the liecycle of the window displaying layouts. */ typedef struct _ServerContextService ServerContextService; -ServerContextService *server_context_service_new (); +EekboardContextService *server_context_service_new (); G_END_DECLS #endif /* SERVER_CONTEXT_SERVICE_H */ diff --git a/src/server-main.c b/src/server-main.c index 896268d7..ca7ee1c1 100644 --- a/src/server-main.c +++ b/src/server-main.c @@ -38,6 +38,14 @@ #include + +/// Global application state +struct squeekboard { + struct squeek_wayland wayland; + EekboardContextService *context; +}; + + static gboolean opt_system = FALSE; static gchar *opt_address = NULL; @@ -93,17 +101,25 @@ registry_handle_global (void *data, const char *interface, uint32_t version) { - struct squeek_wayland *wayland = data; + // currently only v1 supported for most interfaces, + // so there's no reason to check for available versions. + // Even when lower version would be served, it would not be supported, + // causing a hard exit + (void)version; + struct squeekboard *instance = data; if (!strcmp (interface, zwlr_layer_shell_v1_interface.name)) { - wayland->layer_shell = wl_registry_bind (registry, name, + instance->wayland.layer_shell = wl_registry_bind (registry, name, &zwlr_layer_shell_v1_interface, 1); + } 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, "wl_output")) { struct wl_output *output = wl_registry_bind (registry, name, &wl_output_interface, 2); - g_ptr_array_add (wayland->outputs, output); + g_ptr_array_add (instance->wayland.outputs, output); } else if (!strcmp(interface, "wl_seat")) { - wayland->seat = wl_registry_bind(registry, name, + instance->wayland.seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); } } @@ -139,17 +155,33 @@ main (int argc, char **argv) if (display == NULL) { g_error ("Failed to get display: %m\n"); + exit(1); } - struct squeek_wayland wayland = {0}; - squeek_wayland_init (&wayland); - struct wl_registry *registry = wl_display_get_registry (display); - wl_registry_add_listener (registry, ®istry_listener, &wayland); - squeek_wayland_set_global(&wayland); - EekboardContextService *context = create_context(); + struct squeekboard instance = {0}; + squeek_wayland_init (&instance.wayland); + struct wl_registry *registry = wl_display_get_registry (display); + wl_registry_add_listener (registry, ®istry_listener, &instance); + wl_display_roundtrip(display); // wait until the registry is actually populated + squeek_wayland_set_global(&instance.wayland); + + if (!instance.wayland.seat) { + g_error("No seat Wayland global available."); + exit(1); + } + if (!instance.wayland.virtual_keyboard_manager) { + g_error("No virtual keyboard manager Wayland global available."); + exit(1); + } + + instance.context = create_context(); + // set up dbus + // TODO: make dbus errors non-always-fatal + // dbus is not strictly necessary for the useful operation + // if text-input is used, as it can bring the keyboard in and out GBusType bus_type; if (opt_system) bus_type = G_BUS_TYPE_SYSTEM; @@ -191,16 +223,13 @@ main (int argc, char **argv) break; } - // TODO: make dbus errors non-always-fatal - // dbus is not strictly necessary for the useful operation - // if text-input is used, as it can bring the keyboard in and out EekboardService *service = eekboard_service_new (connection, EEKBOARD_SERVICE_PATH); if (service == NULL) { - g_printerr ("Can't create server\n"); + g_printerr ("Can't create dbus server\n"); exit (1); } else { - eekboard_service_set_context(service, context); + eekboard_service_set_context(service, instance.context); } guint owner_id = g_bus_own_name_on_connection (connection, @@ -226,6 +255,6 @@ main (int argc, char **argv) g_object_unref (connection); g_main_loop_unref (loop); - squeek_wayland_deinit (&wayland); + squeek_wayland_deinit (&instance.wayland); return 0; } diff --git a/src/wayland.h b/src/wayland.h index 36dae5d1..16f463e8 100644 --- a/src/wayland.h +++ b/src/wayland.h @@ -2,12 +2,14 @@ #define WAYLAND_H #include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "virtual-keyboard-unstable-v1-client-protocol.h" #include struct squeek_wayland { struct zwlr_layer_shell_v1 *layer_shell; + struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager; GPtrArray *outputs; // *wl_output struct wl_seat *seat; };