summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2011-07-03 18:20:53 +0200
committerJasper St. Pierre <jstpierre@mecheye.net>2012-11-03 19:47:35 -0400
commit5f6f67fb4ecc398660f798faa1275d9f8358bbcd (patch)
treedeb22ae1848598f833fdb20df4eac90e862b9077
parent0d97e6adeb2c2ca01c56bf593cc4f84c2572d643 (diff)
downloadmutter-5f6f67fb4ecc398660f798faa1275d9f8358bbcd.tar.gz
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.
-rw-r--r--src/core/bell.c41
-rw-r--r--src/core/display-private.h42
-rw-r--r--src/core/display.c474
-rw-r--r--src/core/keybindings.c14
-rw-r--r--src/core/place.c21
-rw-r--r--src/core/stack.c39
-rw-r--r--src/core/window-private.h10
-rw-r--r--src/core/window-props.c15
-rw-r--r--src/core/window.c173
-rw-r--r--src/meta/display.h33
-rw-r--r--src/ui/tabpopup.c13
11 files changed, 682 insertions, 193 deletions
diff --git a/src/core/bell.c b/src/core/bell.c
index 4f48c6f94..997ac5f99 100644
--- a/src/core/bell.c
+++ b/src/core/bell.c
@@ -239,6 +239,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;
+}
+
/**
* bell_flash_frame:
* @display: The display the bell event came in on
@@ -251,15 +280,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);
@@ -320,9 +345,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 7cb6a65d6..27cf657a7 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,
@@ -130,6 +131,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;
@@ -148,22 +169,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;
@@ -481,5 +488,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 6db222121..0de262d5b 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -134,6 +134,7 @@ typedef struct
{
MetaDisplay *display;
MetaWindow *window;
+ MetaDevice *device;
int pointer_x;
int pointer_y;
} MetaFocusData;
@@ -203,8 +204,9 @@ 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,
@@ -217,7 +219,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);
@@ -532,8 +543,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
@@ -615,6 +624,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
@@ -846,7 +857,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;
@@ -1577,8 +1587,16 @@ window_raise_with_delay_callback (void *data)
static void
meta_display_mouse_mode_focus (MetaDisplay *display,
+ MetaDevice *device,
MetaWindow *window,
- guint32 timestamp) {
+ guint32 timestamp)
+{
+ MetaFocusInfo *focus_info;
+ MetaDevice *keyboard;
+
+ keyboard = meta_device_get_paired_device (device);
+ focus_info = meta_display_get_focus_info (display, keyboard);
+
if (window->type != META_WINDOW_DESKTOP)
{
meta_topic (META_DEBUG_FOCUS,
@@ -1603,12 +1621,12 @@ meta_display_mouse_mode_focus (MetaDisplay *display,
* alternative mechanism works great.
*/
if (meta_prefs_get_focus_mode() == G_DESKTOP_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 "
"the DESKTOP window\n",
- display->expected_focus_window->desc);
+ focus_info->expected_focus_window->desc);
meta_display_focus_the_no_focus_window (display,
window->screen,
timestamp);
@@ -1617,19 +1635,23 @@ meta_display_mouse_mode_focus (MetaDisplay *display,
}
static gboolean
-window_focus_on_pointer_rest_callback (gpointer data) {
+window_focus_on_pointer_rest_callback (gpointer data)
+{
MetaFocusData *focus_data;
MetaDisplay *display;
+ MetaDevice *device;
MetaScreen *screen;
MetaWindow *window;
- Window root, child;
- int root_x, root_y, x, y;
+ Window child, root;
+ int root_x, root_y;
+ int x, y;
guint32 timestamp;
guint mask;
focus_data = data;
display = focus_data->display;
screen = focus_data->window->screen;
+ device = focus_data->device;
if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK)
goto out;
@@ -1665,7 +1687,7 @@ window_focus_on_pointer_rest_callback (gpointer data) {
goto out;
timestamp = meta_display_get_current_time_roundtrip (display);
- meta_display_mouse_mode_focus (display, window, timestamp);
+ meta_display_mouse_mode_focus (display, device, window, timestamp);
out:
display->focus_timeout_id = 0;
@@ -1707,17 +1729,22 @@ meta_display_queue_autoraise_callback (MetaDisplay *display,
static void
meta_display_queue_focus_callback (MetaDisplay *display,
+ MetaDevice *device,
MetaWindow *window,
- int pointer_x,
- int pointer_y)
+ XEvent *event)
{
MetaFocusData *focus_data;
+ gdouble xroot, yroot;
+
+ if (!meta_input_event_get_coordinates (display, event, NULL, NULL, &xroot, &yroot))
+ return;
focus_data = g_new (MetaFocusData, 1);
focus_data->display = display;
focus_data->window = window;
- focus_data->pointer_x = pointer_x;
- focus_data->pointer_y = pointer_y;
+ focus_data->device = device;
+ focus_data->pointer_x = (int) xroot;
+ focus_data->pointer_y = (int) yroot;
if (display->focus_timeout_id != 0)
g_source_remove (display->focus_timeout_id);
@@ -2173,8 +2200,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.
@@ -2184,9 +2217,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 */
@@ -2288,21 +2321,29 @@ event_callback (XEvent *event,
evtime);
if (meta_prefs_get_focus_change_on_pointer_rest())
- meta_display_queue_focus_callback (display, window,
- event->xcrossing.x_root,
- event->xcrossing.y_root);
+ meta_display_queue_focus_callback (display, device, window, event);
else
- meta_display_mouse_mode_focus (display, window,
- evtime);
+ meta_display_mouse_mode_focus (display, device, window, evtime);
/* stop ignoring stuff */
reset_ignored_crossing_serials (display);
+
+ if (meta_prefs_get_auto_raise ())
+ {
+ meta_display_queue_autoraise_callback (display, window);
+ }
+ else
+ {
+ meta_topic (META_DEBUG_FOCUS,
+ "Auto raise is disabled\n");
+ }
}
break;
+
case G_DESKTOP_FOCUS_MODE_CLICK:
break;
}
-
+
if (window->type == META_WINDOW_DOCK)
meta_window_raise (window);
}
@@ -4375,12 +4416,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;
@@ -4756,17 +4803,22 @@ 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))) \
|| ((t) == META_TAB_LIST_NORMAL_ALL && META_WINDOW_IN_NORMAL_TAB_CHAIN_TYPE (w)))
static MetaWindow*
@@ -4774,6 +4826,7 @@ find_tab_forward (MetaDisplay *display,
MetaTabList type,
MetaScreen *screen,
MetaWorkspace *workspace,
+ MetaDevice *device,
GList *start,
gboolean skip_first)
{
@@ -4791,7 +4844,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;
@@ -4802,7 +4855,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;
@@ -4816,6 +4869,7 @@ find_tab_backward (MetaDisplay *display,
MetaTabList type,
MetaScreen *screen,
MetaWorkspace *workspace,
+ MetaDevice *device,
GList *start,
gboolean skip_last)
{
@@ -4832,7 +4886,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;
@@ -4843,7 +4897,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;
@@ -4853,11 +4907,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.
@@ -4865,10 +4920,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;
@@ -4888,7 +4944,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;
@@ -4905,7 +4961,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;
@@ -4929,7 +4985,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);
@@ -4945,13 +5001,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.
@@ -4960,12 +5045,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;
@@ -4984,25 +5070,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);
@@ -5010,11 +5102,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.
*
@@ -5022,18 +5149,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;
@@ -5041,6 +5171,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)
{
@@ -5534,15 +5692,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;
@@ -5579,14 +5751,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 "
@@ -5595,31 +5772,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;
}
}
@@ -5628,23 +5808,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)
@@ -5652,25 +5838,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)
@@ -5735,6 +5953,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
*
@@ -5749,7 +5991,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
@@ -5887,3 +6134,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 f00d92282..b4ba877ba 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -3111,20 +3111,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 fcb2f69cd..ec28c11f8 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 1d481f9cb..279577c64 100644
--- a/src/core/stack.c
+++ b/src/core/stack.c
@@ -274,13 +274,23 @@ meta_stack_update_window_tile_matches (MetaStack *stack,
g_list_free (windows);
}
+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;
@@ -303,6 +313,9 @@ get_standalone_layer (MetaWindow *window)
{
MetaStackLayer layer;
gboolean focused_transient = FALSE;
+ MetaFocusInfo *focus_info;
+ MetaDevice *keyboard;
+ FocusedForeachData focused_data = { 0 };
switch (window->type)
{
@@ -326,20 +339,30 @@ get_standalone_layer (MetaWindow *window)
case META_WINDOW_OVERRIDE_OTHER:
layer = META_LAYER_OVERRIDE_REDIRECT;
break;
- default:
+ 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);
+ focused_data.window = focus_info->expected_focus_window;
+
meta_window_foreach_transient (window,
is_focused_foreach,
- &focused_transient);
+ &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 &&
+ !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 && !META_WINDOW_MAXIMIZED (window))
layer = META_LAYER_TOP;
diff --git a/src/core/window-private.h b/src/core/window-private.h
index b0970b3b5..68015fb84 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -333,6 +333,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;
@@ -416,6 +422,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
@@ -646,6 +655,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 68e14fd21..0cb284350 100644
--- a/src/core/window-props.c
+++ b/src/core/window-props.c
@@ -1438,6 +1438,13 @@ reload_transient_for (MetaWindow *window,
MetaWindow *parent = NULL;
Window transient_for, old_transient_for;
+ if (meta_window_appears_focused (window) && window->xtransient_for != None)
+ meta_window_propagate_focus_appearance (window,
+ window->focus_keyboard,
+ FALSE);
+
+ window->xtransient_for = None;
+
if (value->type != META_PROP_VALUE_INVALID)
{
transient_for = value->v.xwindow;
@@ -1474,7 +1481,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;
@@ -1527,7 +1536,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 d9814e534..cf949f01f 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1662,6 +1662,7 @@ void
meta_window_unmanage (MetaWindow *window,
guint32 timestamp)
{
+ MetaFocusInfo *focus_info = NULL;
GList *tmp;
meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
@@ -1723,6 +1724,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
@@ -1730,22 +1735,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);
@@ -1775,10 +1782,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)
@@ -2556,12 +2567,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"
@@ -2710,12 +2726,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;
@@ -2737,11 +2756,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 () == G_DESKTOP_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,
@@ -2958,20 +2977,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,
@@ -3299,14 +3328,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);
@@ -5650,13 +5678,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;
}
}
@@ -6198,7 +6235,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,
@@ -6822,14 +6868,23 @@ meta_window_appears_focused_changed (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;
@@ -6850,7 +6905,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))
{
meta_window_appears_focused_changed (parent);
}
@@ -6865,6 +6920,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,
@@ -6890,14 +6947,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",
@@ -6951,17 +7013,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
@@ -7019,12 +7086,14 @@ 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)
meta_window_appears_focused_changed (window);
- meta_window_propagate_focus_appearance (window, TRUE);
+ meta_window_propagate_focus_appearance (window, keyboard, TRUE);
}
}
else if (evtype == FocusOut ||
@@ -7040,7 +7109,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",
@@ -7049,11 +7119,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)
meta_window_appears_focused_changed (window);
diff --git a/src/meta/display.h b/src/meta/display.h
index 4eb0da60a..eb8d52cec 100644
--- a/src/meta/display.h
+++ b/src/meta/display.h
@@ -76,6 +76,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,
@@ -112,6 +115,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,
@@ -147,6 +170,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 ac1029439..3e75e1f87 100644
--- a/src/ui/tabpopup.c
+++ b/src/ui/tabpopup.c
@@ -855,12 +855,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)
{