diff --git a/clutter/clutter/evdev/clutter-device-manager-evdev.c b/clutter/clutter/evdev/clutter-device-manager-evdev.c index b42b57665..c03c68cec 100644 --- a/clutter/clutter/evdev/clutter-device-manager-evdev.c +++ b/clutter/clutter/evdev/clutter-device-manager-evdev.c @@ -2530,6 +2530,60 @@ clutter_evdev_set_keyboard_layout_index (ClutterDeviceManager *evdev, xkb_state_update_mask (state, depressed_mods, latched_mods, locked_mods, 0, 0, idx); } +/** + * clutter_evdev_set_keyboard_numlock: (skip) + * @evdev: the #ClutterDeviceManager created by the evdev backend + * @numlock_set: TRUE to set NumLock ON, FALSE otherwise. + * + * Sets the NumLock state on the backend's #xkb_state . + * + * Stability: unstable + */ +void +clutter_evdev_set_keyboard_numlock (ClutterDeviceManager *evdev, + gboolean numlock_state) +{ + ClutterDeviceManagerEvdev *manager_evdev; + ClutterDeviceManagerEvdevPrivate *priv; + GSList *iter; + xkb_mod_mask_t numlock; + + g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev)); + + manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev); + priv = manager_evdev->priv; + numlock = (1 << xkb_keymap_mod_get_index(priv->keymap, "Mod2")); + + for (iter = priv->seats; iter; iter = iter->next) + { + ClutterSeatEvdev *seat = iter->data; + xkb_mod_mask_t depressed_mods; + xkb_mod_mask_t latched_mods; + xkb_mod_mask_t locked_mods; + xkb_mod_mask_t group_mods; + + depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); + latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); + locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); + group_mods = xkb_state_serialize_layout (seat->xkb, XKB_STATE_LAYOUT_EFFECTIVE); + + if (numlock_state) + locked_mods |= numlock; + else + locked_mods &= ~numlock; + + xkb_state_update_mask (seat->xkb, + depressed_mods, + latched_mods, + locked_mods, + 0, 0, + group_mods); + + clutter_seat_evdev_sync_leds (seat); + } +} + + /** * clutter_evdev_set_pointer_constrain_callback: * @evdev: the #ClutterDeviceManager created by the evdev backend diff --git a/clutter/clutter/evdev/clutter-evdev.h b/clutter/clutter/evdev/clutter-evdev.h index be8748f96..1f5485c17 100644 --- a/clutter/clutter/evdev/clutter-evdev.h +++ b/clutter/clutter/evdev/clutter-evdev.h @@ -105,6 +105,10 @@ CLUTTER_AVAILABLE_IN_1_20 void clutter_evdev_set_keyboard_layout_index (ClutterDeviceManager *evdev, xkb_layout_index_t idx); +CLUTTER_AVAILABLE_IN_1_26 +void clutter_evdev_set_keyboard_numlock (ClutterDeviceManager *evdev, + gboolean numlock_state); + CLUTTER_AVAILABLE_IN_1_18 void clutter_evdev_set_keyboard_repeat (ClutterDeviceManager *evdev, gboolean repeat, diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index ee85e8ae6..b8abccf31 100644 --- a/src/backends/meta-backend-private.h +++ b/src/backends/meta-backend-private.h @@ -103,6 +103,9 @@ struct _MetaBackendClass double *dy, double *dx_unaccel, double *dy_unaccel); + void (* set_numlock) (MetaBackend *backend, + gboolean numlock_state); + }; void meta_init_backend (MetaBackendType backend_type); diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 8c97765c0..872d0d38f 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -542,6 +542,14 @@ meta_backend_lock_layout_group (MetaBackend *backend, META_BACKEND_GET_CLASS (backend)->lock_layout_group (backend, idx); } +void +meta_backend_set_numlock (MetaBackend *backend, + gboolean numlock_state) +{ + META_BACKEND_GET_CLASS (backend)->set_numlock (backend, numlock_state); +} + + /** * meta_backend_get_stage: * @backend: A #MetaBackend diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index 385122c32..09b235b43 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -368,6 +368,14 @@ meta_backend_native_lock_layout_group (MetaBackend *backend, g_signal_emit_by_name (backend, "keymap-layout-group-changed", idx, 0); } +static void +meta_backend_native_set_numlock (MetaBackend *backend, + gboolean numlock_state) +{ + ClutterDeviceManager *manager = clutter_device_manager_get_default (); + clutter_evdev_set_keyboard_numlock (manager, numlock_state); +} + static gboolean meta_backend_native_get_relative_motion_deltas (MetaBackend *backend, const ClutterEvent *event, @@ -421,6 +429,7 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass) backend_class->lock_layout_group = meta_backend_native_lock_layout_group; backend_class->get_relative_motion_deltas = meta_backend_native_get_relative_motion_deltas; backend_class->update_screen_size = meta_backend_native_update_screen_size; + backend_class->set_numlock = meta_backend_native_set_numlock; } static void diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index c9a6b9af0..a0b196efe 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -805,6 +805,14 @@ meta_backend_x11_lock_layout_group (MetaBackend *backend, XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, idx); } +static void +meta_backend_x11_set_numlock (MetaBackend *backend, + gboolean numlock_state) +{ + /* TODO: Currently handled by gnome-settings-deamon */ +} + + static void meta_backend_x11_update_screen_size (MetaBackend *backend, int width, int height) @@ -897,6 +905,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass) backend_class->lock_layout_group = meta_backend_x11_lock_layout_group; backend_class->update_screen_size = meta_backend_x11_update_screen_size; backend_class->select_stage_events = meta_backend_x11_select_stage_events; + backend_class->set_numlock = meta_backend_x11_set_numlock; } static void diff --git a/src/meta/meta-backend.h b/src/meta/meta-backend.h index c50429abe..fad8f558b 100644 --- a/src/meta/meta-backend.h +++ b/src/meta/meta-backend.h @@ -44,6 +44,9 @@ void meta_backend_set_keymap (MetaBackend *backend, void meta_backend_lock_layout_group (MetaBackend *backend, guint idx); +void meta_backend_set_numlock (MetaBackend *backend, + gboolean numlock_state); + ClutterActor *meta_backend_get_stage (MetaBackend *backend); void meta_clutter_init (void); diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c index d50578313..7f267b155 100644 --- a/src/wayland/meta-wayland-keyboard.c +++ b/src/wayland/meta-wayland-keyboard.c @@ -65,9 +65,19 @@ #include "backends/native/meta-backend-native.h" #endif +#define GSD_KEYBOARD_SCHEMA "org.gnome.settings-daemon.peripherals.keyboard" +typedef enum +{ + GSD_KEYBOARD_NUM_LOCK_STATE_UNKNOWN, + GSD_KEYBOARD_NUM_LOCK_STATE_ON, + GSD_KEYBOARD_NUM_LOCK_STATE_OFF +} GsdKeyboardNumLockState; + G_DEFINE_TYPE (MetaWaylandKeyboard, meta_wayland_keyboard, G_TYPE_OBJECT); static void meta_wayland_keyboard_update_xkb_state (MetaWaylandKeyboard *keyboard); +static void meta_wayland_keyboard_set_numlock (MetaWaylandKeyboard *keyboard, + gboolean numlock_state); static void notify_modifiers (MetaWaylandKeyboard *keyboard); static guint evdev_code (const ClutterKeyEvent *event); @@ -361,6 +371,107 @@ notify_modifiers (MetaWaylandKeyboard *keyboard) xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE)); } +static void +numlock_set_xkb_state (MetaWaylandKeyboard *keyboard, + GsdKeyboardNumLockState state) +{ + MetaBackend *backend = meta_get_backend (); + gboolean numlock_state; + + if (state != GSD_KEYBOARD_NUM_LOCK_STATE_ON && + state != GSD_KEYBOARD_NUM_LOCK_STATE_OFF) + return; + + numlock_state = (state == GSD_KEYBOARD_NUM_LOCK_STATE_ON); + meta_verbose ("set numlock state %s\n", (numlock_state ? "ON" : "OFF")); + meta_backend_set_numlock (backend, numlock_state); + meta_wayland_keyboard_set_numlock (keyboard, numlock_state); +} + +static void +maybe_restore_numlock_state (MetaWaylandKeyboard *keyboard) +{ + gboolean remember_numlock; + + if (!keyboard->gsd_settings) + return; + + /* We are cheating for now, we use g-s-d settings... */ + remember_numlock = g_settings_get_boolean (keyboard->gsd_settings, + "remember-numlock-state"); + + if (remember_numlock) + { + GsdKeyboardNumLockState state; + + state = g_settings_get_enum (keyboard->gsd_settings, "numlock-state"); + numlock_set_xkb_state (keyboard, state); + } +} + +static void +maybe_save_numlock_state (MetaWaylandKeyboard *keyboard) +{ + MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info; + GDesktopKeyboardNumLockState numlock_state; + int numlock_active; + + if (!META_IS_BACKEND_NATIVE (meta_get_backend ())) + return; + + if (!xkb_info->state) + return; + + if (!keyboard->gsd_settings) + return; + + if (!g_settings_get_boolean (keyboard->gsd_settings, "remember-numlock-state")) + return; + + numlock_active = xkb_state_mod_name_is_active(xkb_info->state, + "Mod2", + XKB_STATE_MODS_LOCKED); + switch (numlock_active) + { + case -1: + numlock_state = GSD_KEYBOARD_NUM_LOCK_STATE_UNKNOWN; + break; + case 0: + numlock_state = GSD_KEYBOARD_NUM_LOCK_STATE_OFF; + break; + default: + numlock_state = GSD_KEYBOARD_NUM_LOCK_STATE_ON; + break; + } + g_settings_set_enum (keyboard->gsd_settings, "numlock-state", numlock_state); +} + +static void +meta_wayland_keyboard_set_numlock (MetaWaylandKeyboard *keyboard, + gboolean numlock_state) +{ + MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info; + xkb_mod_mask_t latched, locked, group, depressed; + xkb_mod_mask_t numlock; + + meta_verbose ("backend numlock state %s\n", (numlock_state ? "ON" : "OFF")); + + latched = xkb_state_serialize_mods (xkb_info->state, XKB_STATE_MODS_LATCHED); + locked = xkb_state_serialize_mods (xkb_info->state, XKB_STATE_MODS_LOCKED); + group = xkb_state_serialize_layout (xkb_info->state, XKB_STATE_LAYOUT_EFFECTIVE); + depressed = xkb_state_serialize_mods(xkb_info->state, XKB_STATE_DEPRESSED); + numlock = (1 << xkb_keymap_mod_get_index(xkb_info->keymap, "Mod2")); + + if (numlock_state == TRUE) + locked |= numlock; + else + locked &= ~numlock; + + xkb_state_update_mask (xkb_info->state, depressed, latched, locked, 0, 0, group); + + notify_modifiers (keyboard); +} + static void meta_wayland_keyboard_update_xkb_state (MetaWaylandKeyboard *keyboard) { @@ -430,6 +541,16 @@ notify_key_repeat (MetaWaylandKeyboard *keyboard) } } +static void +remember_numlock_state_changed (GSettings *settings, + const char *key, + gpointer data) +{ + MetaWaylandKeyboard *keyboard = data; + + maybe_save_numlock_state (keyboard); +} + static void settings_changed (GSettings *settings, const char *key, @@ -484,6 +605,7 @@ meta_wayland_keyboard_enable (MetaWaylandKeyboard *keyboard, MetaWaylandSeat *seat) { MetaBackend *backend = meta_get_backend (); + GSettingsSchema *schema; keyboard->seat = seat; @@ -502,11 +624,25 @@ meta_wayland_keyboard_enable (MetaWaylandKeyboard *keyboard, g_signal_connect (keyboard->settings, "changed", G_CALLBACK (settings_changed), keyboard); + /* We are cheating for now, we use g-s-d settings... Check if available */ + schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (), + GSD_KEYBOARD_SCHEMA, + TRUE); + if (schema) + { + keyboard->gsd_settings = g_settings_new_full (schema, NULL, NULL); + g_settings_schema_unref (schema); + g_signal_connect (keyboard->gsd_settings, "changed::remember-numlock-state", + G_CALLBACK (remember_numlock_state_changed), keyboard); + } + g_signal_connect (backend, "keymap-changed", G_CALLBACK (on_keymap_changed), keyboard); g_signal_connect (backend, "keymap-layout-group-changed", G_CALLBACK (on_keymap_layout_group_changed), keyboard); meta_wayland_keyboard_take_keymap (keyboard, meta_backend_get_keymap (backend)); + + maybe_restore_numlock_state (keyboard); } static void @@ -538,6 +674,8 @@ meta_wayland_keyboard_disable (MetaWaylandKeyboard *keyboard) /* XXX: What about keyboard->resource_list? */ g_clear_object (&keyboard->settings); + if (keyboard->gsd_settings) + g_object_unref (keyboard->gsd_settings); keyboard->seat = NULL; } @@ -593,6 +731,8 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, if (keyboard->mods_changed != 0) { + if (keyboard->mods_changed & XKB_STATE_MODS_LOCKED) + maybe_save_numlock_state (keyboard); notify_modifiers (keyboard); keyboard->mods_changed = 0; } diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h index 5f7d15c5b..5e7d84b2f 100644 --- a/src/wayland/meta-wayland-keyboard.h +++ b/src/wayland/meta-wayland-keyboard.h @@ -100,6 +100,7 @@ struct _MetaWaylandKeyboard MetaWaylandKeyboardGrab default_grab; GSettings *settings; + GSettings *gsd_settings; }; void meta_wayland_keyboard_enable (MetaWaylandKeyboard *keyboard,