[mutter/wip/multitouch: 36/73] core: Make keyboard focus handling happen per-keyboard



commit dc5b813608ea449e20276f98241eea699af8de62
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Jul 3 18:20:53 2011 +0200

    core: Make keyboard focus handling happen per-keyboard
    
    MetaFocusInfo is a struct holding all necessary info, code has
    been updated to use the per-keyboard focus info instead of the
    old fields.

 src/core/bell.c            |   41 ++++-
 src/core/display-private.h |   42 +++--
 src/core/display.c         |  425 +++++++++++++++++++++++++++++++++++---------
 src/core/keybindings.c     |   14 +-
 src/core/place.c           |   21 ++-
 src/core/stack.c           |   49 ++++--
 src/core/window-private.h  |   10 +
 src/core/window-props.c    |    8 +-
 src/core/window.c          |  173 +++++++++++++-----
 src/meta/display.h         |   33 ++++
 src/ui/tabpopup.c          |   13 ++-
 11 files changed, 648 insertions(+), 181 deletions(-)
---
diff --git a/src/core/bell.c b/src/core/bell.c
index 8c7da04..c8fd1dd 100644
--- a/src/core/bell.c
+++ b/src/core/bell.c
@@ -230,6 +230,35 @@ bell_flash_window_frame (MetaWindow *window)
       bell_unflash_frame, window->frame, NULL);
 }
 
+static MetaWindow *
+get_flash_window (MetaDisplay *display,
+                  XkbAnyEvent *xkb_ev)
+{
+  XkbBellNotifyEvent *xkb_bell_event;
+  MetaWindow *window;
+
+  g_assert (xkb_ev->xkb_type == XkbBellNotify);
+
+  xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
+  window = meta_display_lookup_x_window (display, xkb_bell_event->window);
+
+  if (!window &&
+      g_hash_table_size (display->focus_info) == 1)
+    {
+      GHashTableIter iter;
+      MetaFocusInfo *info;
+
+      /* If there is only one focused window, use it */
+      g_hash_table_iter_init (&iter, display->focus_info);
+
+      if (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info) &&
+          info->focus_window && info->focus_window->frame)
+        window = info->focus_window;
+    }
+
+  return window;
+}
+
 /**
  * Flashes the frame of the focussed window. If there is no focussed window,
  * flashes the screen.
@@ -241,15 +270,11 @@ static void
 bell_flash_frame (MetaDisplay *display, 
 		  XkbAnyEvent *xkb_ev)
 {
-  XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
   MetaWindow *window;
   
   g_assert (xkb_ev->xkb_type == XkbBellNotify);
-  window = meta_display_lookup_x_window (display, xkb_bell_event->window);
-  if (!window && (display->focus_window))
-    {
-      window = display->focus_window;
-    }
+  window = get_flash_window (display, xkb_ev);
+
   if (window && window->frame)
     {
       bell_flash_window_frame (window);
@@ -310,9 +335,7 @@ meta_bell_notify (MetaDisplay *display,
       ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, _("Bell event"));
       ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent");
 
-      window = meta_display_lookup_x_window (display, xkb_bell_event->window);
-      if (!window && (display->focus_window) && (display->focus_window->frame))
-        window = display->focus_window;
+      window = get_flash_window (display, xkb_ev);
 
       if (window)
         {
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 393a319..41ef726 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -58,6 +58,7 @@ typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
 typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
 
 typedef struct _MetaGrabInfo MetaGrabInfo;
+typedef struct _MetaFocusInfo MetaFocusInfo;
 
 typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
 				     Window       xwindow,
@@ -129,6 +130,26 @@ struct _MetaGrabInfo
   int	      grab_resize_timeout_id;
 };
 
+struct _MetaFocusInfo
+{
+  /* This is the actual window from focus events,
+   * not the one we last set
+   */
+  MetaWindow *focus_window;
+
+  /* window we are expecting a FocusIn event for or the current focus
+   * window if we are not expecting any FocusIn/FocusOut events; not
+   * perfect because applications can call XSetInputFocus directly.
+   * (It could also be messed up if a timestamp later than current
+   * time is sent to meta_display_set_input_focus_window, though that
+   * would be a programming error).  See bug 154598 for more info.
+   */
+  MetaWindow *expected_focus_window;
+
+  /* last timestamp passed to XSetInputFocus */
+  guint32 last_focus_time;
+};
+
 struct _MetaDisplay
 {
   GObject parent_instance;
@@ -147,22 +168,8 @@ struct _MetaDisplay
 #include <meta/atomnames.h>
 #undef item
 
-  /* This is the actual window from focus events,
-   * not the one we last set
-   */
-  MetaWindow *focus_window;
-
-  /* window we are expecting a FocusIn event for or the current focus
-   * window if we are not expecting any FocusIn/FocusOut events; not
-   * perfect because applications can call XSetInputFocus directly.
-   * (It could also be messed up if a timestamp later than current
-   * time is sent to meta_display_set_input_focus_window, though that
-   * would be a programming error).  See bug 154598 for more info.
-   */
-  MetaWindow *expected_focus_window;
-
-  /* last timestamp passed to XSetInputFocus */
-  guint32 last_focus_time;
+  /* keyboard -> MetaFocusInfo hashtable */
+  GHashTable *focus_info;
 
   /* last user interaction time in any app */
   guint32 last_user_time;
@@ -477,5 +484,8 @@ void           meta_display_remove_grab_info         (MetaDisplay  *display,
 
 MetaGrabInfo * meta_display_get_grab_info            (MetaDisplay  *display,
                                                       MetaDevice   *device);
+MetaFocusInfo * meta_display_get_focus_info          (MetaDisplay  *display,
+                                                      MetaDevice   *device);
+
 
 #endif
diff --git a/src/core/display.c b/src/core/display.c
index a628012..1a6213a 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -189,7 +189,8 @@ static void    prefs_changed_callback    (MetaPreference pref,
 static void    sanity_check_timestamps   (MetaDisplay *display,
                                           guint32      known_good_timestamp);
 
-MetaGroup*     get_focussed_group (MetaDisplay *display);
+MetaGroup*     get_focussed_group (MetaDisplay *display,
+                                   MetaDevice  *keyboard);
 
 static void
 meta_display_get_property(GObject         *object,
@@ -202,7 +203,16 @@ meta_display_get_property(GObject         *object,
   switch (prop_id)
     {
     case PROP_FOCUS_WINDOW:
-      g_value_set_object (value, display->focus_window);
+      {
+        MetaFocusInfo *focus_info;
+        MetaDevice *device;
+
+        /* Always follow the VCK focus */
+        device = meta_device_map_lookup (display->device_map,
+                                         META_CORE_KEYBOARD_ID);
+        focus_info = meta_display_get_focus_info (display, device);
+        g_value_set_object (value, focus_info->focus_window);
+      }
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -468,8 +478,6 @@ meta_display_open (void)
   the_display->pending_pings = NULL;
   the_display->autoraise_timeout_id = 0;
   the_display->autoraise_window = NULL;
-  the_display->focus_window = NULL;
-  the_display->expected_focus_window = NULL;
 
   the_display->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
   the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a
@@ -551,6 +559,8 @@ meta_display_open (void)
 
   the_display->current_grabs = g_hash_table_new_full (NULL, NULL, NULL,
                                                       (GDestroyNotify) g_free);
+  the_display->focus_info = g_hash_table_new_full (NULL, NULL, NULL,
+                                                   (GDestroyNotify) g_free);
   the_display->edge_resistance_info = g_hash_table_new (NULL, NULL);
 
 #ifdef HAVE_XSYNC
@@ -784,7 +794,6 @@ meta_display_open (void)
                                   DefaultRootWindow (the_display->xdisplay),
                                   PropertyChangeMask);
 
-  the_display->last_focus_time = timestamp;
   the_display->last_user_time = timestamp;
   the_display->compositor = NULL;
   
@@ -1962,8 +1971,14 @@ event_callback (XEvent   *event,
                   /* This is from our synchronous grab since
                    * it has no modifiers and was on the client window
                    */
+                  MetaFocusInfo *focus_info;
+                  MetaDevice *keyboard;
                   int mode;
 
+                  /* This is a pointer event, get the paired keyboard */
+                  keyboard = meta_device_get_paired_device (device);
+                  focus_info = meta_display_get_focus_info (display, keyboard);
+
                   /* When clicking a different app in click-to-focus
                    * in application-based mode, and the different
                    * app is not a dock or desktop, eat the focus click.
@@ -1973,9 +1988,9 @@ event_callback (XEvent   *event,
                       !window->has_focus &&
                       window->type != META_WINDOW_DOCK &&
                       window->type != META_WINDOW_DESKTOP &&
-                      (display->focus_window == NULL ||
+                      (focus_info == NULL || focus_info->focus_window == NULL ||
                        !meta_window_same_application (window,
-                                                      display->focus_window)))
+                                                      focus_info->focus_window)))
                     mode = AsyncPointer; /* eat focus click */
                   else
                     mode = ReplayPointer; /* give event back */
@@ -2059,6 +2074,9 @@ event_callback (XEvent   *event,
               detail != NotifyInferior &&
               meta_display_focus_sentinel_clear (display))
             {
+              MetaFocusInfo *focus_info;
+              MetaDevice *keyboard;
+
               switch (meta_prefs_get_focus_mode ())
                 {
                 case META_FOCUS_MODE_SLOPPY:
@@ -2090,6 +2108,10 @@ event_callback (XEvent   *event,
                                       "Auto raise is disabled\n");
                         }
                     }
+
+                  keyboard = meta_device_get_paired_device (device);
+                  focus_info = meta_display_get_focus_info (display, keyboard);
+
                   /* In mouse focus mode, we defocus when the mouse *enters*
                    * the DESKTOP window, instead of defocusing on LeaveNotify.
                    * This is because having the mouse enter override-redirect
@@ -2101,12 +2123,14 @@ event_callback (XEvent   *event,
                    */
                   if (window->type == META_WINDOW_DESKTOP &&
                       meta_prefs_get_focus_mode() == META_FOCUS_MODE_MOUSE &&
-                      display->expected_focus_window != NULL)
+                      focus_info->expected_focus_window != NULL)
                     {
                       meta_topic (META_DEBUG_FOCUS,
-                                  "Unsetting focus from %s due to mouse entering "
+                                  "Unsetting focus on device %d "
+                                  "from %s due to mouse entering "
                                   "the DESKTOP window\n",
-                                  display->expected_focus_window->desc);
+                                  meta_device_get_id (keyboard),
+                                  focus_info->expected_focus_window->desc);
                       meta_display_focus_the_no_focus_window (display,
                                                               window->screen,
                                                               evtime);
@@ -4175,12 +4199,18 @@ meta_display_increment_event_serial (MetaDisplay *display)
 void
 meta_display_update_active_window_hint (MetaDisplay *display)
 {
+  MetaFocusInfo *focus_info;
+  MetaDevice *keyboard;
   GSList *tmp;
   
   gulong data[1];
 
-  if (display->focus_window)
-    data[0] = display->focus_window->xwindow;
+  keyboard = meta_device_map_lookup (display->device_map,
+                                     META_CORE_KEYBOARD_ID);
+  focus_info = meta_display_get_focus_info (display, keyboard);
+
+  if (focus_info && focus_info->focus_window)
+    data[0] = focus_info->focus_window->xwindow;
   else
     data[0] = None;
   
@@ -4558,23 +4588,29 @@ meta_display_window_has_pending_pings (MetaDisplay *display,
 }
 
 MetaGroup*
-get_focussed_group (MetaDisplay *display)
+get_focussed_group (MetaDisplay *display,
+                    MetaDevice  *keyboard)
 {
-  if (display->focus_window)
-    return display->focus_window->group;
+  MetaFocusInfo *focus_info;
+
+  focus_info = meta_display_get_focus_info (display, keyboard);
+
+  if (focus_info && focus_info->focus_window)
+    return focus_info->focus_window->group;
   else
     return NULL;
 }
 
-#define IN_TAB_CHAIN(w,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \
+#define IN_TAB_CHAIN(w,d,t) (((t) == META_TAB_LIST_NORMAL && META_WINDOW_IN_NORMAL_TAB_CHAIN (w)) \
     || ((t) == META_TAB_LIST_DOCKS && META_WINDOW_IN_DOCK_TAB_CHAIN (w)) \
-    || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display))))
+    || ((t) == META_TAB_LIST_GROUP && META_WINDOW_IN_GROUP_TAB_CHAIN (w, get_focussed_group(w->display, d))))
 
 static MetaWindow*
 find_tab_forward (MetaDisplay   *display,
                   MetaTabList    type,
                   MetaScreen    *screen, 
                   MetaWorkspace *workspace,
+                  MetaDevice    *device,
                   GList         *start,
                   gboolean       skip_first)
 {
@@ -4592,7 +4628,7 @@ find_tab_forward (MetaDisplay   *display,
       MetaWindow *window = tmp->data;
 
       if (window->screen == screen &&
-	  IN_TAB_CHAIN (window, type))
+	  IN_TAB_CHAIN (window, device, type))
         return window;
 
       tmp = tmp->next;
@@ -4603,7 +4639,7 @@ find_tab_forward (MetaDisplay   *display,
     {
       MetaWindow *window = tmp->data;
 
-      if (IN_TAB_CHAIN (window, type))
+      if (IN_TAB_CHAIN (window, device, type))
         return window;
 
       tmp = tmp->next;
@@ -4617,6 +4653,7 @@ find_tab_backward (MetaDisplay   *display,
                    MetaTabList    type,
                    MetaScreen    *screen, 
                    MetaWorkspace *workspace,
+                   MetaDevice    *device,
                    GList         *start,
                    gboolean       skip_last)
 {
@@ -4633,7 +4670,7 @@ find_tab_backward (MetaDisplay   *display,
       MetaWindow *window = tmp->data;
 
       if (window->screen == screen &&
-	  IN_TAB_CHAIN (window, type))
+	  IN_TAB_CHAIN (window, device, type))
         return window;
 
       tmp = tmp->prev;
@@ -4644,7 +4681,7 @@ find_tab_backward (MetaDisplay   *display,
     {
       MetaWindow *window = tmp->data;
 
-      if (IN_TAB_CHAIN (window, type))
+      if (IN_TAB_CHAIN (window, device, type))
         return window;
 
       tmp = tmp->prev;
@@ -4654,11 +4691,12 @@ find_tab_backward (MetaDisplay   *display,
 }
 
 /**
- * meta_display_get_tab_list:
+ * meta_display_get_device_tab_list:
  * @display: a #MetaDisplay
  * @type: type of tab list
  * @screen: a #MetaScreen
  * @workspace: origin workspace
+ * @device: keyboard triggering Alt-TAB
  *
  * Determine the list of windows that should be displayed for Alt-TAB
  * functionality.  The windows are returned in most recently used order.
@@ -4666,10 +4704,11 @@ find_tab_backward (MetaDisplay   *display,
  * Returns: (transfer container) (element-type Meta.Window): List of windows
  */
 GList*
-meta_display_get_tab_list (MetaDisplay   *display,
-                           MetaTabList    type,
-                           MetaScreen    *screen,
-                           MetaWorkspace *workspace)
+meta_display_get_device_tab_list (MetaDisplay   *display,
+                                  MetaTabList    type,
+                                  MetaScreen    *screen,
+                                  MetaWorkspace *workspace,
+                                  MetaDevice    *device)
 {
   GList *tab_list;
 
@@ -4689,7 +4728,7 @@ meta_display_get_tab_list (MetaDisplay   *display,
         
         if (!window->minimized &&
             window->screen == screen &&
-            IN_TAB_CHAIN (window, type))
+            IN_TAB_CHAIN (window, device, type))
           tab_list = g_list_prepend (tab_list, window);
         
         tmp = tmp->next;
@@ -4706,7 +4745,7 @@ meta_display_get_tab_list (MetaDisplay   *display,
         
         if (window->minimized &&
             window->screen == screen &&
-            IN_TAB_CHAIN (window, type))
+            IN_TAB_CHAIN (window, device, type))
           tab_list = g_list_prepend (tab_list, window);
         
         tmp = tmp->next;
@@ -4729,7 +4768,7 @@ meta_display_get_tab_list (MetaDisplay   *display,
         /* Check to see if it demands attention */
         if (l_window->wm_state_demands_attention && 
             l_window->workspace!=workspace &&
-            IN_TAB_CHAIN (l_window, type)) 
+            IN_TAB_CHAIN (l_window, device, type))
           {
             /* if it does, add it to the popup */
             tab_list = g_list_prepend (tab_list, l_window);
@@ -4743,13 +4782,42 @@ meta_display_get_tab_list (MetaDisplay   *display,
 }
 
 /**
- * meta_display_get_tab_next:
+ * meta_display_get_tab_list:
  * @display: a #MetaDisplay
  * @type: type of tab list
  * @screen: a #MetaScreen
  * @workspace: origin workspace
- * @window: (allow-none): starting window 
- * @backward: If %TRUE, look for the previous window.  
+ *
+ * Determine the list of windows that should be displayed for Alt-TAB
+ * functionality.  The windows are returned in most recently used order.
+ *
+ * Returns: (transfer container) (element-type Meta.Window): List of windows
+ */
+GList*
+meta_display_get_tab_list (MetaDisplay   *display,
+                           MetaTabList    type,
+                           MetaScreen    *screen,
+                           MetaWorkspace *workspace)
+{
+  MetaDevice *keyboard;
+
+  keyboard = meta_device_map_lookup (display->device_map,
+                                     META_CORE_KEYBOARD_ID);
+
+  return meta_display_get_device_tab_list (display, type,
+                                           screen, workspace,
+                                           keyboard);
+}
+
+/**
+ * meta_display_get_device_tab_next:
+ * @display: a #MetaDisplay
+ * @type: type of tab list
+ * @screen: a #MetaScreen
+ * @workspace: origin workspace
+ * @window: (allow-none): starting window
+ * @device: keyboard triggering Alt-TAB
+ * @backward: If %TRUE, look for the previous window.
  *
  * Determine the next window that should be displayed for Alt-TAB
  * functionality.
@@ -4758,12 +4826,13 @@ meta_display_get_tab_list (MetaDisplay   *display,
  *
  */
 MetaWindow*
-meta_display_get_tab_next (MetaDisplay   *display,
-                           MetaTabList    type,
-                           MetaScreen    *screen,
-                           MetaWorkspace *workspace,
-                           MetaWindow    *window,
-                           gboolean       backward)
+meta_display_get_device_tab_next (MetaDisplay   *display,
+                                  MetaTabList    type,
+                                  MetaScreen    *screen,
+                                  MetaWorkspace *workspace,
+                                  MetaWindow    *window,
+                                  MetaDevice    *device,
+                                  gboolean       backward)
 {
   gboolean skip;
   GList *tab_list;
@@ -4782,25 +4851,31 @@ meta_display_get_tab_next (MetaDisplay   *display,
       
       if (backward)
         ret = find_tab_backward (display, type, screen, workspace,
+                                 device,
                                  g_list_find (tab_list,
                                               window),
                                  TRUE);
       else
         ret = find_tab_forward (display, type, screen, workspace,
+                                device,
                                 g_list_find (tab_list,
                                              window),
                                 TRUE);
     }
   else
     {
-      skip = display->focus_window != NULL && 
-             tab_list->data == display->focus_window;
+      MetaFocusInfo *focus_info;
+
+      focus_info = meta_display_get_focus_info (display, device);
+
+      skip = focus_info->focus_window != NULL && 
+             tab_list->data == focus_info->focus_window;
       if (backward)
         ret = find_tab_backward (display, type, screen, workspace,
-                                 tab_list, skip);
+                                 device, tab_list, skip);
       else
         ret = find_tab_forward (display, type, screen, workspace,
-                                tab_list, skip);
+                                device, tab_list, skip);
     }
 
   g_list_free (tab_list);
@@ -4808,11 +4883,46 @@ meta_display_get_tab_next (MetaDisplay   *display,
 }
 
 /**
- * meta_display_get_tab_current:
+ * meta_display_get_tab_next:
+ * @display: a #MetaDisplay
+ * @type: type of tab list
+ * @screen: a #MetaScreen
+ * @workspace: origin workspace
+ * @window: (allow-none): starting window 
+ * @backward: If %TRUE, look for the previous window.  
+ *
+ * Determine the next window that should be displayed for Alt-TAB
+ * functionality.
+ *
+ * Returns: (transfer none): Next window
+ *
+ */
+MetaWindow*
+meta_display_get_tab_next (MetaDisplay   *display,
+                           MetaTabList    type,
+                           MetaScreen    *screen,
+                           MetaWorkspace *workspace,
+                           MetaWindow    *window,
+                           gboolean       backward)
+{
+  MetaDevice *keyboard;
+
+  keyboard = meta_device_map_lookup (display->device_map,
+                                     META_CORE_KEYBOARD_ID);
+
+  return meta_display_get_device_tab_next (display, type,
+                                           screen, workspace,
+                                           window, keyboard,
+                                           backward);
+}
+
+/**
+ * meta_display_get_device_tab_current:
  * @display: a #MetaDisplay
  * @type: type of tab list
  * @screen: a #MetaScreen
  * @workspace: origin workspace
+ * @device: keyboard triggering alt-TAB
  *
  * Determine the active window that should be displayed for Alt-TAB.
  *
@@ -4820,18 +4930,21 @@ meta_display_get_tab_next (MetaDisplay   *display,
  *
  */
 MetaWindow*
-meta_display_get_tab_current (MetaDisplay   *display,
-                              MetaTabList    type,
-                              MetaScreen    *screen,
-                              MetaWorkspace *workspace)
+meta_display_get_device_tab_current (MetaDisplay   *display,
+                                     MetaTabList    type,
+                                     MetaScreen    *screen,
+                                     MetaWorkspace *workspace,
+                                     MetaDevice    *device)
 {
+  MetaFocusInfo *focus_info;
   MetaWindow *window;
 
-  window = display->focus_window;
-  
+  focus_info = meta_display_get_focus_info (display, device);
+  window = focus_info->focus_window;
+
   if (window != NULL &&
       window->screen == screen &&
-      IN_TAB_CHAIN (window, type) &&
+      IN_TAB_CHAIN (window, device, type) &&
       (workspace == NULL ||
        meta_window_located_on_workspace (window, workspace)))
     return window;
@@ -4839,6 +4952,34 @@ meta_display_get_tab_current (MetaDisplay   *display,
     return NULL;
 }
 
+/**
+ * meta_display_get_tab_current:
+ * @display: a #MetaDisplay
+ * @type: type of tab list
+ * @screen: a #MetaScreen
+ * @workspace: origin workspace
+ *
+ * Determine the active window that should be displayed for Alt-TAB.
+ *
+ * Returns: (transfer none): Current window
+ *
+ */
+MetaWindow*
+meta_display_get_tab_current (MetaDisplay   *display,
+                              MetaTabList    type,
+                              MetaScreen    *screen,
+                              MetaWorkspace *workspace)
+{
+  MetaDevice *keyboard;
+
+  keyboard = meta_device_map_lookup (display->device_map,
+                                     META_CORE_KEYBOARD_ID);
+
+  return meta_display_get_device_tab_current (display, type,
+                                              screen, workspace,
+                                              keyboard);
+}
+
 int
 meta_resize_gravity_from_grab_op (MetaGrabOp op)
 {
@@ -5323,15 +5464,29 @@ static void
 sanity_check_timestamps (MetaDisplay *display,
                          guint32      timestamp)
 {
-  if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_focus_time))
+  MetaFocusInfo *focus_info;
+  MetaDevice *keyboard;
+  GHashTableIter iter;
+
+  g_hash_table_iter_init (&iter, display->focus_info);
+
+  while (g_hash_table_iter_next (&iter,
+                                 (gpointer *) &keyboard,
+                                 (gpointer *) &focus_info))
     {
-      meta_warning ("last_focus_time (%u) is greater than comparison "
-                    "timestamp (%u).  This most likely represents a buggy "
-                    "client sending inaccurate timestamps in messages such as "
-                    "_NET_ACTIVE_WINDOW.  Trying to work around...\n",
-                    display->last_focus_time, timestamp);
-      display->last_focus_time = timestamp;
+      if (XSERVER_TIME_IS_BEFORE (timestamp, focus_info->last_focus_time))
+        {
+          meta_warning ("last_focus_time (%u) for device %d is greater than comparison "
+                        "timestamp (%u).  This most likely represents a buggy "
+                        "client sending inaccurate timestamps in messages such as "
+                        "_NET_ACTIVE_WINDOW.  Trying to work around...\n",
+                        focus_info->last_focus_time,
+                        meta_device_get_id (keyboard),
+                        timestamp);
+          focus_info->last_focus_time = timestamp;
+        }
     }
+
   if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_user_time))
     {
       GSList *windows;
@@ -5368,14 +5523,19 @@ sanity_check_timestamps (MetaDisplay *display,
 static gboolean
 timestamp_too_old (MetaDisplay *display,
                    MetaWindow  *window,
+                   MetaDevice  *device,
                    guint32     *timestamp)
 {
+  MetaFocusInfo *focus_info;
+
   /* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow
    * us to sanity check the timestamp here and ensure it doesn't correspond to
    * a future time (though we would want to rename to 
    * timestamp_too_old_or_in_future).
    */
 
+  focus_info = meta_display_get_focus_info (display, device);
+
   if (*timestamp == CurrentTime)
     {
       meta_warning ("Got a request to focus %s with a timestamp of 0.  This "
@@ -5385,31 +5545,34 @@ timestamp_too_old (MetaDisplay *display,
       *timestamp = meta_display_get_current_time_roundtrip (display);
       return FALSE;
     }
-  else if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_focus_time))
+  else if (XSERVER_TIME_IS_BEFORE (*timestamp, focus_info->last_focus_time))
     {
       if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_user_time))
         {
           meta_topic (META_DEBUG_FOCUS,
-                      "Ignoring focus request for %s since %u "
+                      "Ignoring focus request for device %d, %s since %u "
                       "is less than %u and %u.\n",
+                      meta_device_get_id (device),
                       window ? window->desc : "the no_focus_window",
                       *timestamp,
                       display->last_user_time,
-                      display->last_focus_time);
+                      focus_info->last_focus_time);
           return TRUE;
         }
       else
         {
           meta_topic (META_DEBUG_FOCUS,
-                      "Received focus request for %s which is newer than most "
+                      "Received focus request for device %d, %s "
+                      "which is newer than most "
                       "recent user_time, but less recent than "
                       "last_focus_time (%u < %u < %u); adjusting "
                       "accordingly.  (See bug 167358)\n",
+                      meta_device_get_id (device),
                       window ? window->desc : "the no_focus_window",
                       display->last_user_time,
                       *timestamp,
-                      display->last_focus_time);
-          *timestamp = display->last_focus_time;
+                      focus_info->last_focus_time);
+          *timestamp = focus_info->last_focus_time;
           return FALSE;
         }
     }
@@ -5418,23 +5581,29 @@ timestamp_too_old (MetaDisplay *display,
 }
 
 void
-meta_display_set_input_focus_window (MetaDisplay *display, 
-                                     MetaWindow  *window,
-                                     gboolean     focus_frame,
-                                     guint32      timestamp)
+meta_display_set_keyboard_focus (MetaDisplay *display,
+                                 MetaWindow  *window,
+                                 MetaDevice  *keyboard,
+                                 gboolean     focus_frame,
+                                 guint32      timestamp)
 {
-  if (timestamp_too_old (display, window, &timestamp))
+  MetaFocusInfo *focus_info;
+  Window xwindow;
+
+  if (timestamp_too_old (display, window, keyboard, &timestamp))
     return;
 
+  xwindow = focus_frame ? window->frame->xwindow : window->xwindow;
+
   meta_error_trap_push (display);
-  XSetInputFocus (display->xdisplay,
-                  focus_frame ? window->frame->xwindow : window->xwindow,
-                  RevertToPointerRoot,
-                  timestamp);
+  meta_device_keyboard_set_focus_window (META_DEVICE_KEYBOARD (keyboard),
+                                         xwindow, timestamp);
   meta_error_trap_pop (display);
 
-  display->expected_focus_window = window;
-  display->last_focus_time = timestamp;
+  focus_info = meta_display_get_focus_info (display, keyboard);
+
+  focus_info->expected_focus_window = window;
+  focus_info->last_focus_time = timestamp;
   display->active_screen = window->screen;
 
   if (window != display->autoraise_window)
@@ -5442,25 +5611,57 @@ meta_display_set_input_focus_window (MetaDisplay *display,
 }
 
 void
-meta_display_focus_the_no_focus_window (MetaDisplay *display, 
-                                        MetaScreen  *screen,
-                                        guint32      timestamp)
+meta_display_unset_keyboard_focus (MetaDisplay *display,
+                                   MetaScreen  *screen,
+                                   MetaDevice  *keyboard,
+                                   guint32      timestamp)
 {
-  if (timestamp_too_old (display, NULL, &timestamp))
+  MetaFocusInfo *focus_info;
+
+  if (timestamp_too_old (display, NULL, keyboard, &timestamp))
     return;
 
-  XSetInputFocus (display->xdisplay,
-                  screen->no_focus_window,
-                  RevertToPointerRoot,
-                  timestamp);
-  display->expected_focus_window = NULL;
-  display->last_focus_time = timestamp;
+  meta_device_keyboard_set_focus_window (META_DEVICE_KEYBOARD (keyboard),
+                                         screen->no_focus_window,
+                                         timestamp);
+
+  focus_info = meta_display_get_focus_info (display, keyboard);
+
+  focus_info->expected_focus_window = NULL;
+  focus_info->last_focus_time = timestamp;
   display->active_screen = screen;
 
   meta_display_remove_autoraise_callback (display);
 }
 
 void
+meta_display_set_input_focus_window (MetaDisplay *display,
+                                     MetaWindow  *window,
+                                     gboolean     focus_frame,
+                                     guint32      timestamp)
+{
+  MetaDevice *keyboard;
+
+  keyboard = meta_device_map_lookup (display->device_map,
+                                     META_CORE_KEYBOARD_ID);
+  meta_display_set_keyboard_focus (display, window, keyboard,
+                                   focus_frame, timestamp);
+}
+
+void
+meta_display_focus_the_no_focus_window (MetaDisplay *display,
+                                        MetaScreen  *screen,
+                                        guint32      timestamp)
+{
+  MetaDevice *keyboard;
+
+  keyboard = meta_device_map_lookup (display->device_map,
+                                     META_CORE_KEYBOARD_ID);
+  meta_display_unset_keyboard_focus (display, screen, keyboard,
+                                     timestamp);
+}
+
+void
 meta_display_remove_autoraise_callback (MetaDisplay *display)
 {
   if (display->autoraise_timeout_id != 0)
@@ -5525,6 +5726,30 @@ meta_display_has_shape (MetaDisplay *display)
 }
 
 /**
+ * meta_display_get_keyboard_focus_window:
+ * @display: a #MetaDisplay
+ * @keyboard: keyboard to get current focus window for
+ *
+ * Returns the window that is currently receiving events for
+ * the keyboard @keyboard. We may have already sent a request
+ * to the X server to move the focus window elsewhere. (The
+ * expected_focus_window records where we've last set the input
+ * focus.)
+ *
+ * Returns: (transfer none): window receiving @keyboard focus
+ **/
+MetaWindow *
+meta_display_get_keyboard_focus_window (MetaDisplay *display,
+                                        MetaDevice  *keyboard)
+{
+  MetaFocusInfo *focus_info;
+
+  focus_info = meta_display_get_focus_info (display, keyboard);
+
+  return focus_info->focus_window;
+}
+
+/**
  * meta_display_get_focus_window:
  * @display: a #MetaDisplay
  *
@@ -5539,7 +5764,12 @@ meta_display_has_shape (MetaDisplay *display)
 MetaWindow *
 meta_display_get_focus_window (MetaDisplay *display)
 {
-  return display->focus_window;
+  MetaDevice *keyboard;
+
+  keyboard = meta_device_map_lookup (display->device_map,
+                                     META_CORE_KEYBOARD_ID);
+
+  return meta_display_get_keyboard_focus_window (display, keyboard);
 }
 
 int 
@@ -5661,3 +5891,28 @@ meta_display_get_grab_info (MetaDisplay *display,
 
   return info;
 }
+
+MetaFocusInfo *
+meta_display_get_focus_info (MetaDisplay *display,
+                             MetaDevice  *device)
+{
+  MetaFocusInfo *info;
+
+  if (!device)
+    return NULL;
+
+  info = g_hash_table_lookup (display->focus_info, device);
+
+  if (!info)
+    {
+      if (!META_IS_DEVICE_KEYBOARD (device))
+        device = meta_device_get_paired_device (device);
+
+      info = g_slice_new0 (MetaFocusInfo);
+      info->last_focus_time = display->current_time;
+
+      g_hash_table_insert (display->focus_info, device, info);
+    }
+
+  return info;
+}
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 8c2ffa4..b3b6d9e 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -3169,20 +3169,26 @@ handle_activate_window_menu (MetaDisplay    *display,
                       MetaKeyBinding *binding,
                       gpointer        dummy)
 {
-  if (display->focus_window)
+  MetaFocusInfo *focus_info;
+  MetaDevice *device;
+
+  device = meta_input_event_get_device (display, event);
+  focus_info = meta_display_get_focus_info (display, device);
+
+  if (focus_info->focus_window)
     {
       Time evtime;
       int x, y;
 
-      meta_window_get_position (display->focus_window,
+      meta_window_get_position (focus_info->focus_window,
                                 &x, &y);
       
       if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
-	  x += display->focus_window->rect.width;
+	  x += focus_info->focus_window->rect.width;
 
       evtime = meta_input_event_get_time (display, event);
 
-      meta_window_show_menu (display->focus_window,
+      meta_window_show_menu (focus_info->focus_window,
                              x, y,
                              0,
                              evtime);
diff --git a/src/core/place.c b/src/core/place.c
index 7f21f6f..51c188a 100644
--- a/src/core/place.c
+++ b/src/core/place.c
@@ -354,10 +354,17 @@ avoid_being_obscured_as_second_modal_dialog (MetaWindow *window,
    * know about the modal-to-the-main-window part.
    */
 
-  MetaWindow *focus_window;
+  MetaWindow *focus_window = NULL;
+  MetaFocusInfo *focus_info;
   MetaRectangle overlap;
+  MetaDevice *pointer, *keyboard;
 
-  focus_window = window->display->focus_window;
+  pointer = meta_window_guess_grab_pointer (window);
+  keyboard = meta_device_get_paired_device (pointer);
+  focus_info = meta_display_get_focus_info (window->display, keyboard);
+
+  if (focus_window)
+    focus_window = focus_info->focus_window;
 
   if (window->denied_focus_and_not_transient &&
       window->wm_state_modal && /* FIXME: Maybe do this for all transients? */
@@ -913,8 +920,16 @@ meta_window_place (MetaWindow        *window,
       gboolean       found_fit;
       MetaWindow    *focus_window;
       MetaRectangle  overlap;
+      MetaDevice    *pointer, *keyboard;
+      MetaFocusInfo *focus_info;
+
+      pointer = meta_window_guess_grab_pointer (window);
+      keyboard = meta_device_get_paired_device (pointer);
+
+      focus_info = meta_display_get_focus_info (window->display, keyboard);
+      g_assert (focus_info != NULL);
 
-      focus_window = window->display->focus_window;
+      focus_window = focus_info->focus_window;
       g_assert (focus_window != NULL);
 
       /* No need to do anything if the window doesn't overlap at all */
diff --git a/src/core/stack.c b/src/core/stack.c
index c3917c6..270103d 100644
--- a/src/core/stack.c
+++ b/src/core/stack.c
@@ -211,13 +211,23 @@ meta_stack_thaw (MetaStack *stack)
   stack_sync_to_server (stack);
 }
 
+typedef struct _FocusedForeachData FocusedForeachData;
+
+struct _FocusedForeachData
+{
+  MetaWindow *window;
+  gboolean focused_transient;
+};
+
 static gboolean
 is_focused_foreach (MetaWindow *window,
                     void       *data)
 {
-  if (window == window->display->expected_focus_window)
+  FocusedForeachData *focused_data = data;
+
+  if (window == focused_data->window)
     {
-      *((gboolean*) data) = TRUE;
+      focused_data->focused_transient = TRUE;
       return FALSE;
     }
   return TRUE;
@@ -239,7 +249,9 @@ static MetaStackLayer
 get_standalone_layer (MetaWindow *window)
 {
   MetaStackLayer layer;
-  gboolean focused_transient = FALSE;
+  MetaFocusInfo *focus_info;
+  MetaDevice *keyboard;
+  FocusedForeachData focused_data = { NULL, FALSE };
 
   switch (window->type)
     {
@@ -263,20 +275,33 @@ get_standalone_layer (MetaWindow *window)
     case META_WINDOW_OVERRIDE_OTHER:
       layer = META_LAYER_OVERRIDE_REDIRECT;
       break;
-    default:       
-      meta_window_foreach_transient (window,
-                                     is_focused_foreach,
-                                     &focused_transient);
+    default:
+      /* FIXME: How about other keyboards? should
+       * we allow fullscreen for non-VCP/K anyway?
+       */
+      keyboard = meta_device_map_lookup (window->display->device_map,
+                                         META_CORE_KEYBOARD_ID);
+
+      focus_info = meta_display_get_focus_info (window->display, keyboard);
+
+      if (focus_info)
+        {
+          focused_data.window = focus_info->expected_focus_window;
+          meta_window_foreach_transient (window,
+                                         is_focused_foreach,
+                                         &focused_data);
+        }
 
       if (window->wm_state_below)
         layer = META_LAYER_BOTTOM;
       else if (window->fullscreen &&
-               (focused_transient ||
-                window == window->display->expected_focus_window ||
-                window->display->expected_focus_window == NULL ||
-                (window->display->expected_focus_window != NULL &&
+               (focused_data.focused_transient ||
+                !focus_info ||
+                window == focus_info->expected_focus_window ||
+                focus_info->expected_focus_window == NULL ||
+                (focus_info->expected_focus_window != NULL &&
                  windows_on_different_monitor (window,
-                                               window->display->expected_focus_window))))
+                                               focus_info->expected_focus_window))))
         layer = META_LAYER_FULLSCREEN;
       else if (window->wm_state_above)
         layer = META_LAYER_TOP;
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 09666a1..022d4be 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -322,6 +322,12 @@ struct _MetaWindow
   /* if TRUE, window is attached to its parent */
   guint attached : 1;
 
+  /* if TRUE, window didn't yet get the FocusIn for window->focus_keyboard */
+  guint expecting_focus_in : 1;
+
+  /* Keyboard currently owning the window focus, or NULL */
+  MetaDevice *focus_keyboard;
+
   /* if non-NULL, the bounds of the window frame */
   cairo_region_t *frame_bounds;
 
@@ -402,6 +408,9 @@ struct _MetaWindow
 
   /* Current grab op for this window, or NULL */
   MetaGrabInfo *cur_grab;
+
+  /* Focus info if the window is focused, or NULL */
+  MetaFocusInfo *cur_focus;
 };
 
 struct _MetaWindowClass
@@ -653,6 +662,7 @@ void meta_window_update_for_monitors_changed (MetaWindow *window);
 void meta_window_update_on_all_workspaces (MetaWindow *window);
 
 void meta_window_propagate_focus_appearance (MetaWindow *window,
+                                             MetaDevice *keyboard,
                                              gboolean    focused);
 
 gboolean meta_window_should_attach_to_parent (MetaWindow *window);
diff --git a/src/core/window-props.c b/src/core/window-props.c
index 837e055..8eee8fd 100644
--- a/src/core/window-props.c
+++ b/src/core/window-props.c
@@ -1507,7 +1507,9 @@ reload_transient_for (MetaWindow    *window,
     return;
 
   if (meta_window_appears_focused (window) && window->xtransient_for != None)
-    meta_window_propagate_focus_appearance (window, FALSE);
+    meta_window_propagate_focus_appearance (window,
+                                            window->focus_keyboard,
+                                            FALSE);
 
   old_transient_for = window->xtransient_for;
   window->xtransient_for = transient_for;
@@ -1560,7 +1562,9 @@ reload_transient_for (MetaWindow    *window,
     meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
 
   if (meta_window_appears_focused (window) && window->xtransient_for != None)
-    meta_window_propagate_focus_appearance (window, TRUE);
+    meta_window_propagate_focus_appearance (window,
+                                            window->focus_keyboard,
+                                            TRUE);
 }
 
 static void
diff --git a/src/core/window.c b/src/core/window.c
index 0f63b78..f14feee 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1558,6 +1558,7 @@ void
 meta_window_unmanage (MetaWindow  *window,
                       guint32      timestamp)
 {
+  MetaFocusInfo *focus_info = NULL;
   GList *tmp;
 
   meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
@@ -1619,6 +1620,10 @@ meta_window_unmanage (MetaWindow  *window,
                                         * group if window->unmanaging
                                         */
 
+  if (window->focus_keyboard)
+    focus_info = meta_display_get_focus_info (window->display,
+                                              window->focus_keyboard);
+
   /* If we have the focus, focus some other window.
    * This is done first, so that if the unmap causes
    * an EnterNotify the EnterNotify will have final say
@@ -1626,22 +1631,24 @@ meta_window_unmanage (MetaWindow  *window,
    * invariants.
    */
   if (meta_window_appears_focused (window))
-    meta_window_propagate_focus_appearance (window, FALSE);
-  if (window->has_focus)
-    {
-      meta_topic (META_DEBUG_FOCUS,
-                  "Focusing default window since we're unmanaging %s\n",
-                  window->desc);
-      meta_workspace_focus_default_window (window->screen->active_workspace,
-                                           window,
-                                           timestamp);
-    }
-  else if (window->display->expected_focus_window == window)
+    meta_window_propagate_focus_appearance (window,
+                                            window->focus_keyboard,
+                                            FALSE);
+
+  if (window->focus_keyboard)
     {
-      meta_topic (META_DEBUG_FOCUS,
-                  "Focusing default window since expected focus window freed %s\n",
-                  window->desc);
-      window->display->expected_focus_window = NULL;
+      if (window->expecting_focus_in)
+        {
+          meta_topic (META_DEBUG_FOCUS,
+                      "Focusing default window since expected focus window freed %s\n",
+                      window->desc);
+          focus_info->expected_focus_window = NULL;
+        }
+      else
+        meta_topic (META_DEBUG_FOCUS,
+                    "Focusing default window since we're unmanaging %s\n",
+                    window->desc);
+
       meta_workspace_focus_default_window (window->screen->active_workspace,
                                            window,
                                            timestamp);
@@ -1671,10 +1678,14 @@ meta_window_unmanage (MetaWindow  *window,
 
   g_assert (window->cur_grab == NULL);
 
-  if (window->display->focus_window == window)
+  if (focus_info &&
+      focus_info->focus_window == window)
     {
-      window->display->focus_window = NULL;
-      g_object_notify (G_OBJECT (window->display), "focus-window");
+      focus_info->focus_window = NULL;
+
+      if (window->focus_keyboard &&
+          meta_device_get_id (window->focus_keyboard) == META_CORE_KEYBOARD_ID)
+        g_object_notify (G_OBJECT (window->display), "focus-window");
     }
 
   if (window->maximized_horizontally || window->maximized_vertically)
@@ -2445,12 +2456,17 @@ meta_window_queue (MetaWindow *window, guint queuebits)
 }
 
 static gboolean
-intervening_user_event_occurred (MetaWindow *window)
+intervening_user_event_occurred (MetaWindow *window,
+                                 MetaDevice *keyboard)
 {
   guint32 compare;
-  MetaWindow *focus_window;
+  MetaWindow *focus_window = NULL;
+  MetaFocusInfo *focus_info;
 
-  focus_window = window->display->focus_window;
+  focus_info = meta_display_get_focus_info (window->display, keyboard);
+
+  if (focus_info)
+    focus_window = focus_info->focus_window;
 
   meta_topic (META_DEBUG_STARTUP,
               "COMPARISON:\n"
@@ -2599,12 +2615,15 @@ __window_is_terminal (MetaWindow *window)
  */
 static void
 window_state_on_map (MetaWindow *window,
-                     gboolean *takes_focus,
-                     gboolean *places_on_top)
+                     MetaDevice *keyboard,
+                     gboolean   *takes_focus,
+                     gboolean   *places_on_top)
 {
   gboolean intervening_events;
+  MetaFocusInfo *focus_info;
 
-  intervening_events = intervening_user_event_occurred (window);
+  intervening_events = intervening_user_event_occurred (window, keyboard);
+  focus_info = meta_display_get_focus_info (window->display, keyboard);
 
   *takes_focus = !intervening_events;
   *places_on_top = *takes_focus;
@@ -2626,11 +2645,11 @@ window_state_on_map (MetaWindow *window,
    * terminals due to new window map, but the latter is a much easier
    * approximation to enforce so we do that.
    */
-  if (*takes_focus &&
+  if (*takes_focus && focus_info &&
       meta_prefs_get_focus_new_windows () == META_FOCUS_NEW_WINDOWS_STRICT &&
       !window->display->allow_terminal_deactivation &&
-      __window_is_terminal (window->display->focus_window) &&
-      !meta_window_is_ancestor_of_transient (window->display->focus_window,
+      __window_is_terminal (focus_info->focus_window) &&
+      !meta_window_is_ancestor_of_transient (focus_info->focus_window,
                                              window))
     {
       meta_topic (META_DEBUG_FOCUS,
@@ -2861,20 +2880,30 @@ meta_window_show (MetaWindow *window)
   gboolean takes_focus_on_map;
   gboolean place_on_top_on_map;
   gboolean needs_stacking_adjustment;
-  MetaWindow *focus_window;
+  MetaWindow *focus_window = NULL;
   gboolean toplevel_was_mapped;
   gboolean toplevel_now_mapped;
   gboolean notify_demands_attention = FALSE;
+  MetaDevice *pointer, *keyboard;
+  MetaFocusInfo *focus_info;
 
   meta_topic (META_DEBUG_WINDOW_STATE,
               "Showing window %s, shaded: %d iconic: %d placed: %d\n",
               window->desc, window->shaded, window->iconic, window->placed);
 
+  pointer = meta_window_guess_grab_pointer (window);
+  keyboard = meta_device_get_paired_device (pointer);
+
   toplevel_was_mapped = meta_window_toplevel_is_mapped (window);
 
-  focus_window = window->display->focus_window;  /* May be NULL! */
+  focus_info = meta_display_get_focus_info (window->display, keyboard);
+
+  if (focus_info)
+    focus_window = focus_info->focus_window;
+
   did_show = FALSE;
-  window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map);
+  window_state_on_map (window, keyboard,
+                       &takes_focus_on_map, &place_on_top_on_map);
   needs_stacking_adjustment = FALSE;
 
   meta_topic (META_DEBUG_WINDOW_STATE,
@@ -3205,14 +3234,13 @@ meta_window_hide (MetaWindow *window)
       invalidate_work_areas (window);
     }
 
-  /* The check on expected_focus_window is a temporary workaround for
+  /* The check on expected_focus_in is a temporary workaround for
    *  https://bugzilla.gnome.org/show_bug.cgi?id=597352
    * We may have already switched away from this window but not yet
    * gotten FocusIn/FocusOut events. A more complete comprehensive
    * fix for these type of issues is described in the bug.
    */
-  if (window->has_focus &&
-      window == window->display->expected_focus_window)
+  if (window->has_focus && window->expecting_focus_in)
     {
       MetaWindow *not_this_one = NULL;
       MetaWorkspace *my_workspace = meta_window_get_workspace (window);
@@ -5493,13 +5521,22 @@ meta_window_focus (MetaWindow  *window,
 
       if (window->take_focus)
         {
+          MetaFocusInfo *focus_info;
+          MetaDevice *keyboard;
+
           meta_topic (META_DEBUG_FOCUS,
                       "Sending WM_TAKE_FOCUS to %s since take_focus = true\n",
                       window->desc);
           meta_window_send_icccm_message (window,
                                           window->display->atom_WM_TAKE_FOCUS,
                                           timestamp);
-          window->display->expected_focus_window = window;
+
+          keyboard = meta_device_get_paired_device (device);
+          focus_info = meta_display_get_focus_info (window->display, keyboard);
+
+          focus_info->expected_focus_window = window;
+          window->focus_keyboard = keyboard;
+          window->expecting_focus_in = TRUE;
         }
     }
 
@@ -6042,7 +6079,16 @@ meta_window_configure_request (MetaWindow *window,
   if (event->xconfigurerequest.value_mask & CWStackMode)
     {
       MetaWindow *active_window;
-      active_window = window->display->expected_focus_window;
+      MetaDevice *pointer, *keyboard;
+      MetaFocusInfo *focus_info;
+
+      pointer = meta_window_guess_grab_pointer (window);
+      keyboard = meta_device_get_paired_device (pointer);
+      focus_info = meta_display_get_focus_info (window->display, keyboard);
+
+      if (focus_info)
+        active_window = focus_info->expected_focus_window;
+
       if (meta_prefs_get_disable_workarounds ())
         {
           meta_topic (META_DEBUG_STACK,
@@ -6655,14 +6701,23 @@ meta_window_client_message (MetaWindow *window,
  */
 void
 meta_window_propagate_focus_appearance (MetaWindow *window,
+                                        MetaDevice *keyboard,
                                         gboolean    focused)
 {
   MetaWindow *child, *parent, *focus_window;
-
-  focus_window = window->display->focus_window;
+  MetaFocusInfo *focus_info;
 
   child = window;
   parent = meta_window_get_transient_for (child);
+
+  if (keyboard)
+    {
+      focus_info = meta_display_get_focus_info (window->display, keyboard);
+      focus_window = focus_info->focus_window;
+    }
+  else
+    focus_window = NULL;
+
   while (parent && (!focused || meta_window_is_attached_dialog (child)))
     {
       gboolean child_focus_state_changed;
@@ -6683,7 +6738,7 @@ meta_window_propagate_focus_appearance (MetaWindow *window,
         }
 
       if (child_focus_state_changed && !parent->has_focus &&
-          parent != window->display->expected_focus_window)
+          (!focus_info || parent != focus_info->expected_focus_window))
         {
           g_object_notify (G_OBJECT (parent), "appears-focused");
           if (parent->frame)
@@ -6700,6 +6755,8 @@ meta_window_notify_focus (MetaWindow *window,
                           XEvent     *event)
 {
   guint evtype, mode, detail;
+  MetaFocusInfo *focus_info = NULL;
+  MetaDevice *keyboard;
   Window xwindow;
 
   /* note the event can be on either the window or the frame,
@@ -6725,14 +6782,19 @@ meta_window_notify_focus (MetaWindow *window,
       meta_input_event_get_crossing_details (window->display, event,
                                              &mode, &detail);
       xwindow = meta_input_event_get_window (window->display, event);
+      keyboard = meta_input_event_get_device (window->display, event);
     }
   else
     {
       xwindow = event->xany.window;
       evtype = event->type;
       mode = detail = 0;
+      keyboard = window->focus_keyboard;
     }
 
+  if (keyboard)
+    focus_info = meta_display_get_focus_info (window->display, keyboard);
+
   meta_topic (META_DEBUG_FOCUS,
               "Focus %s event received on %s 0x%lx (%s) "
               "mode %s detail %s\n",
@@ -6786,17 +6848,22 @@ meta_window_notify_focus (MetaWindow *window,
     {
       if (window->override_redirect)
         {
-          window->display->focus_window = NULL;
-          g_object_notify (G_OBJECT (window->display), "focus-window");
+          focus_info->focus_window = NULL;
+
+          if (meta_device_get_id (keyboard) == META_CORE_KEYBOARD_ID)
+            g_object_notify (G_OBJECT (window->display), "focus-window");
+
           return FALSE;
         }
 
-      if (window != window->display->focus_window)
+      if (window != focus_info->focus_window)
         {
           meta_topic (META_DEBUG_FOCUS,
                       "* Focus --> %s\n", window->desc);
-          window->display->focus_window = window;
+          focus_info->focus_window = window;
           window->has_focus = TRUE;
+          window->focus_keyboard = keyboard;
+          window->expecting_focus_in = FALSE;
 
           /* Move to the front of the focusing workspace's MRU list.
            * We should only be "removing" it from the MRU list if it's
@@ -6854,7 +6921,9 @@ meta_window_notify_focus (MetaWindow *window,
             meta_display_ungrab_focus_window_button (window->display, window);
 
           g_signal_emit (window, window_signals[FOCUS], 0);
-          g_object_notify (G_OBJECT (window->display), "focus-window");
+
+          if (meta_device_get_id (keyboard) == META_CORE_KEYBOARD_ID)
+            g_object_notify (G_OBJECT (window->display), "focus-window");
 
           if (!window->attached_focus_window)
             {
@@ -6862,7 +6931,7 @@ meta_window_notify_focus (MetaWindow *window,
               if (window->frame)
                 meta_frame_queue_draw (window->frame);
             }
-          meta_window_propagate_focus_appearance (window, TRUE);
+          meta_window_propagate_focus_appearance (window, keyboard, TRUE);
         }
     }
   else if (evtype == FocusOut ||
@@ -6878,7 +6947,8 @@ meta_window_notify_focus (MetaWindow *window,
           return TRUE;
         }
 
-      if (window == window->display->focus_window)
+      if (focus_info &&
+          window == focus_info->focus_window)
         {
           meta_topic (META_DEBUG_FOCUS,
                       "%s is now the previous focus window due to being focused out or unmapped\n",
@@ -6887,11 +6957,18 @@ meta_window_notify_focus (MetaWindow *window,
           meta_topic (META_DEBUG_FOCUS,
                       "* Focus --> NULL (was %s)\n", window->desc);
 
-          meta_window_propagate_focus_appearance (window, FALSE);
+          meta_window_propagate_focus_appearance (window, keyboard, FALSE);
+          focus_info->focus_window = NULL;
+
+          if (meta_device_get_id (keyboard) == META_CORE_KEYBOARD_ID)
+            g_object_notify (G_OBJECT (window->display), "focus-window");
 
-          window->display->focus_window = NULL;
-          g_object_notify (G_OBJECT (window->display), "focus-window");
           window->has_focus = FALSE;
+          window->focus_keyboard = NULL;
+          window->expecting_focus_in = FALSE;
+
+          if (meta_device_get_id (keyboard) == META_CORE_KEYBOARD_ID)
+            g_object_notify (G_OBJECT (window->display), "focus-window");
 
           if (!window->attached_focus_window)
             {
diff --git a/src/meta/display.h b/src/meta/display.h
index 73d758e..85f7e75 100644
--- a/src/meta/display.h
+++ b/src/meta/display.h
@@ -75,6 +75,9 @@ gboolean meta_display_has_shape (MetaDisplay *display);
 
 MetaScreen *meta_display_screen_for_root (MetaDisplay *display,
                                           Window       xroot);
+
+MetaWindow *meta_display_get_keyboard_focus_window (MetaDisplay *display,
+                                                    MetaDevice  *keyboard);
 MetaWindow *meta_display_get_focus_window (MetaDisplay *display);
 
 gboolean  meta_display_xwindow_is_a_no_focus_window (MetaDisplay *display,
@@ -109,6 +112,26 @@ MetaWindow* meta_display_get_tab_current (MetaDisplay   *display,
                                           MetaScreen    *screen,
                                           MetaWorkspace *workspace);
 
+GList* meta_display_get_device_tab_list (MetaDisplay   *display,
+                                         MetaTabList    type,
+                                         MetaScreen    *screen,
+                                         MetaWorkspace *workspace,
+                                         MetaDevice    *device);
+
+MetaWindow* meta_display_get_device_tab_next (MetaDisplay   *display,
+                                              MetaTabList    type,
+                                              MetaScreen    *screen,
+                                              MetaWorkspace *workspace,
+                                              MetaWindow    *window,
+                                              MetaDevice    *device,
+                                              gboolean       backward);
+
+MetaWindow* meta_display_get_device_tab_current (MetaDisplay   *display,
+                                                 MetaTabList    type,
+                                                 MetaScreen    *screen,
+                                                 MetaWorkspace *workspace,
+                                                 MetaDevice    *device);
+
 gboolean meta_display_begin_grab_op (MetaDisplay *display,
                                      MetaScreen  *screen,
                                      MetaWindow  *window,
@@ -134,6 +157,16 @@ MetaKeyBindingAction meta_display_get_keybinding_action (MetaDisplay  *display,
                                                          unsigned int  keycode,
                                                          unsigned long mask);
 
+void meta_display_set_keyboard_focus   (MetaDisplay        *display,
+                                        MetaWindow         *window,
+                                        MetaDevice         *keyboard,
+                                        gboolean            focus_frame,
+                                        guint32             timestamp);
+void meta_display_unset_keyboard_focus (MetaDisplay        *display,
+                                        MetaScreen         *screen,
+                                        MetaDevice         *keyboard,
+                                        guint32             timestamp);
+
 /* meta_display_set_input_focus_window is like XSetInputFocus, except
  * that (a) it can't detect timestamps later than the current time,
  * since Mutter isn't part of the XServer, and thus gives erroneous
diff --git a/src/ui/tabpopup.c b/src/ui/tabpopup.c
index f6d7e6a..025e1d2 100644
--- a/src/ui/tabpopup.c
+++ b/src/ui/tabpopup.c
@@ -852,12 +852,21 @@ static WnckWindowDisplayInfo
 meta_convert_meta_to_wnck (MetaWindow *window, MetaScreen *screen)
 {
   WnckWindowDisplayInfo wnck_window;
+  MetaFocusInfo *focus_info;
+  GHashTableIter iter;
+
   wnck_window.icon = window->icon;
   wnck_window.mini_icon = window->mini_icon;
   
   wnck_window.is_active = FALSE;
-  if (window == window->display->expected_focus_window)
-    wnck_window.is_active = TRUE;
+
+  g_hash_table_iter_init (&iter, window->display->focus_info);
+
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &focus_info))
+    {
+      if (window == focus_info->expected_focus_window)
+        wnck_window.is_active = TRUE;
+    }
 
   if (window->frame)
     {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]