commit 82c7fcf7fd4fe43e73ea5ce6408c79d35ec3dfb8
Author: Andrew Potter <agpotter@gmail.com>
Date:   Wed Oct 24 13:52:09 2012 -0700

    keyboard: Prevent potential infinite loop
    
    Ensure we don't set the numlock setting in response to our own
    numlock-setting event.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=679151

diff --git a/plugins/keyboard/gsd-keyboard-manager.c b/plugins/keyboard/gsd-keyboard-manager.c
index a33460c..1519510 100644
--- a/plugins/keyboard/gsd-keyboard-manager.c
+++ b/plugins/keyboard/gsd-keyboard-manager.c
@@ -73,6 +73,7 @@ struct GsdKeyboardManagerPrivate
         gboolean   have_xkb;
         gint       xkb_event_base;
         GsdNumLockState old_state;
+        gulong     numlock_serial;
 };
 
 static void     gsd_keyboard_manager_class_init  (GsdKeyboardManagerClass *klass);
@@ -128,13 +129,15 @@ numlock_NumLock_modifier_mask (void)
 }
 
 static void
-numlock_set_xkb_state (GsdNumLockState new_state)
+numlock_set_xkb_state (GsdKeyboardManager *manager)
 {
         unsigned int num_mask;
         Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+        GsdNumLockState new_state = manager->priv->old_state;
         if (new_state != GSD_NUM_LOCK_STATE_ON && new_state != GSD_NUM_LOCK_STATE_OFF)
                 return;
         num_mask = numlock_NumLock_modifier_mask ();
+        manager->priv->numlock_serial = NextRequest(dpy);
         XkbLockModifiers (dpy, XkbUseCoreKbd, num_mask, new_state == GSD_NUM_LOCK_STATE_ON ? num_mask : 0);
 }
 
@@ -156,16 +159,18 @@ numlock_xkb_callback (GdkXEvent *xev_,
 	if (xkbev->state.changed & XkbModifierLockMask) {
 		unsigned num_mask = numlock_NumLock_modifier_mask ();
 		unsigned locked_mods = xkbev->state.locked_mods;
+                unsigned long serial = xkbev->state.serial;
 		GsdNumLockState numlock_state;
 
 		numlock_state = (num_mask & locked_mods) ? GSD_NUM_LOCK_STATE_ON : GSD_NUM_LOCK_STATE_OFF;
 
-		if (numlock_state != manager->priv->old_state) {
-			g_settings_set_enum (manager->priv->settings,
-					     KEY_NUMLOCK_STATE,
-					     numlock_state);
-			manager->priv->old_state = numlock_state;
-		}
+		if (numlock_state != manager->priv->old_state
+                    && serial > manager->priv->numlock_serial) {
+                                g_settings_set_enum (manager->priv->settings,
+                                                     KEY_NUMLOCK_STATE,
+                                                     numlock_state);
+                                manager->priv->old_state = numlock_state;
+                }
 	}
 
         return GDK_FILTER_CONTINUE;
@@ -254,7 +259,7 @@ apply_settings (GSettings          *settings,
         manager->priv->old_state = g_settings_get_enum (manager->priv->settings, KEY_NUMLOCK_STATE);
 
         if (manager->priv->have_xkb && rnumlock)
-                numlock_set_xkb_state (manager->priv->old_state);
+                numlock_set_xkb_state (manager);
 
         XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE);
         gdk_error_trap_pop_ignored ();
@@ -359,6 +364,7 @@ static void
 gsd_keyboard_manager_init (GsdKeyboardManager *manager)
 {
         manager->priv = GSD_KEYBOARD_MANAGER_GET_PRIVATE (manager);
+        manager->priv->numlock_serial = G_MAXULONG;
 }
 
 static void
