CVS2003-05-29 Rob Adams <robadams@ucla.edu>

CVS2003-05-29  Rob Adams  <robadams@ucla.edu>

	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.

: ----------------------------------------------------------------------
This commit is contained in:
Rob Adams 2003-05-30 20:24:00 +00:00
parent 903f3d7e6e
commit 3edad8599c
7 changed files with 140 additions and 9 deletions

View File

@ -1,3 +1,38 @@
2003-05-29 Rob Adams <robadams@ucla.edu>
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 <hp@redhat.com>
* src/theme-parser.c (meta_theme_load): s/int/gsize/ for

View File

@ -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);
}

View File

@ -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

View File

@ -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
{

View File

@ -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,6 +1362,7 @@ idle_calc_showing (gpointer data)
should_show = NULL;
should_hide = NULL;
unplaced = NULL;
displays = NULL;
tmp = copy;
while (tmp != NULL)
@ -1439,11 +1441,30 @@ 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;

View File

@ -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

View File

@ -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);