summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-07 18:25:51 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-07 18:25:51 +0000
commit445873cae45fd143a1f1fd936a578b576b6118ec (patch)
tree40fc63a337afcac36dfce98fabfdd184c26bddb7 /views
parenta3f3079c3fa68dc79831183af4aa7ef79854f2ec (diff)
downloadchromium_src-445873cae45fd143a1f1fd936a578b576b6118ec.zip
chromium_src-445873cae45fd143a1f1fd936a578b576b6118ec.tar.gz
chromium_src-445873cae45fd143a1f1fd936a578b576b6118ec.tar.bz2
Fixes two related focus bugs on views/gtk:
. Focus was inadvertently getting cleared when a window was shown because the focus-in event is received asynchronously. . In some situations we get multiple focus-out events in a row, this caused us to clear out who we thought would have focus. BUG=31140, 31130 TEST=see bugs Review URL: http://codereview.chromium.org/521045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35714 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/focus/focus_manager_unittest.cc3
-rw-r--r--views/widget/widget_gtk.cc19
-rw-r--r--views/widget/widget_gtk.h16
3 files changed, 35 insertions, 3 deletions
diff --git a/views/focus/focus_manager_unittest.cc b/views/focus/focus_manager_unittest.cc
index bab3cf1..548989a 100644
--- a/views/focus/focus_manager_unittest.cc
+++ b/views/focus/focus_manager_unittest.cc
@@ -839,6 +839,9 @@ TEST_F(FocusManagerTest, FocusNativeControls) {
// Test that when activating/deactivating the top window, the focus is stored/
// restored properly.
TEST_F(FocusManagerTest, FocusStoreRestore) {
+ // Simulate an activate, otherwise the deactivate isn't going to do anything.
+ SimulateActivateWindow();
+
NativeButton* button = new NativeButton(NULL, L"Press me");
View* view = new View();
view->SetFocusable(true);
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index e10bf60..ab88713 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -98,7 +98,9 @@ WidgetGtk::WidgetGtk(Type type)
drag_data_(NULL),
in_paint_now_(false),
is_active_(false),
- transient_to_parent_(false) {
+ transient_to_parent_(false),
+ got_initial_focus_in_(false),
+ has_focus_(false) {
static bool installed_message_loop_observer = false;
if (!installed_message_loop_observer) {
installed_message_loop_observer = true;
@@ -778,15 +780,26 @@ gboolean WidgetGtk::OnButtonRelease(GtkWidget* widget, GdkEventButton* event) {
}
gboolean WidgetGtk::OnFocusIn(GtkWidget* widget, GdkEventFocus* event) {
+ if (has_focus_)
+ return false; // This is the second focus-in event in a row, ignore it.
+ has_focus_ = true;
+
if (type_ == TYPE_CHILD)
return false;
- // The top-level window got focus, restore the last focused view.
- focus_manager_->RestoreFocusedView();
+ // See description of got_initial_focus_in_ for details on this.
+ if (!got_initial_focus_in_)
+ got_initial_focus_in_ = true;
+ else
+ focus_manager_->RestoreFocusedView();
return false;
}
gboolean WidgetGtk::OnFocusOut(GtkWidget* widget, GdkEventFocus* event) {
+ if (!has_focus_)
+ return false; // This is the second focus-out event in a row, ignore it.
+ has_focus_ = false;
+
if (type_ == TYPE_CHILD)
return false;
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
index 4efe515..9d73bf0 100644
--- a/views/widget/widget_gtk.h
+++ b/views/widget/widget_gtk.h
@@ -432,6 +432,22 @@ class WidgetGtk
// hasn't changed, we can end up getting stuck in a never ending loop.
gfx::Size size_;
+ // This is initially false and when the first focus-in event is received this
+ // is set to true and no additional processing is done. Subsequently when
+ // focus-in is received we do the normal focus manager processing.
+ //
+ // This behavior is necessitated by Gtk/X sending focus events
+ // asynchronously. The initial sequence for windows is typically: show,
+ // request focus on some widget. Because of async events on Gtk this becomes
+ // show, request focus, get focus in event which ends up clearing focus
+ // (first request to FocusManager::RestoreFocusedView ends up clearing focus).
+ bool got_initial_focus_in_;
+
+ // If true, we've received a focus-in event. If false we've received a
+ // focus-out event. We can get multiple focus-out events in a row, we use
+ // this to determine whether we should process the event.
+ bool has_focus_;
+
DISALLOW_COPY_AND_ASSIGN(WidgetGtk);
};