summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);
};