summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRob Adams <readams@src.gnome.org>2003-05-30 20:24:00 +0000
committerRob Adams <readams@src.gnome.org>2003-05-30 20:24:00 +0000
commit3edad8599c6f91ea86123baac08ece858bc27aa7 (patch)
tree66895895a9118dcd1c56d097f95e5b2fa987d1fa /src
parent903f3d7e6e8f528d7e18ede9d5abb6beaeb06821 (diff)
downloadmetacity-3edad8599c6f91ea86123baac08ece858bc27aa7.tar.gz
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. : ----------------------------------------------------------------------
Diffstat (limited to 'src')
-rw-r--r--src/display.c49
-rw-r--r--src/display.h11
-rw-r--r--src/keybindings.c2
-rw-r--r--src/window.c25
-rw-r--r--src/workspace.c23
-rw-r--r--src/workspace.h4
6 files changed, 105 insertions, 9 deletions
diff --git a/src/display.c b/src/display.c
index 523fa1c6..a9e3f30e 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 00956651..65f43b13 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 395b30b8..050733a7 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 326c188a..7b65e95e 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 5f6476ba..56cbaa62 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 1e1ba92f..c6edc758 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);