From 5f6f67fb4ecc398660f798faa1275d9f8358bbcd Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 3 Jul 2011 18:20:53 +0200 Subject: [PATCH] core: Make keyboard focus handling happen per-keyboard MetaFocusInfo is a struct holding all necessary info, code has been updated to use the per-keyboard focus info instead of the old fields. --- src/core/bell.c | 41 ++- src/core/display-private.h | 42 +-- src/core/display.c | 530 ++++++++++++++++++++++++++++--------- src/core/keybindings.c | 14 +- src/core/place.c | 21 +- src/core/stack.c | 39 ++- src/core/window-private.h | 10 + src/core/window-props.c | 15 +- src/core/window.c | 173 ++++++++---- src/meta/display.h | 33 +++ src/ui/tabpopup.c | 13 +- 11 files changed, 710 insertions(+), 221 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 #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); @@ -4944,6 +5000,107 @@ meta_display_get_tab_list (MetaDisplay *display, 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: * @display: a #MetaDisplay @@ -4967,46 +5124,51 @@ meta_display_get_tab_next (MetaDisplay *display, MetaWindow *window, gboolean backward) { - gboolean skip; - GList *tab_list; - MetaWindow *ret; - tab_list = meta_display_get_tab_list(display, - type, - screen, - workspace); + MetaDevice *keyboard; - if (tab_list == NULL) - return NULL; - - if (window != NULL) - { - g_assert (window->display == display); - - if (backward) - ret = find_tab_backward (display, type, screen, workspace, - g_list_find (tab_list, - window), - TRUE); - else - ret = find_tab_forward (display, type, screen, workspace, - g_list_find (tab_list, - window), - TRUE); - } + 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. + * + * 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 - { - 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; + return NULL; } /** @@ -5027,18 +5189,14 @@ meta_display_get_tab_current (MetaDisplay *display, MetaScreen *screen, MetaWorkspace *workspace) { - MetaWindow *window; + MetaDevice *keyboard; - window = display->focus_window; - - if (window != NULL && - window->screen == screen && - IN_TAB_CHAIN (window, type) && - (workspace == NULL || - meta_window_located_on_workspace (window, workspace))) - return window; - else - return NULL; + 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 @@ -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, ×tamp)) + MetaFocusInfo *focus_info; + Window xwindow; + + if (timestamp_too_old (display, window, keyboard, ×tamp)) 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,24 +5838,56 @@ 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, ×tamp)) + MetaFocusInfo *focus_info; + + if (timestamp_too_old (display, NULL, keyboard, ×tamp)) 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) { @@ -5734,6 +5952,30 @@ meta_display_has_shape (MetaDisplay *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: * @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; - 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); /* 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_window_propagate_focus_appearance (window, + window->focus_keyboard, + FALSE); + + if (window->focus_keyboard) { - 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_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) {