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.
This commit is contained in:
Carlos Garnacho 2011-07-03 18:20:53 +02:00
parent 4cb9a5e3bf
commit bde0d28f1b
11 changed files with 670 additions and 205 deletions

View File

@ -230,6 +230,35 @@ bell_flash_window_frame (MetaWindow *window)
bell_unflash_frame, window->frame, NULL); 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 frame of the focussed window. If there is no focussed window,
* flashes the screen. * flashes the screen.
@ -241,15 +270,11 @@ static void
bell_flash_frame (MetaDisplay *display, bell_flash_frame (MetaDisplay *display,
XkbAnyEvent *xkb_ev) XkbAnyEvent *xkb_ev)
{ {
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
MetaWindow *window; MetaWindow *window;
g_assert (xkb_ev->xkb_type == XkbBellNotify); g_assert (xkb_ev->xkb_type == XkbBellNotify);
window = meta_display_lookup_x_window (display, xkb_bell_event->window); window = get_flash_window (display, xkb_ev);
if (!window && (display->focus_window))
{
window = display->focus_window;
}
if (window && window->frame) if (window && window->frame)
{ {
bell_flash_window_frame (window); 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_EVENT_DESCRIPTION, _("Bell event"));
ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent"); ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent");
window = meta_display_lookup_x_window (display, xkb_bell_event->window); window = get_flash_window (display, xkb_ev);
if (!window && (display->focus_window) && (display->focus_window->frame))
window = display->focus_window;
if (window) if (window)
{ {

View File

@ -58,6 +58,7 @@ typedef struct _MetaWindowPropHooks MetaWindowPropHooks;
typedef struct MetaEdgeResistanceData MetaEdgeResistanceData; typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
typedef struct _MetaGrabInfo MetaGrabInfo; typedef struct _MetaGrabInfo MetaGrabInfo;
typedef struct _MetaFocusInfo MetaFocusInfo;
typedef void (* MetaWindowPingFunc) (MetaDisplay *display, typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
Window xwindow, Window xwindow,
@ -126,6 +127,26 @@ struct _MetaGrabInfo
int grab_resize_timeout_id; 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 struct _MetaDisplay
{ {
GObject parent_instance; GObject parent_instance;
@ -144,22 +165,8 @@ struct _MetaDisplay
#include <meta/atomnames.h> #include <meta/atomnames.h>
#undef item #undef item
/* This is the actual window from focus events, /* keyboard -> MetaFocusInfo hashtable */
* not the one we last set GHashTable *focus_info;
*/
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;
/* last user interaction time in any app */ /* last user interaction time in any app */
guint32 last_user_time; guint32 last_user_time;
@ -478,5 +485,8 @@ void meta_display_remove_grab_info (MetaDisplay *display,
MetaGrabInfo * meta_display_get_grab_info (MetaDisplay *display, MetaGrabInfo * meta_display_get_grab_info (MetaDisplay *display,
MetaDevice *device); MetaDevice *device);
MetaFocusInfo * meta_display_get_focus_info (MetaDisplay *display,
MetaDevice *device);
#endif #endif

View File

@ -189,7 +189,8 @@ static void prefs_changed_callback (MetaPreference pref,
static void sanity_check_timestamps (MetaDisplay *display, static void sanity_check_timestamps (MetaDisplay *display,
guint32 known_good_timestamp); guint32 known_good_timestamp);
MetaGroup* get_focussed_group (MetaDisplay *display); MetaGroup* get_focussed_group (MetaDisplay *display,
MetaDevice *keyboard);
static void static void
meta_display_get_property(GObject *object, meta_display_get_property(GObject *object,
@ -202,7 +203,16 @@ meta_display_get_property(GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_FOCUS_WINDOW: 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; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 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->pending_pings = NULL;
the_display->autoraise_timeout_id = 0; the_display->autoraise_timeout_id = 0;
the_display->autoraise_window = NULL; 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->mouse_mode = TRUE; /* Only relevant for mouse or sloppy focus */
the_display->allow_terminal_deactivation = TRUE; /* Only relevant for when a 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, the_display->current_grabs = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) g_free); (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); the_display->edge_resistance_info = g_hash_table_new (NULL, NULL);
#ifdef HAVE_XSYNC #ifdef HAVE_XSYNC
@ -784,7 +794,6 @@ meta_display_open (void)
DefaultRootWindow (the_display->xdisplay), DefaultRootWindow (the_display->xdisplay),
PropertyChangeMask); PropertyChangeMask);
the_display->last_focus_time = timestamp;
the_display->last_user_time = timestamp; the_display->last_user_time = timestamp;
the_display->compositor = NULL; the_display->compositor = NULL;
@ -1954,8 +1963,14 @@ event_callback (XEvent *event,
/* This is from our synchronous grab since /* This is from our synchronous grab since
* it has no modifiers and was on the client window * it has no modifiers and was on the client window
*/ */
MetaFocusInfo *focus_info;
MetaDevice *keyboard;
int mode; 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 /* When clicking a different app in click-to-focus
* in application-based mode, and the different * in application-based mode, and the different
* app is not a dock or desktop, eat the focus click. * app is not a dock or desktop, eat the focus click.
@ -1965,9 +1980,9 @@ event_callback (XEvent *event,
!window->has_focus && !window->has_focus &&
window->type != META_WINDOW_DOCK && window->type != META_WINDOW_DOCK &&
window->type != META_WINDOW_DESKTOP && window->type != META_WINDOW_DESKTOP &&
(display->focus_window == NULL || (focus_info == NULL || focus_info->focus_window == NULL ||
!meta_window_same_application (window, !meta_window_same_application (window,
display->focus_window))) focus_info->focus_window)))
mode = AsyncPointer; /* eat focus click */ mode = AsyncPointer; /* eat focus click */
else else
mode = ReplayPointer; /* give event back */ mode = ReplayPointer; /* give event back */
@ -2051,6 +2066,9 @@ event_callback (XEvent *event,
detail != NotifyInferior && detail != NotifyInferior &&
meta_display_focus_sentinel_clear (display)) meta_display_focus_sentinel_clear (display))
{ {
MetaFocusInfo *focus_info;
MetaDevice *keyboard;
switch (meta_prefs_get_focus_mode ()) switch (meta_prefs_get_focus_mode ())
{ {
case META_FOCUS_MODE_SLOPPY: case META_FOCUS_MODE_SLOPPY:
@ -2082,6 +2100,10 @@ event_callback (XEvent *event,
"Auto raise is disabled\n"); "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* /* In mouse focus mode, we defocus when the mouse *enters*
* the DESKTOP window, instead of defocusing on LeaveNotify. * the DESKTOP window, instead of defocusing on LeaveNotify.
* This is because having the mouse enter override-redirect * This is because having the mouse enter override-redirect
@ -2093,12 +2115,14 @@ event_callback (XEvent *event,
*/ */
if (window->type == META_WINDOW_DESKTOP && if (window->type == META_WINDOW_DESKTOP &&
meta_prefs_get_focus_mode() == META_FOCUS_MODE_MOUSE && 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, 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", "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, meta_display_focus_the_no_focus_window (display,
window->screen, window->screen,
evtime); evtime);
@ -4165,12 +4189,18 @@ meta_display_increment_event_serial (MetaDisplay *display)
void void
meta_display_update_active_window_hint (MetaDisplay *display) meta_display_update_active_window_hint (MetaDisplay *display)
{ {
MetaFocusInfo *focus_info;
MetaDevice *keyboard;
GSList *tmp; GSList *tmp;
gulong data[1]; gulong data[1];
if (display->focus_window) keyboard = meta_device_map_lookup (display->device_map,
data[0] = display->focus_window->xwindow; 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 else
data[0] = None; data[0] = None;
@ -4558,23 +4588,29 @@ meta_display_window_has_pending_pings (MetaDisplay *display,
} }
MetaGroup* MetaGroup*
get_focussed_group (MetaDisplay *display) get_focussed_group (MetaDisplay *display,
MetaDevice *keyboard)
{ {
if (display->focus_window) MetaFocusInfo *focus_info;
return display->focus_window->group;
focus_info = meta_display_get_focus_info (display, keyboard);
if (focus_info && focus_info->focus_window)
return focus_info->focus_window->group;
else else
return NULL; 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_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* static MetaWindow*
find_tab_forward (MetaDisplay *display, find_tab_forward (MetaDisplay *display,
MetaTabList type, MetaTabList type,
MetaScreen *screen, MetaScreen *screen,
MetaWorkspace *workspace, MetaWorkspace *workspace,
MetaDevice *device,
GList *start, GList *start,
gboolean skip_first) gboolean skip_first)
{ {
@ -4592,7 +4628,7 @@ find_tab_forward (MetaDisplay *display,
MetaWindow *window = tmp->data; MetaWindow *window = tmp->data;
if (window->screen == screen && if (window->screen == screen &&
IN_TAB_CHAIN (window, type)) IN_TAB_CHAIN (window, device, type))
return window; return window;
tmp = tmp->next; tmp = tmp->next;
@ -4603,7 +4639,7 @@ find_tab_forward (MetaDisplay *display,
{ {
MetaWindow *window = tmp->data; MetaWindow *window = tmp->data;
if (IN_TAB_CHAIN (window, type)) if (IN_TAB_CHAIN (window, device, type))
return window; return window;
tmp = tmp->next; tmp = tmp->next;
@ -4617,6 +4653,7 @@ find_tab_backward (MetaDisplay *display,
MetaTabList type, MetaTabList type,
MetaScreen *screen, MetaScreen *screen,
MetaWorkspace *workspace, MetaWorkspace *workspace,
MetaDevice *device,
GList *start, GList *start,
gboolean skip_last) gboolean skip_last)
{ {
@ -4633,7 +4670,7 @@ find_tab_backward (MetaDisplay *display,
MetaWindow *window = tmp->data; MetaWindow *window = tmp->data;
if (window->screen == screen && if (window->screen == screen &&
IN_TAB_CHAIN (window, type)) IN_TAB_CHAIN (window, device, type))
return window; return window;
tmp = tmp->prev; tmp = tmp->prev;
@ -4644,7 +4681,7 @@ find_tab_backward (MetaDisplay *display,
{ {
MetaWindow *window = tmp->data; MetaWindow *window = tmp->data;
if (IN_TAB_CHAIN (window, type)) if (IN_TAB_CHAIN (window, device, type))
return window; return window;
tmp = tmp->prev; 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 * @display: a #MetaDisplay
* @type: type of tab list * @type: type of tab list
* @screen: a #MetaScreen * @screen: a #MetaScreen
* @workspace: origin workspace * @workspace: origin workspace
* @device: keyboard triggering Alt-TAB
* *
* Determine the list of windows that should be displayed for Alt-TAB * Determine the list of windows that should be displayed for Alt-TAB
* functionality. The windows are returned in most recently used order. * 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 * Returns: (transfer container) (element-type Meta.Window): List of windows
*/ */
GList* GList*
meta_display_get_tab_list (MetaDisplay *display, meta_display_get_device_tab_list (MetaDisplay *display,
MetaTabList type, MetaTabList type,
MetaScreen *screen, MetaScreen *screen,
MetaWorkspace *workspace) MetaWorkspace *workspace,
MetaDevice *device)
{ {
GList *tab_list; GList *tab_list;
@ -4689,7 +4728,7 @@ meta_display_get_tab_list (MetaDisplay *display,
if (!window->minimized && if (!window->minimized &&
window->screen == screen && window->screen == screen &&
IN_TAB_CHAIN (window, type)) IN_TAB_CHAIN (window, device, type))
tab_list = g_list_prepend (tab_list, window); tab_list = g_list_prepend (tab_list, window);
tmp = tmp->next; tmp = tmp->next;
@ -4706,7 +4745,7 @@ meta_display_get_tab_list (MetaDisplay *display,
if (window->minimized && if (window->minimized &&
window->screen == screen && window->screen == screen &&
IN_TAB_CHAIN (window, type)) IN_TAB_CHAIN (window, device, type))
tab_list = g_list_prepend (tab_list, window); tab_list = g_list_prepend (tab_list, window);
tmp = tmp->next; tmp = tmp->next;
@ -4729,7 +4768,7 @@ meta_display_get_tab_list (MetaDisplay *display,
/* Check to see if it demands attention */ /* Check to see if it demands attention */
if (l_window->wm_state_demands_attention && if (l_window->wm_state_demands_attention &&
l_window->workspace!=workspace && 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 */ /* if it does, add it to the popup */
tab_list = g_list_prepend (tab_list, l_window); tab_list = g_list_prepend (tab_list, l_window);
@ -4742,6 +4781,107 @@ meta_display_get_tab_list (MetaDisplay *display,
return tab_list; return tab_list;
} }
/**
* meta_display_get_tab_list:
* @display: a #MetaDisplay
* @type: type of tab list
* @screen: a #MetaScreen
* @workspace: origin workspace
*
* 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.
*
* Returns: (transfer none): Next window
*
*/
MetaWindow*
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;
MetaWindow *ret;
tab_list = meta_display_get_tab_list(display,
type,
screen,
workspace);
if (tab_list == NULL)
return NULL;
if (window != NULL)
{
g_assert (window->display == 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
{
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,
device, tab_list, skip);
else
ret = find_tab_forward (display, type, screen, workspace,
device, tab_list, skip);
}
g_list_free (tab_list);
return ret;
}
/** /**
* meta_display_get_tab_next: * meta_display_get_tab_next:
* @display: a #MetaDisplay * @display: a #MetaDisplay
@ -4765,46 +4905,51 @@ meta_display_get_tab_next (MetaDisplay *display,
MetaWindow *window, MetaWindow *window,
gboolean backward) gboolean backward)
{ {
gboolean skip; MetaDevice *keyboard;
GList *tab_list;
MetaWindow *ret;
tab_list = meta_display_get_tab_list(display,
type,
screen,
workspace);
if (tab_list == NULL) keyboard = meta_device_map_lookup (display->device_map,
return NULL; META_CORE_KEYBOARD_ID);
if (window != NULL) return meta_display_get_device_tab_next (display, type,
{ screen, workspace,
g_assert (window->display == display); window, keyboard,
backward);
}
if (backward) /**
ret = find_tab_backward (display, type, screen, workspace, * meta_display_get_device_tab_current:
g_list_find (tab_list, * @display: a #MetaDisplay
window), * @type: type of tab list
TRUE); * @screen: a #MetaScreen
else * @workspace: origin workspace
ret = find_tab_forward (display, type, screen, workspace, * @device: keyboard triggering alt-TAB
g_list_find (tab_list, *
window), * Determine the active window that should be displayed for Alt-TAB.
TRUE); *
} * Returns: (transfer none): Current window
*
*/
MetaWindow*
meta_display_get_device_tab_current (MetaDisplay *display,
MetaTabList type,
MetaScreen *screen,
MetaWorkspace *workspace,
MetaDevice *device)
{
MetaFocusInfo *focus_info;
MetaWindow *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, device, type) &&
(workspace == NULL ||
meta_window_located_on_workspace (window, workspace)))
return window;
else else
{ return NULL;
skip = display->focus_window != NULL &&
tab_list->data == display->focus_window;
if (backward)
ret = find_tab_backward (display, type, screen, workspace,
tab_list, skip);
else
ret = find_tab_forward (display, type, screen, workspace,
tab_list, skip);
}
g_list_free (tab_list);
return ret;
} }
/** /**
@ -4825,18 +4970,14 @@ meta_display_get_tab_current (MetaDisplay *display,
MetaScreen *screen, MetaScreen *screen,
MetaWorkspace *workspace) MetaWorkspace *workspace)
{ {
MetaWindow *window; MetaDevice *keyboard;
window = display->focus_window; keyboard = meta_device_map_lookup (display->device_map,
META_CORE_KEYBOARD_ID);
if (window != NULL && return meta_display_get_device_tab_current (display, type,
window->screen == screen && screen, workspace,
IN_TAB_CHAIN (window, type) && keyboard);
(workspace == NULL ||
meta_window_located_on_workspace (window, workspace)))
return window;
else
return NULL;
} }
int int
@ -5351,15 +5492,29 @@ static void
sanity_check_timestamps (MetaDisplay *display, sanity_check_timestamps (MetaDisplay *display,
guint32 timestamp) 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 " if (XSERVER_TIME_IS_BEFORE (timestamp, focus_info->last_focus_time))
"timestamp (%u). This most likely represents a buggy " {
"client sending inaccurate timestamps in messages such as " meta_warning ("last_focus_time (%u) for device %d is greater than comparison "
"_NET_ACTIVE_WINDOW. Trying to work around...\n", "timestamp (%u). This most likely represents a buggy "
display->last_focus_time, timestamp); "client sending inaccurate timestamps in messages such as "
display->last_focus_time = timestamp; "_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)) if (XSERVER_TIME_IS_BEFORE (timestamp, display->last_user_time))
{ {
GSList *windows; GSList *windows;
@ -5396,14 +5551,19 @@ sanity_check_timestamps (MetaDisplay *display,
static gboolean static gboolean
timestamp_too_old (MetaDisplay *display, timestamp_too_old (MetaDisplay *display,
MetaWindow *window, MetaWindow *window,
MetaDevice *device,
guint32 *timestamp) guint32 *timestamp)
{ {
MetaFocusInfo *focus_info;
/* FIXME: If Soeren's suggestion in bug 151984 is implemented, it will allow /* 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 * us to sanity check the timestamp here and ensure it doesn't correspond to
* a future time (though we would want to rename to * a future time (though we would want to rename to
* timestamp_too_old_or_in_future). * timestamp_too_old_or_in_future).
*/ */
focus_info = meta_display_get_focus_info (display, device);
if (*timestamp == CurrentTime) if (*timestamp == CurrentTime)
{ {
meta_warning ("Got a request to focus %s with a timestamp of 0. This " meta_warning ("Got a request to focus %s with a timestamp of 0. This "
@ -5413,31 +5573,34 @@ timestamp_too_old (MetaDisplay *display,
*timestamp = meta_display_get_current_time_roundtrip (display); *timestamp = meta_display_get_current_time_roundtrip (display);
return FALSE; 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)) if (XSERVER_TIME_IS_BEFORE (*timestamp, display->last_user_time))
{ {
meta_topic (META_DEBUG_FOCUS, 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", "is less than %u and %u.\n",
meta_device_get_id (device),
window ? window->desc : "the no_focus_window", window ? window->desc : "the no_focus_window",
*timestamp, *timestamp,
display->last_user_time, display->last_user_time,
display->last_focus_time); focus_info->last_focus_time);
return TRUE; return TRUE;
} }
else else
{ {
meta_topic (META_DEBUG_FOCUS, 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 " "recent user_time, but less recent than "
"last_focus_time (%u < %u < %u); adjusting " "last_focus_time (%u < %u < %u); adjusting "
"accordingly. (See bug 167358)\n", "accordingly. (See bug 167358)\n",
meta_device_get_id (device),
window ? window->desc : "the no_focus_window", window ? window->desc : "the no_focus_window",
display->last_user_time, display->last_user_time,
*timestamp, *timestamp,
display->last_focus_time); focus_info->last_focus_time);
*timestamp = display->last_focus_time; *timestamp = focus_info->last_focus_time;
return FALSE; return FALSE;
} }
} }
@ -5446,46 +5609,84 @@ timestamp_too_old (MetaDisplay *display,
} }
void void
meta_display_set_input_focus_window (MetaDisplay *display, meta_display_set_keyboard_focus (MetaDisplay *display,
MetaWindow *window, MetaWindow *window,
gboolean focus_frame, MetaDevice *keyboard,
guint32 timestamp) 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; return;
xwindow = focus_frame ? window->frame->xwindow : window->xwindow;
meta_error_trap_push (display); meta_error_trap_push (display);
XSetInputFocus (display->xdisplay, meta_device_keyboard_set_focus_window (META_DEVICE_KEYBOARD (keyboard),
focus_frame ? window->frame->xwindow : window->xwindow, xwindow, timestamp);
RevertToPointerRoot,
timestamp);
meta_error_trap_pop (display); meta_error_trap_pop (display);
display->expected_focus_window = window; focus_info = meta_display_get_focus_info (display, keyboard);
display->last_focus_time = timestamp;
focus_info->expected_focus_window = window;
focus_info->last_focus_time = timestamp;
display->active_screen = window->screen; display->active_screen = window->screen;
if (window != display->autoraise_window) if (window != display->autoraise_window)
meta_display_remove_autoraise_callback (window->display); meta_display_remove_autoraise_callback (window->display);
} }
void
meta_display_unset_keyboard_focus (MetaDisplay *display,
MetaScreen *screen,
MetaDevice *keyboard,
guint32 timestamp)
{
MetaFocusInfo *focus_info;
if (timestamp_too_old (display, NULL, keyboard, &timestamp))
return;
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 void
meta_display_focus_the_no_focus_window (MetaDisplay *display, meta_display_focus_the_no_focus_window (MetaDisplay *display,
MetaScreen *screen, MetaScreen *screen,
guint32 timestamp) guint32 timestamp)
{ {
if (timestamp_too_old (display, NULL, &timestamp)) MetaDevice *keyboard;
return;
XSetInputFocus (display->xdisplay, keyboard = meta_device_map_lookup (display->device_map,
screen->no_focus_window, META_CORE_KEYBOARD_ID);
RevertToPointerRoot, meta_display_unset_keyboard_focus (display, screen, keyboard,
timestamp); timestamp);
display->expected_focus_window = NULL;
display->last_focus_time = timestamp;
display->active_screen = screen;
meta_display_remove_autoraise_callback (display);
} }
void void
@ -5552,6 +5753,30 @@ meta_display_has_shape (MetaDisplay *display)
return META_DISPLAY_HAS_SHAPE (display); return META_DISPLAY_HAS_SHAPE (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: * meta_display_get_focus_window:
* @display: a #MetaDisplay * @display: a #MetaDisplay
@ -5567,7 +5792,12 @@ meta_display_has_shape (MetaDisplay *display)
MetaWindow * MetaWindow *
meta_display_get_focus_window (MetaDisplay *display) 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 int
@ -5689,3 +5919,28 @@ meta_display_get_grab_info (MetaDisplay *display,
return info; 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;
}

View File

@ -3108,20 +3108,26 @@ handle_activate_window_menu (MetaDisplay *display,
MetaKeyBinding *binding, MetaKeyBinding *binding,
gpointer dummy) 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; Time evtime;
int x, y; int x, y;
meta_window_get_position (display->focus_window, meta_window_get_position (focus_info->focus_window,
&x, &y); &x, &y);
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) 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); 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, x, y,
0, 0,
evtime); evtime);

View File

@ -354,10 +354,17 @@ avoid_being_obscured_as_second_modal_dialog (MetaWindow *window,
* know about the modal-to-the-main-window part. * know about the modal-to-the-main-window part.
*/ */
MetaWindow *focus_window; MetaWindow *focus_window = NULL;
MetaFocusInfo *focus_info;
MetaRectangle overlap; 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 && if (window->denied_focus_and_not_transient &&
window->wm_state_modal && /* FIXME: Maybe do this for all transients? */ window->wm_state_modal && /* FIXME: Maybe do this for all transients? */
@ -913,8 +920,16 @@ meta_window_place (MetaWindow *window,
gboolean found_fit; gboolean found_fit;
MetaWindow *focus_window; MetaWindow *focus_window;
MetaRectangle overlap; MetaRectangle overlap;
MetaDevice *pointer, *keyboard;
MetaFocusInfo *focus_info;
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);
g_assert (focus_info != NULL);
focus_window = focus_info->focus_window;
g_assert (focus_window != NULL); g_assert (focus_window != NULL);
/* No need to do anything if the window doesn't overlap at all */ /* No need to do anything if the window doesn't overlap at all */

View File

@ -211,13 +211,23 @@ meta_stack_thaw (MetaStack *stack)
stack_sync_to_server (stack); stack_sync_to_server (stack);
} }
typedef struct _FocusedForeachData FocusedForeachData;
struct _FocusedForeachData
{
MetaWindow *window;
gboolean focused_transient;
};
static gboolean static gboolean
is_focused_foreach (MetaWindow *window, is_focused_foreach (MetaWindow *window,
void *data) 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 FALSE;
} }
return TRUE; return TRUE;
@ -240,6 +250,9 @@ get_standalone_layer (MetaWindow *window)
{ {
MetaStackLayer layer; MetaStackLayer layer;
gboolean focused_transient = FALSE; gboolean focused_transient = FALSE;
MetaFocusInfo *focus_info;
MetaDevice *keyboard;
FocusedForeachData focused_data = { 0 };
switch (window->type) switch (window->type)
{ {
@ -264,19 +277,29 @@ get_standalone_layer (MetaWindow *window)
layer = META_LAYER_OVERRIDE_REDIRECT; layer = META_LAYER_OVERRIDE_REDIRECT;
break; 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, meta_window_foreach_transient (window,
is_focused_foreach, is_focused_foreach,
&focused_transient); &focused_data);
if (window->wm_state_below) if (window->wm_state_below)
layer = META_LAYER_BOTTOM; layer = META_LAYER_BOTTOM;
else if (window->fullscreen && else if (window->fullscreen &&
(focused_transient || (focused_transient ||
window == window->display->expected_focus_window || !focus_info ||
window->display->expected_focus_window == NULL || window == focus_info->expected_focus_window ||
(window->display->expected_focus_window != NULL && focus_info->expected_focus_window == NULL ||
(focus_info->expected_focus_window != NULL &&
windows_on_different_monitor (window, windows_on_different_monitor (window,
window->display->expected_focus_window)))) focus_info->expected_focus_window))))
layer = META_LAYER_FULLSCREEN; layer = META_LAYER_FULLSCREEN;
else if (window->wm_state_above) else if (window->wm_state_above)
layer = META_LAYER_TOP; layer = META_LAYER_TOP;

View File

@ -318,6 +318,12 @@ struct _MetaWindow
/* if TRUE, application is buggy and SYNC resizing is turned off */ /* if TRUE, application is buggy and SYNC resizing is turned off */
guint disable_sync : 1; guint disable_sync : 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 */ /* if non-NULL, the bounds of the window frame */
cairo_region_t *frame_bounds; cairo_region_t *frame_bounds;
@ -398,6 +404,9 @@ struct _MetaWindow
/* Current grab op for this window, or NULL */ /* Current grab op for this window, or NULL */
MetaGrabInfo *cur_grab; MetaGrabInfo *cur_grab;
/* Focus info if the window is focused, or NULL */
MetaFocusInfo *cur_focus;
}; };
struct _MetaWindowClass struct _MetaWindowClass
@ -647,6 +656,7 @@ void meta_window_update_monitor (MetaWindow *window);
void meta_window_update_on_all_workspaces (MetaWindow *window); void meta_window_update_on_all_workspaces (MetaWindow *window);
void meta_window_propagate_focus_appearance (MetaWindow *window, void meta_window_propagate_focus_appearance (MetaWindow *window,
MetaDevice *keyboard,
gboolean focused); gboolean focused);
MetaDevice * meta_window_guess_grab_pointer (MetaWindow *window); MetaDevice * meta_window_guess_grab_pointer (MetaWindow *window);

View File

@ -1471,7 +1471,9 @@ reload_transient_for (MetaWindow *window,
MetaWindow *parent = NULL; MetaWindow *parent = NULL;
if (meta_window_appears_focused (window) && window->xtransient_for != None) 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);
window->xtransient_for = None; window->xtransient_for = None;
@ -1537,7 +1539,9 @@ reload_transient_for (MetaWindow *window,
meta_window_queue (window, META_QUEUE_MOVE_RESIZE); meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
if (meta_window_appears_focused (window) && window->xtransient_for != None) 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 static void

View File

@ -1481,6 +1481,7 @@ void
meta_window_unmanage (MetaWindow *window, meta_window_unmanage (MetaWindow *window,
guint32 timestamp) guint32 timestamp)
{ {
MetaFocusInfo *focus_info = NULL;
GList *tmp; GList *tmp;
meta_verbose ("Unmanaging 0x%lx\n", window->xwindow); meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
@ -1527,6 +1528,10 @@ meta_window_unmanage (MetaWindow *window,
* group if window->unmanaging * 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. /* If we have the focus, focus some other window.
* This is done first, so that if the unmap causes * This is done first, so that if the unmap causes
* an EnterNotify the EnterNotify will have final say * an EnterNotify the EnterNotify will have final say
@ -1534,22 +1539,24 @@ meta_window_unmanage (MetaWindow *window,
* invariants. * invariants.
*/ */
if (meta_window_appears_focused (window)) if (meta_window_appears_focused (window))
meta_window_propagate_focus_appearance (window, FALSE); meta_window_propagate_focus_appearance (window,
if (window->has_focus) window->focus_keyboard,
FALSE);
if (window->focus_keyboard)
{ {
meta_topic (META_DEBUG_FOCUS, if (window->expecting_focus_in)
"Focusing default window since we're unmanaging %s\n", {
window->desc); meta_topic (META_DEBUG_FOCUS,
meta_workspace_focus_default_window (window->screen->active_workspace, "Focusing default window since expected focus window freed %s\n",
window, window->desc);
timestamp); focus_info->expected_focus_window = NULL;
} }
else if (window->display->expected_focus_window == window) else
{ meta_topic (META_DEBUG_FOCUS,
meta_topic (META_DEBUG_FOCUS, "Focusing default window since we're unmanaging %s\n",
"Focusing default window since expected focus window freed %s\n", window->desc);
window->desc);
window->display->expected_focus_window = NULL;
meta_workspace_focus_default_window (window->screen->active_workspace, meta_workspace_focus_default_window (window->screen->active_workspace,
window, window,
timestamp); timestamp);
@ -1579,10 +1586,14 @@ meta_window_unmanage (MetaWindow *window,
g_assert (window->cur_grab == NULL); 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; focus_info->focus_window = NULL;
g_object_notify (G_OBJECT (window->display), "focus-window");
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) if (window->maximized_horizontally || window->maximized_vertically)
@ -2349,12 +2360,17 @@ meta_window_queue (MetaWindow *window, guint queuebits)
} }
static gboolean static gboolean
intervening_user_event_occurred (MetaWindow *window) intervening_user_event_occurred (MetaWindow *window,
MetaDevice *keyboard)
{ {
guint32 compare; 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, meta_topic (META_DEBUG_STARTUP,
"COMPARISON:\n" "COMPARISON:\n"
@ -2503,12 +2519,15 @@ __window_is_terminal (MetaWindow *window)
*/ */
static void static void
window_state_on_map (MetaWindow *window, window_state_on_map (MetaWindow *window,
gboolean *takes_focus, MetaDevice *keyboard,
gboolean *places_on_top) gboolean *takes_focus,
gboolean *places_on_top)
{ {
gboolean intervening_events; 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; *takes_focus = !intervening_events;
*places_on_top = *takes_focus; *places_on_top = *takes_focus;
@ -2530,11 +2549,11 @@ window_state_on_map (MetaWindow *window,
* terminals due to new window map, but the latter is a much easier * terminals due to new window map, but the latter is a much easier
* approximation to enforce so we do that. * 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 && meta_prefs_get_focus_new_windows () == META_FOCUS_NEW_WINDOWS_STRICT &&
!window->display->allow_terminal_deactivation && !window->display->allow_terminal_deactivation &&
__window_is_terminal (window->display->focus_window) && __window_is_terminal (focus_info->focus_window) &&
!meta_window_is_ancestor_of_transient (window->display->focus_window, !meta_window_is_ancestor_of_transient (focus_info->focus_window,
window)) window))
{ {
meta_topic (META_DEBUG_FOCUS, meta_topic (META_DEBUG_FOCUS,
@ -2765,20 +2784,30 @@ meta_window_show (MetaWindow *window)
gboolean takes_focus_on_map; gboolean takes_focus_on_map;
gboolean place_on_top_on_map; gboolean place_on_top_on_map;
gboolean needs_stacking_adjustment; gboolean needs_stacking_adjustment;
MetaWindow *focus_window; MetaWindow *focus_window = NULL;
gboolean toplevel_was_mapped; gboolean toplevel_was_mapped;
gboolean toplevel_now_mapped; gboolean toplevel_now_mapped;
gboolean notify_demands_attention = FALSE; gboolean notify_demands_attention = FALSE;
MetaDevice *pointer, *keyboard;
MetaFocusInfo *focus_info;
meta_topic (META_DEBUG_WINDOW_STATE, meta_topic (META_DEBUG_WINDOW_STATE,
"Showing window %s, shaded: %d iconic: %d placed: %d\n", "Showing window %s, shaded: %d iconic: %d placed: %d\n",
window->desc, window->shaded, window->iconic, window->placed); 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); 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; 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; needs_stacking_adjustment = FALSE;
meta_topic (META_DEBUG_WINDOW_STATE, meta_topic (META_DEBUG_WINDOW_STATE,
@ -3109,14 +3138,13 @@ meta_window_hide (MetaWindow *window)
invalidate_work_areas (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 * https://bugzilla.gnome.org/show_bug.cgi?id=597352
* We may have already switched away from this window but not yet * We may have already switched away from this window but not yet
* gotten FocusIn/FocusOut events. A more complete comprehensive * gotten FocusIn/FocusOut events. A more complete comprehensive
* fix for these type of issues is described in the bug. * fix for these type of issues is described in the bug.
*/ */
if (window->has_focus && if (window->has_focus && window->expecting_focus_in)
window == window->display->expected_focus_window)
{ {
MetaWindow *not_this_one = NULL; MetaWindow *not_this_one = NULL;
MetaWorkspace *my_workspace = meta_window_get_workspace (window); MetaWorkspace *my_workspace = meta_window_get_workspace (window);
@ -5312,13 +5340,22 @@ meta_window_focus (MetaWindow *window,
if (window->take_focus) if (window->take_focus)
{ {
MetaFocusInfo *focus_info;
MetaDevice *keyboard;
meta_topic (META_DEBUG_FOCUS, meta_topic (META_DEBUG_FOCUS,
"Sending WM_TAKE_FOCUS to %s since take_focus = true\n", "Sending WM_TAKE_FOCUS to %s since take_focus = true\n",
window->desc); window->desc);
meta_window_send_icccm_message (window, meta_window_send_icccm_message (window,
window->display->atom_WM_TAKE_FOCUS, window->display->atom_WM_TAKE_FOCUS,
timestamp); 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;
} }
} }
@ -5858,7 +5895,16 @@ meta_window_configure_request (MetaWindow *window,
if (event->xconfigurerequest.value_mask & CWStackMode) if (event->xconfigurerequest.value_mask & CWStackMode)
{ {
MetaWindow *active_window; 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 ()) if (meta_prefs_get_disable_workarounds ())
{ {
meta_topic (META_DEBUG_STACK, meta_topic (META_DEBUG_STACK,
@ -6477,17 +6523,26 @@ meta_window_client_message (MetaWindow *window,
*/ */
void void
meta_window_propagate_focus_appearance (MetaWindow *window, meta_window_propagate_focus_appearance (MetaWindow *window,
MetaDevice *keyboard,
gboolean focused) gboolean focused)
{ {
MetaWindow *child, *parent, *focus_window; MetaWindow *child, *parent, *focus_window;
MetaFocusInfo *focus_info;
if (!meta_prefs_get_attach_modal_dialogs ()) if (!meta_prefs_get_attach_modal_dialogs ())
return; return;
focus_window = window->display->focus_window;
child = window; child = window;
parent = meta_window_get_transient_for (child); 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 || child->type == META_WINDOW_MODAL_DIALOG)) while (parent && (!focused || child->type == META_WINDOW_MODAL_DIALOG))
{ {
gboolean child_focus_state_changed; gboolean child_focus_state_changed;
@ -6508,7 +6563,7 @@ meta_window_propagate_focus_appearance (MetaWindow *window,
} }
if (child_focus_state_changed && !parent->has_focus && 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"); g_object_notify (G_OBJECT (parent), "appears-focused");
if (parent->frame) if (parent->frame)
@ -6525,6 +6580,8 @@ meta_window_notify_focus (MetaWindow *window,
XEvent *event) XEvent *event)
{ {
guint evtype, mode, detail; guint evtype, mode, detail;
MetaFocusInfo *focus_info = NULL;
MetaDevice *keyboard;
Window xwindow; Window xwindow;
/* note the event can be on either the window or the frame, /* note the event can be on either the window or the frame,
@ -6550,14 +6607,19 @@ meta_window_notify_focus (MetaWindow *window,
meta_input_event_get_crossing_details (window->display, event, meta_input_event_get_crossing_details (window->display, event,
&mode, &detail); &mode, &detail);
xwindow = meta_input_event_get_window (window->display, event); xwindow = meta_input_event_get_window (window->display, event);
keyboard = meta_input_event_get_device (window->display, event);
} }
else else
{ {
xwindow = event->xany.window; xwindow = event->xany.window;
evtype = event->type; evtype = event->type;
mode = detail = 0; mode = detail = 0;
keyboard = window->focus_keyboard;
} }
if (keyboard)
focus_info = meta_display_get_focus_info (window->display, keyboard);
meta_topic (META_DEBUG_FOCUS, meta_topic (META_DEBUG_FOCUS,
"Focus %s event received on %s 0x%lx (%s) " "Focus %s event received on %s 0x%lx (%s) "
"mode %s detail %s\n", "mode %s detail %s\n",
@ -6611,17 +6673,22 @@ meta_window_notify_focus (MetaWindow *window,
{ {
if (window->override_redirect) if (window->override_redirect)
{ {
window->display->focus_window = NULL; focus_info->focus_window = NULL;
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");
return FALSE; return FALSE;
} }
if (window != window->display->focus_window) if (window != focus_info->focus_window)
{ {
meta_topic (META_DEBUG_FOCUS, meta_topic (META_DEBUG_FOCUS,
"* Focus --> %s\n", window->desc); "* Focus --> %s\n", window->desc);
window->display->focus_window = window; focus_info->focus_window = window;
window->has_focus = TRUE; window->has_focus = TRUE;
window->focus_keyboard = keyboard;
window->expecting_focus_in = FALSE;
/* Move to the front of the focusing workspace's MRU list. /* Move to the front of the focusing workspace's MRU list.
* We should only be "removing" it from the MRU list if it's * We should only be "removing" it from the MRU list if it's
@ -6679,7 +6746,9 @@ meta_window_notify_focus (MetaWindow *window,
meta_display_ungrab_focus_window_button (window->display, window); meta_display_ungrab_focus_window_button (window->display, window);
g_signal_emit (window, window_signals[FOCUS], 0); 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) if (!window->attached_focus_window)
{ {
@ -6687,7 +6756,7 @@ meta_window_notify_focus (MetaWindow *window,
if (window->frame) if (window->frame)
meta_frame_queue_draw (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 || else if (evtype == FocusOut ||
@ -6703,7 +6772,8 @@ meta_window_notify_focus (MetaWindow *window,
return TRUE; return TRUE;
} }
if (window == window->display->focus_window) if (focus_info &&
window == focus_info->focus_window)
{ {
meta_topic (META_DEBUG_FOCUS, meta_topic (META_DEBUG_FOCUS,
"%s is now the previous focus window due to being focused out or unmapped\n", "%s is now the previous focus window due to being focused out or unmapped\n",
@ -6712,11 +6782,18 @@ meta_window_notify_focus (MetaWindow *window,
meta_topic (META_DEBUG_FOCUS, meta_topic (META_DEBUG_FOCUS,
"* Focus --> NULL (was %s)\n", window->desc); "* 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->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) if (!window->attached_focus_window)
{ {

View File

@ -75,6 +75,9 @@ gboolean meta_display_has_shape (MetaDisplay *display);
MetaScreen *meta_display_screen_for_root (MetaDisplay *display, MetaScreen *meta_display_screen_for_root (MetaDisplay *display,
Window xroot); Window xroot);
MetaWindow *meta_display_get_keyboard_focus_window (MetaDisplay *display,
MetaDevice *keyboard);
MetaWindow *meta_display_get_focus_window (MetaDisplay *display); MetaWindow *meta_display_get_focus_window (MetaDisplay *display);
gboolean meta_display_xwindow_is_a_no_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, MetaScreen *screen,
MetaWorkspace *workspace); 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, gboolean meta_display_begin_grab_op (MetaDisplay *display,
MetaScreen *screen, MetaScreen *screen,
MetaWindow *window, MetaWindow *window,
@ -134,6 +157,16 @@ MetaKeyBindingAction meta_display_get_keybinding_action (MetaDisplay *display,
unsigned int keycode, unsigned int keycode,
unsigned long mask); 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 /* meta_display_set_input_focus_window is like XSetInputFocus, except
* that (a) it can't detect timestamps later than the current time, * that (a) it can't detect timestamps later than the current time,
* since Mutter isn't part of the XServer, and thus gives erroneous * since Mutter isn't part of the XServer, and thus gives erroneous

View File

@ -858,12 +858,21 @@ static WnckWindowDisplayInfo
meta_convert_meta_to_wnck (MetaWindow *window, MetaScreen *screen) meta_convert_meta_to_wnck (MetaWindow *window, MetaScreen *screen)
{ {
WnckWindowDisplayInfo wnck_window; WnckWindowDisplayInfo wnck_window;
MetaFocusInfo *focus_info;
GHashTableIter iter;
wnck_window.icon = window->icon; wnck_window.icon = window->icon;
wnck_window.mini_icon = window->mini_icon; wnck_window.mini_icon = window->mini_icon;
wnck_window.is_active = FALSE; 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) if (window->frame)
{ {