summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
Diffstat (limited to 'views')
-rw-r--r--views/controls/native/native_view_host_win.cc20
-rw-r--r--views/view.cc72
-rw-r--r--views/view.h29
-rw-r--r--views/view_unittest.cc139
-rw-r--r--views/widget/root_view.cc5
-rw-r--r--views/widget/root_view.h4
-rw-r--r--views/widget/widget.h6
-rw-r--r--views/widget/widget_gtk.cc36
-rw-r--r--views/widget/widget_win.cc32
-rw-r--r--views/window/dialog_client_view.cc54
-rw-r--r--views/window/dialog_client_view.h14
11 files changed, 380 insertions, 31 deletions
diff --git a/views/controls/native/native_view_host_win.cc b/views/controls/native/native_view_host_win.cc
index 4a8f357..75045ab 100644
--- a/views/controls/native/native_view_host_win.cc
+++ b/views/controls/native/native_view_host_win.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "views/controls/native/native_view_host.h"
#include "views/focus/focus_manager.h"
+#include "views/widget/root_view.h"
#include "views/widget/widget.h"
namespace views {
@@ -25,7 +26,6 @@ NativeViewHostWin::~NativeViewHostWin() {
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostWin, NativeViewHostWrapper implementation:
-
void NativeViewHostWin::NativeViewAttached() {
DCHECK(host_->native_view())
<< "Impossible detatched tab case; See crbug.com/6316";
@@ -37,10 +37,28 @@ void NativeViewHostWin::NativeViewAttached() {
// Need to set the HWND's parent before changing its size to avoid flashing.
SetParent(host_->native_view(), host_->GetWidget()->GetNativeView());
host_->Layout();
+ // Notify children that parent changed, so they could adjust the focus
+ std::vector<RootView*> root_views;
+ Widget::FindAllRootViews(host_->native_view(), &root_views);
+ for (std::vector<RootView*>::iterator it = root_views.begin();
+ it < root_views.end();
+ ++it) {
+ (*it)->NotifyNativeViewHierarchyChanged(true,
+ host_->GetWidget()->GetNativeView());
+ }
}
void NativeViewHostWin::NativeViewDetaching(bool destroyed) {
installed_clip_ = false;
+ // Notify children that parent is removed
+ std::vector<RootView*> root_views;
+ Widget::FindAllRootViews(host_->native_view(), &root_views);
+ for (std::vector<RootView*>::iterator it = root_views.begin();
+ it < root_views.end();
+ ++it) {
+ (*it)->NotifyNativeViewHierarchyChanged(false,
+ host_->GetWidget()->GetNativeView());
+ }
}
void NativeViewHostWin::AddedToWidget() {
diff --git a/views/view.cc b/views/view.cc
index 248622b..566de01 100644
--- a/views/view.cc
+++ b/views/view.cc
@@ -58,8 +58,10 @@ View::View()
is_parent_owned_(true),
notify_when_visible_bounds_in_root_changes_(false),
registered_for_visible_bounds_notification_(false),
+ accelerator_registration_delayed_(false),
next_focusable_view_(NULL),
previous_focusable_view_(NULL),
+ accelerator_focus_manager_(NULL),
registered_accelerator_count_(0),
context_menu_controller_(NULL),
#if defined(OS_WIN)
@@ -686,10 +688,16 @@ void View::ViewHierarchyChangedImpl(bool register_accelerators,
if (is_add) {
// If you get this registration, you are part of a subtree that has been
// added to the view hierarchy.
- RegisterPendingAccelerators();
+ if (GetFocusManager()) {
+ RegisterPendingAccelerators();
+ } else {
+ // Delay accelerator registration until visible as we do not have
+ // focus manager until then.
+ accelerator_registration_delayed_ = true;
+ }
} else {
if (child == this)
- UnregisterAccelerators();
+ UnregisterAccelerators(false);
}
}
@@ -705,6 +713,34 @@ void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
void View::VisibilityChanged(View* starting_from, bool is_visible) {
}
+void View::PropagateNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ RootView* root_view) {
+ for (int i = 0, count = GetChildViewCount(); i < count; ++i)
+ GetChildViewAt(i)->PropagateNativeViewHierarchyChanged(attached,
+ native_view,
+ root_view);
+ NativeViewHierarchyChanged(attached, native_view, root_view);
+}
+
+void View::NativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ RootView* root_view) {
+ FocusManager* focus_manager = GetFocusManager();
+ if (!accelerator_registration_delayed_ &&
+ accelerator_focus_manager_ &&
+ accelerator_focus_manager_ != focus_manager) {
+ UnregisterAccelerators(true);
+ accelerator_registration_delayed_ = true;
+ }
+ if (accelerator_registration_delayed_ && attached) {
+ if (focus_manager) {
+ RegisterPendingAccelerators();
+ accelerator_registration_delayed_ = false;
+ }
+ }
+}
+
void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
if (notify_when_visible_bounds_in_root_changes_ == value)
return;
@@ -988,18 +1024,16 @@ void View::RemoveAccelerator(const Accelerator& accelerator) {
return;
}
- FocusManager* focus_manager = GetFocusManager();
- if (focus_manager) {
- // We may not have a FocusManager if the window containing us is being
- // closed, in which case the FocusManager is being deleted so there is
- // nothing to unregister.
- focus_manager->UnregisterAccelerator(accelerator, this);
+ // If accelerator_focus_manager_ is NULL then we did not registered
+ // accelerators so there is nothing to unregister.
+ if (accelerator_focus_manager_) {
+ accelerator_focus_manager_->UnregisterAccelerator(accelerator, this);
}
}
void View::ResetAccelerators() {
if (accelerators_.get())
- UnregisterAccelerators();
+ UnregisterAccelerators(false);
}
void View::RegisterPendingAccelerators() {
@@ -1016,8 +1050,8 @@ void View::RegisterPendingAccelerators() {
return;
}
- FocusManager* focus_manager = GetFocusManager();
- if (!focus_manager) {
+ accelerator_focus_manager_ = GetFocusManager();
+ if (!accelerator_focus_manager_) {
// Some crash reports seem to show that we may get cases where we have no
// focus manager (see bug #1291225). This should never be the case, just
// making sure we don't crash.
@@ -1033,26 +1067,28 @@ void View::RegisterPendingAccelerators() {
std::vector<Accelerator>::const_iterator iter;
for (iter = accelerators_->begin() + registered_accelerator_count_;
iter != accelerators_->end(); ++iter) {
- focus_manager->RegisterAccelerator(*iter, this);
+ accelerator_focus_manager_->RegisterAccelerator(*iter, this);
}
registered_accelerator_count_ = accelerators_->size();
}
-void View::UnregisterAccelerators() {
+void View::UnregisterAccelerators(bool leave_data_intact) {
if (!accelerators_.get())
return;
RootView* root_view = GetRootView();
if (root_view) {
- FocusManager* focus_manager = GetFocusManager();
- if (focus_manager) {
+ if (accelerator_focus_manager_) {
// We may not have a FocusManager if the window containing us is being
// closed, in which case the FocusManager is being deleted so there is
// nothing to unregister.
- focus_manager->UnregisterAccelerators(this);
+ accelerator_focus_manager_->UnregisterAccelerators(this);
+ accelerator_focus_manager_ = NULL;
+ }
+ if (!leave_data_intact) {
+ accelerators_->clear();
+ accelerators_.reset();
}
- accelerators_->clear();
- accelerators_.reset();
registered_accelerator_count_ = 0;
}
}
diff --git a/views/view.h b/views/view.h
index 13a85ee..a9865d2 100644
--- a/views/view.h
+++ b/views/view.h
@@ -1019,6 +1019,18 @@ class View : public AcceleratorTarget {
// invoked for that view as well as all the children recursively.
virtual void VisibilityChanged(View* starting_from, bool is_visible);
+ // Called when the native view hierarchy changed.
+ // |attached| is true if that view has been attached to a new NativeView
+ // hierarchy, false if it has been detached.
+ // |native_view| is the NativeView this view was attached/detached from, and
+ // |root_view| is the root view associated with the NativeView.
+ // Views created without a native view parent don't have a focus manager.
+ // When this function is called they could do the processing that requires
+ // it - like registering accelerators, for example.
+ virtual void NativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ RootView* root_view);
+
// Called when the preferred size of a child view changed. This gives the
// parent an opportunity to do a fresh layout if that makes sense.
virtual void ChildPreferredSizeChanged(View* child) {}
@@ -1136,6 +1148,12 @@ class View : public AcceleratorTarget {
// Call VisibilityChanged() recursively for all children.
void PropagateVisibilityNotifications(View* from, bool is_visible);
+ // Propagates NativeViewHierarchyChanged() notification through all the
+ // children.
+ void PropagateNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ RootView* root_view);
+
// Takes care of registering/unregistering accelerators if
// |register_accelerators| true and calls ViewHierarchyChanged().
void ViewHierarchyChangedImpl(bool register_accelerators,
@@ -1184,7 +1202,9 @@ class View : public AcceleratorTarget {
void RegisterPendingAccelerators();
// Unregisters all the keyboard accelerators associated with this view.
- void UnregisterAccelerators();
+ // |leave_data_intact| if true does not remove data from accelerators_ array,
+ // so it could be re-registered with other focus manager
+ void UnregisterAccelerators(bool leave_data_intact);
// This View's bounds in the parent coordinate system.
gfx::Rect bounds_;
@@ -1219,6 +1239,10 @@ class View : public AcceleratorTarget {
// has been invoked.
bool registered_for_visible_bounds_notification_;
+ // true if when we were added to hierarchy we were without focus manager
+ // attempt addition when ancestor chain changed.
+ bool accelerator_registration_delayed_;
+
// List of descendants wanting notification when their visible bounds change.
scoped_ptr<ViewList> descendants_to_notify_;
@@ -1228,6 +1252,9 @@ class View : public AcceleratorTarget {
// Next view to be focused when the Shift-Tab key combination is pressed.
View* previous_focusable_view_;
+ // Focus manager accelerators registered on.
+ FocusManager* accelerator_focus_manager_;
+
// The list of accelerators. List elements in the range
// [0, registered_accelerator_count_) are already registered to FocusManager,
// and the rest are not yet.
diff --git a/views/view_unittest.cc b/views/view_unittest.cc
index 605d4838..1f4cfc1 100644
--- a/views/view_unittest.cc
+++ b/views/view_unittest.cc
@@ -16,6 +16,7 @@
#if defined(OS_WIN)
#include "views/controls/button/native_button_win.h"
#endif
+#include "views/controls/native/native_view_host.h"
#include "views/controls/scroll_view.h"
#include "views/controls/textfield/textfield.h"
#include "views/event.h"
@@ -59,6 +60,9 @@ class ViewTest : public testing::Test {
#endif
}
+ void RunPendingMessages() {
+ message_loop_.RunAllPending();
+ }
private:
MessageLoopForUI message_loop_;
};
@@ -1207,3 +1211,138 @@ TEST_F(ViewTest, ChangeVisibility) {
native->SetVisible(true);
}
*/
+
+////////////////////////////////////////////////////////////////////////////////
+// Native view hierachy
+////////////////////////////////////////////////////////////////////////////////
+class TestNativeViewHierarchy : public views::View {
+ public:
+ TestNativeViewHierarchy() {
+ }
+
+ virtual void NativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ RootView* root_view) {
+ NotificationInfo info;
+ info.attached = attached;
+ info.native_view = native_view;
+ info.root_view = root_view;
+ notifications_.push_back(info);
+ };
+ struct NotificationInfo {
+ bool attached;
+ gfx::NativeView native_view;
+ RootView* root_view;
+ };
+ static const size_t kTotalViews = 2;
+ std::vector<NotificationInfo> notifications_;
+};
+
+class TestChangeNativeViewHierarchy {
+ public:
+ explicit TestChangeNativeViewHierarchy(ViewTest *view_test) {
+ view_test_ = view_test;
+ native_host_ = new views::NativeViewHost();
+ host_ = view_test->CreateWidget();
+ host_->Init(NULL, gfx::Rect(0, 0, 500, 300));
+ host_->GetRootView()->AddChildView(native_host_);
+ for (size_t i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
+ windows_[i] = view_test->CreateWidget();
+ windows_[i]->Init(host_->GetNativeView(), gfx::Rect(0, 0, 500, 300));
+ root_views_[i] = windows_[i]->GetRootView();
+ test_views_[i] = new TestNativeViewHierarchy;
+ root_views_[i]->AddChildView(test_views_[i]);
+ }
+ }
+
+ ~TestChangeNativeViewHierarchy() {
+ for (size_t i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
+ windows_[i]->Close();
+ }
+ host_->Close();
+ // Will close and self-delete widgets - no need to manually delete them.
+ view_test_->RunPendingMessages();
+ }
+
+ void CheckEnumeratingRootViews() {
+ std::vector<RootView*> enumerated_root_views;
+#if defined(OS_WIN)
+ views::Widget::FindAllRootViews(host_->GetNativeView(),
+ &enumerated_root_views);
+#else
+ // host_->GetNativeView() returns gfx::NativeView which is GtkWidget on
+ // systems other than Windows and views::Widget::FindAllRootViews()
+ // requires GtkWindow.
+ if (host_->GetWindow()) {
+ views::Widget::FindAllRootViews(host_->GetWindow()->GetNativeWindow(),
+ &enumerated_root_views);
+ } else {
+ return;
+ }
+#endif
+ EXPECT_EQ(TestNativeViewHierarchy::kTotalViews + 1,
+ enumerated_root_views.size());
+ // Unfortunately there is no guarantee the sequence of views here so always
+ // go through all of them.
+ for (std::vector<RootView*>::iterator i = enumerated_root_views.begin();
+ i != enumerated_root_views.end(); ++i) {
+ if (host_->GetRootView() == *i)
+ continue;
+ size_t j;
+ for (j = 0; j < TestNativeViewHierarchy::kTotalViews; ++j)
+ if (root_views_[j] == *i)
+ break;
+ // EXPECT_LT/GT/GE() fails to compile with class-defined constants
+ // with gcc, with error
+ // "error: undefined reference to 'TestNativeViewHierarchy::kTotalViews'"
+ // so I forced to use EXPECT_TRUE() instead.
+ EXPECT_TRUE(TestNativeViewHierarchy::kTotalViews > j);
+ }
+ }
+
+ void CheckChangingHierarhy() {
+ size_t i;
+ for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
+ // TODO(georgey): use actual hierarchy changes to send notifications.
+ root_views_[i]->NotifyNativeViewHierarchyChanged(false,
+ host_->GetNativeView());
+ root_views_[i]->NotifyNativeViewHierarchyChanged(true,
+ host_->GetNativeView());
+ }
+ for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
+ ASSERT_EQ(static_cast<size_t>(2), test_views_[i]->notifications_.size());
+ EXPECT_FALSE(test_views_[i]->notifications_[0].attached);
+ EXPECT_EQ(host_->GetNativeView(),
+ test_views_[i]->notifications_[0].native_view);
+ EXPECT_EQ(root_views_[i], test_views_[i]->notifications_[0].root_view);
+ EXPECT_TRUE(test_views_[i]->notifications_[1].attached);
+ EXPECT_EQ(host_->GetNativeView(),
+ test_views_[i]->notifications_[1].native_view);
+ EXPECT_EQ(root_views_[i], test_views_[i]->notifications_[1].root_view);
+ }
+ }
+
+ views::NativeViewHost* native_host_;
+ views::Widget* host_;
+ views::Widget* windows_[TestNativeViewHierarchy::kTotalViews];
+ views::RootView* root_views_[TestNativeViewHierarchy::kTotalViews];
+ TestNativeViewHierarchy* test_views_[TestNativeViewHierarchy::kTotalViews];
+ ViewTest* view_test_;
+};
+
+TEST_F(ViewTest, ChangeNativeViewHierarchyFindRoots) {
+ // TODO(georgey): Fix the test for Linux
+#if defined(OS_WIN)
+ TestChangeNativeViewHierarchy test(this);
+ test.CheckEnumeratingRootViews();
+#endif
+}
+
+TEST_F(ViewTest, ChangeNativeViewHierarchyChangeHierarchy) {
+ // TODO(georgey): Fix the test for Linux
+#if defined(OS_WIN)
+ TestChangeNativeViewHierarchy test(this);
+ test.CheckChangingHierarhy();
+#endif
+}
+
diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc
index 5d2b6e4..862d000 100644
--- a/views/widget/root_view.cc
+++ b/views/widget/root_view.cc
@@ -764,6 +764,11 @@ void RootView::SetFocusTraversableParentView(View* view) {
focus_traversable_parent_view_ = view;
}
+void RootView::NotifyNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view) {
+ PropagateNativeViewHierarchyChanged(attached, native_view, this);
+}
+
// static
View* RootView::FindSelectedViewForGroup(View* view) {
if (view->IsGroupFocusTraversable() ||
diff --git a/views/widget/root_view.h b/views/widget/root_view.h
index dbb480f..d175c63 100644
--- a/views/widget/root_view.h
+++ b/views/widget/root_view.h
@@ -152,6 +152,10 @@ class RootView : public View,
// Used to set the View parent after the view has been created.
virtual void SetFocusTraversableParentView(View* view);
+ // Called when parent of the host changed.
+ void NotifyNativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view);
+
// Returns the name of this class: views/RootView
virtual std::string GetClassName() const;
diff --git a/views/widget/widget.h b/views/widget/widget.h
index 8de4b6c..fa8111e 100644
--- a/views/widget/widget.h
+++ b/views/widget/widget.h
@@ -5,6 +5,7 @@
#ifndef VIEWS_WIDGET_WIDGET_H_
#define VIEWS_WIDGET_WIDGET_H_
+#include <vector>
#include "app/gfx/native_widget_types.h"
class ThemeProvider;
@@ -71,6 +72,11 @@ class Widget {
// one is found. If a root view isn't found, null is returned.
static RootView* FindRootView(gfx::NativeWindow native_window);
+ // Returns list of all root views for the native window and its
+ // children.
+ static void FindAllRootViews(gfx::NativeWindow native_window,
+ std::vector<RootView*>* root_views);
+
// Retrieve the Widget corresponding to the specified native_view, or NULL
// if there is no such Widget.
static Widget* GetWidgetFromNativeView(gfx::NativeView native_view);
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index a2d699f..e10bf60 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -1302,6 +1302,42 @@ RootView* Widget::FindRootView(GtkWindow* window) {
return root_view;
}
+static void AllRootViewsLocatorCallback(GtkWidget* widget,
+ gpointer root_view_p) {
+ std::set<RootView*>* root_views_set =
+ reinterpret_cast<std::set<RootView*>*>(root_view_p);
+ RootView *root_view = WidgetGtk::GetRootViewForWidget(widget);
+ if (!root_view && GTK_IS_CONTAINER(widget)) {
+ // gtk_container_foreach only iterates over children, not all descendants,
+ // so we have to recurse here to get all descendants.
+ gtk_container_foreach(GTK_CONTAINER(widget), AllRootViewsLocatorCallback,
+ root_view_p);
+ } else {
+ if (root_view)
+ root_views_set->insert(root_view);
+ }
+}
+
+// static
+void Widget::FindAllRootViews(GtkWindow* window,
+ std::vector<RootView*>* root_views) {
+ RootView* root_view = WidgetGtk::GetRootViewForWidget(GTK_WIDGET(window));
+ if (root_view)
+ root_views->push_back(root_view);
+
+ std::set<RootView*> root_views_set;
+
+ // Enumerate all children and check if they have a RootView.
+ gtk_container_foreach(GTK_CONTAINER(window), AllRootViewsLocatorCallback,
+ reinterpret_cast<gpointer>(&root_views_set));
+ root_views->clear();
+ root_views->reserve(root_views_set.size());
+ for (std::set<RootView*>::iterator it = root_views_set.begin();
+ it != root_views_set.end();
+ ++it)
+ root_views->push_back(*it);
+}
+
// static
Widget* Widget::GetWidgetFromNativeView(gfx::NativeView native_view) {
gpointer raw_widget = g_object_get_data(G_OBJECT(native_view), kWidgetKey);
diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc
index 76f58e4..6f75506 100644
--- a/views/widget/widget_win.cc
+++ b/views/widget/widget_win.cc
@@ -1205,6 +1205,38 @@ RootView* Widget::FindRootView(HWND hwnd) {
return root_view;
}
+// Enumerate child windows as they could have RootView distinct from
+// the HWND's root view.
+BOOL CALLBACK EnumAllRootViewsChildProc(HWND hwnd, LPARAM l_param) {
+ RootView* root_view =
+ reinterpret_cast<RootView*>(GetProp(hwnd, kRootViewWindowProperty));
+ if (root_view) {
+ std::set<RootView*>* root_views_set =
+ reinterpret_cast<std::set<RootView*>*>(l_param);
+ root_views_set->insert(root_view);
+ }
+ return TRUE; // Keep enumerating.
+}
+
+void Widget::FindAllRootViews(HWND window,
+ std::vector<RootView*>* root_views) {
+ RootView* root_view =
+ reinterpret_cast<RootView*>(GetProp(window, kRootViewWindowProperty));
+ std::set<RootView*> root_views_set;
+ if (root_view)
+ root_views_set.insert(root_view);
+ // Enumerate all children and check if they have a RootView.
+ EnumChildWindows(window, EnumAllRootViewsChildProc,
+ reinterpret_cast<LPARAM>(&root_views_set));
+ root_views->clear();
+ root_views->reserve(root_views_set.size());
+ for (std::set<RootView*>::iterator it = root_views_set.begin();
+ it != root_views_set.end();
+ ++it)
+ root_views->push_back(*it);
+}
+
+
////////////////////////////////////////////////////////////////////////////////
// Widget, public:
diff --git a/views/window/dialog_client_view.cc b/views/window/dialog_client_view.cc
index 64c4677..b25c6bc 100644
--- a/views/window/dialog_client_view.cc
+++ b/views/window/dialog_client_view.cc
@@ -110,7 +110,9 @@ DialogClientView::DialogClientView(Window* owner, View* contents_view)
cancel_button_(NULL),
default_button_(NULL),
extra_view_(NULL),
- accepted_(false) {
+ accepted_(false),
+ listening_to_focus_(false),
+ saved_focus_manager_(NULL) {
InitClass();
}
@@ -236,6 +238,17 @@ void DialogClientView::CancelWindow() {
}
///////////////////////////////////////////////////////////////////////////////
+// DialogClientView, View overrides:
+
+void DialogClientView::NativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ RootView* root_view) {
+ if (attached) {
+ UpdateFocusListener();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
// DialogClientView, ClientView overrides:
bool DialogClientView::CanClose() const {
@@ -251,10 +264,11 @@ bool DialogClientView::CanClose() const {
}
void DialogClientView::WindowClosing() {
- FocusManager* focus_manager = GetFocusManager();
- DCHECK(focus_manager);
- if (focus_manager)
- focus_manager->RemoveFocusChangeListener(this);
+ if (listening_to_focus_) {
+ DCHECK(saved_focus_manager_);
+ if (saved_focus_manager_)
+ saved_focus_manager_->RemoveFocusChangeListener(this);
+ }
ClientView::WindowClosing();
}
@@ -302,12 +316,7 @@ void DialogClientView::ViewHierarchyChanged(bool is_add, View* parent,
ShowDialogButtons();
ClientView::ViewHierarchyChanged(is_add, parent, child);
- FocusManager* focus_manager = GetFocusManager();
- // Listen for focus change events so we can update the default button.
- DCHECK(focus_manager); // bug #1291225: crash reports seem to indicate it
- // can be NULL.
- if (focus_manager)
- focus_manager->AddFocusChangeListener(this);
+ UpdateFocusListener();
// The "extra view" must be created and installed after the contents view
// has been inserted into the view hierarchy.
@@ -503,4 +512,27 @@ void DialogClientView::Close() {
GetDialogDelegate()->OnClose();
}
+void DialogClientView::UpdateFocusListener() {
+ FocusManager* focus_manager = GetFocusManager();
+ // Listen for focus change events so we can update the default button.
+ // focus_manager can be NULL when the dialog is created on un-shown view.
+ // We start listening for focus changes when the page is visible.
+ // Focus manager could also change if window host changes a parent.
+ if (listening_to_focus_) {
+ if (saved_focus_manager_ == focus_manager)
+ return;
+ DCHECK(saved_focus_manager_);
+ if (saved_focus_manager_)
+ saved_focus_manager_->RemoveFocusChangeListener(this);
+ listening_to_focus_ = false;
+ }
+ saved_focus_manager_ = focus_manager;
+ // Listen for focus change events so we can update the default button.
+ if (focus_manager) {
+ focus_manager->AddFocusChangeListener(this);
+ listening_to_focus_ = true;
+ }
+}
+
+
} // namespace views
diff --git a/views/window/dialog_client_view.h b/views/window/dialog_client_view.h
index 1c3d19f..d7a5fb2 100644
--- a/views/window/dialog_client_view.h
+++ b/views/window/dialog_client_view.h
@@ -50,6 +50,11 @@ class DialogClientView : public ClientView,
NativeButton* ok_button() const { return ok_button_; }
NativeButton* cancel_button() const { return cancel_button_; }
+ // Overridden from View:
+ virtual void NativeViewHierarchyChanged(bool attached,
+ gfx::NativeView native_view,
+ RootView* root_view);
+
// Overridden from ClientView:
virtual bool CanClose() const;
virtual void WindowClosing();
@@ -98,6 +103,9 @@ class DialogClientView : public ClientView,
// Closes the window.
void Close();
+ // Updates focus listener.
+ void UpdateFocusListener();
+
// The dialog buttons.
NativeButton* ok_button_;
NativeButton* cancel_button_;
@@ -114,6 +122,12 @@ class DialogClientView : public ClientView,
// True if the window was Accepted by the user using the OK button.
bool accepted_;
+ // true if focus listener is added.
+ bool listening_to_focus_;
+
+ // When ancestor gets changed focus manager gets changed as well.
+ FocusManager* saved_focus_manager_;
+
// Static resource initialization
static void InitClass();
static gfx::Font* dialog_button_font_;