From 3edad8599c6f91ea86123baac08ece858bc27aa7 Mon Sep 17 00:00:00 2001 From: Rob Adams Date: Fri, 30 May 2003 20:24:00 +0000 Subject: [PATCH] CVS2003-05-29 Rob Adams CVS2003-05-29 Rob Adams Use a new property _METACITY_SENTINEL to eliminate a race condition that causes focus to behave badly with sloppy/mouse focus when lots of windows are mapped/unmapped, such as with a workspace switch. The EnterNotify events on a display are ignored until the PropertyNotify sent after all the window maps is received. This is a fix for #110970. * src/display.[ch]: New _METACITY_SENTINEL atom. (event_callback): ignore EnterNotify if the sentinel isn't clear, and decrement the sentinel counter when the PropertyNotify is received. (meta_display_increment_focus_sentinel): new function. Increments the sentinel counter and updates the property on a root window on this display. (meta_display_decrement_focus_sentinel): Decrement the sentinel counter. (meta_display_focus_sentinel_clear): returns whether the sentinel counter is zero. * src/window.c (idle_calc_showing): after showing windows, call meta_display_increment_focus_sentinel on each display for windows to be shown. * src/workspace.[ch] (meta_workspace_activate_with_focus): new function activates a workspace and focuses a particular window after the workspace is activated. (meta_workspace_activate): now just a wrapper for meta_workspace_activate_with_focus * src/keybindings.c: use new meta_workspace_activate_with_focus function to ensure that focus will follow the focused window through the workspace switch. : ---------------------------------------------------------------------- --- ChangeLog | 35 +++++++++++++++++++++++++++++++++ src/display.c | 49 +++++++++++++++++++++++++++++++++++++++++++++-- src/display.h | 11 +++++++++++ src/keybindings.c | 2 +- src/window.c | 25 ++++++++++++++++++++++-- src/workspace.c | 23 +++++++++++++++++++--- src/workspace.h | 4 +++- 7 files changed, 140 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 470508400..db534681d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2003-05-29 Rob Adams + + Use a new property _METACITY_SENTINEL to eliminate a race + condition that causes focus to behave badly with sloppy/mouse + focus when lots of windows are mapped/unmapped, such as with a + workspace switch. The EnterNotify events on a display are ignored + until the PropertyNotify sent after all the window maps is + received. This is a fix for #110970. + + * src/display.[ch]: New _METACITY_SENTINEL atom. + (event_callback): ignore EnterNotify if the sentinel isn't clear, + and decrement the sentinel counter when the PropertyNotify is + received. + (meta_display_increment_focus_sentinel): new function. Increments + the sentinel counter and updates the property on a root window on + this display. + (meta_display_decrement_focus_sentinel): Decrement the sentinel + counter. + (meta_display_focus_sentinel_clear): returns whether the sentinel + counter is zero. + + * src/window.c (idle_calc_showing): after showing windows, call + meta_display_increment_focus_sentinel on each display for windows + to be shown. + + * src/workspace.[ch] (meta_workspace_activate_with_focus): new + function activates a workspace and focuses a particular window + after the workspace is activated. + (meta_workspace_activate): now just a wrapper for + meta_workspace_activate_with_focus + + * src/keybindings.c: use new meta_workspace_activate_with_focus + function to ensure that focus will follow the focused window + through the workspace switch. + 2003-05-29 Havoc Pennington * src/theme-parser.c (meta_theme_load): s/int/gsize/ for diff --git a/src/display.c b/src/display.c index 523fa1c66..a9e3f30ef 100644 --- a/src/display.c +++ b/src/display.c @@ -269,7 +269,8 @@ meta_display_open (const char *name) "SYNC_COUNTER", "_GNOME_PANEL_ACTION", "_GNOME_PANEL_ACTION_MAIN_MENU", - "_GNOME_PANEL_ACTION_RUN_DIALOG" + "_GNOME_PANEL_ACTION_RUN_DIALOG", + "_METACITY_SENTINEL" }; Atom atoms[G_N_ELEMENTS(atom_names)]; @@ -416,6 +417,7 @@ meta_display_open (const char *name) display->atom_gnome_panel_action = atoms[81]; display->atom_gnome_panel_action_main_menu = atoms[82]; display->atom_gnome_panel_action_run_dialog = atoms[83]; + display->atom_metacity_sentinel = atoms[84]; display->prop_hooks = NULL; meta_display_init_window_prop_hooks (display); @@ -473,6 +475,7 @@ meta_display_open (const char *name) display->ungrab_should_not_cause_focus_window = None; display->current_time = CurrentTime; + display->sentinel_counter = 0; display->grab_op = META_GRAB_OP_NONE; display->grab_window = NULL; @@ -1434,7 +1437,8 @@ event_callback (XEvent *event, meta_window_handle_mouse_grab_op_event (window, event); /* do this even if window->has_focus to avoid races */ else if (window && !serial_is_ignored (display, event->xany.serial) && - event->xcrossing.detail != NotifyInferior) + event->xcrossing.detail != NotifyInferior && + meta_display_focus_sentinel_clear (display)) { switch (meta_prefs_get_focus_mode ()) { @@ -1749,6 +1753,16 @@ event_callback (XEvent *event, else if (event->xproperty.atom == display->atom_net_desktop_names) meta_screen_update_workspace_names (screen); + + /* we just use this property as a sentinel to avoid + * certain race conditions. See the comment for the + * sentinel_counter variable declaration in display.h + */ + if (event->xproperty.atom == + display->atom_metacity_sentinel) + { + meta_display_decrement_focus_sentinel (display); + } } } break; @@ -3996,3 +4010,34 @@ prefs_changed_callback (MetaPreference pref, meta_bell_set_audible (display, meta_prefs_bell_is_audible ()); } } + +void +meta_display_increment_focus_sentinel (MetaDisplay *display) +{ + unsigned long data[1]; + + data[0] = meta_display_get_current_time (display); + + XChangeProperty (display->xdisplay, + ((MetaScreen*) display->screens->data)->xroot, + display->atom_metacity_sentinel, + XA_CARDINAL, + 32, PropModeReplace, (guchar*) data, 1); + + display->sentinel_counter += 1; +} + +void +meta_display_decrement_focus_sentinel (MetaDisplay *display) +{ + display->sentinel_counter -= 1; + + if (display->sentinel_counter < 0) + display->sentinel_counter = 0; +} + +gboolean +meta_display_focus_sentinel_clear (MetaDisplay *display) +{ + return (display->sentinel_counter == 0); +} diff --git a/src/display.h b/src/display.h index 009566515..65f43b130 100644 --- a/src/display.h +++ b/src/display.h @@ -172,6 +172,7 @@ struct _MetaDisplay Atom atom_gnome_panel_action; Atom atom_gnome_panel_action_main_menu; Atom atom_gnome_panel_action_run_dialog; + Atom atom_metacity_sentinel; /* This is the actual window from focus events, * not the one we last set @@ -248,6 +249,12 @@ struct _MetaDisplay MetaResizePopup *grab_resize_popup; GTimeVal grab_last_moveresize_time; Time grab_motion_notify_time; + + /* we use property updates as sentinels for certain window focus events + * to avoid some race conditions on EnterNotify events + */ + int sentinel_counter; + #ifdef HAVE_XKB int xkb_base_event_type; #endif @@ -439,4 +446,8 @@ void meta_display_devirtualize_modifiers (MetaDisplay *display, MetaVirtualModifier modifiers, unsigned int *mask); +void meta_display_increment_focus_sentinel (MetaDisplay *display); +void meta_display_decrement_focus_sentinel (MetaDisplay *display); +gboolean meta_display_focus_sentinel_clear (MetaDisplay *display); + #endif diff --git a/src/keybindings.c b/src/keybindings.c index 395b30b8b..050733a7f 100644 --- a/src/keybindings.c +++ b/src/keybindings.c @@ -3022,7 +3022,7 @@ do_handle_move_to_workspace (MetaDisplay *display, /* Activate second, so the window is never unmapped */ meta_window_change_workspace (window, workspace); if (flip) - meta_workspace_activate (workspace); + meta_workspace_activate_with_focus (workspace, window); } else { diff --git a/src/window.c b/src/window.c index 326c188ab..7b65e95eb 100644 --- a/src/window.c +++ b/src/window.c @@ -1338,6 +1338,7 @@ idle_calc_showing (gpointer data) GSList *should_show; GSList *should_hide; GSList *unplaced; + GSList *displays; meta_topic (META_DEBUG_WINDOW_STATE, "Clearing the calc_showing queue\n"); @@ -1361,7 +1362,8 @@ idle_calc_showing (gpointer data) should_show = NULL; should_hide = NULL; unplaced = NULL; - + displays = NULL; + tmp = copy; while (tmp != NULL) { @@ -1438,12 +1440,31 @@ idle_calc_showing (gpointer data) tmp = tmp->next; } - + + /* for all displays used in the queue, set a sentinel property on + * the root window so that we can ignore EnterNotify events that + * occur before the window maps occur. This avoids a race + * condition. */ + tmp = should_show; + while (tmp != NULL) + { + MetaWindow *window = tmp->data; + + if (g_slist_find (displays, window->display) == NULL) + { + displays = g_slist_prepend (displays, window->display); + meta_display_increment_focus_sentinel (window->display); + } + + tmp = tmp->next; + } + g_slist_free (copy); g_slist_free (unplaced); g_slist_free (should_show); g_slist_free (should_hide); + g_slist_free (displays); destroying_windows_disallowed -= 1; diff --git a/src/workspace.c b/src/workspace.c index 5f6476bae..56cbaa624 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -196,7 +196,8 @@ meta_workspace_queue_calc_showing (MetaWorkspace *workspace) } void -meta_workspace_activate (MetaWorkspace *workspace) +meta_workspace_activate_with_focus (MetaWorkspace *workspace, + MetaWindow *focus_this) { MetaWorkspace *old; @@ -218,8 +219,24 @@ meta_workspace_activate (MetaWorkspace *workspace) meta_workspace_queue_calc_showing (old); meta_workspace_queue_calc_showing (workspace); - meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n"); - meta_screen_focus_default_window (workspace->screen, NULL); + if (focus_this) + { + meta_window_focus (focus_this, + meta_display_get_current_time (focus_this->display)); + meta_window_raise (focus_this); + } + else + { + meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n"); + meta_screen_focus_default_window (workspace->screen, NULL); + } +} + +void +meta_workspace_activate (MetaWorkspace *workspace) +{ + meta_workspace_activate_with_focus (workspace, + NULL); } int diff --git a/src/workspace.h b/src/workspace.h index 1e1ba92f6..c6edc758d 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -58,7 +58,9 @@ void meta_workspace_relocate_windows (MetaWorkspace *workspace, /* don't confuse with meta_window_visible_on_workspace() */ gboolean meta_workspace_contains_window (MetaWorkspace *workspace, MetaWindow *window); -void meta_workspace_activate (MetaWorkspace *workspace); +void meta_workspace_activate_with_focus (MetaWorkspace *workspace, + MetaWindow *focus_this); +void meta_workspace_activate (MetaWorkspace *workspace); int meta_workspace_index (MetaWorkspace *workspace); GList* meta_workspace_list_windows (MetaWorkspace *workspace);