summaryrefslogtreecommitdiffstats
path: root/views/focus/focus_manager.cc
diff options
context:
space:
mode:
authortwiz@chromium.org <twiz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-10 22:46:47 +0000
committertwiz@chromium.org <twiz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-10 22:46:47 +0000
commit2db27be7dbb16f02587b90f150a843d8ad234563 (patch)
tree9bfd5b6b2ff4637a69744ce35249361d1f3ea353 /views/focus/focus_manager.cc
parente1ce144bd04336891bb12b967095e938ed5f1bbb (diff)
downloadchromium_src-2db27be7dbb16f02587b90f150a843d8ad234563.zip
chromium_src-2db27be7dbb16f02587b90f150a843d8ad234563.tar.gz
chromium_src-2db27be7dbb16f02587b90f150a843d8ad234563.tar.bz2
CL implementing focus-dismissal of the chrome.experimental.popup set of extension APIs.
Specifically, these changes cause a displayed pop-up to be dismissed when the focus shifts away from both the pop-up view, and the extension-view that launched the pop-up.I had to do a lot of investigating and trial-and-error to converge to the solution present here. I was hoping to be able to piggy-back on the existing FocusManager's various listener routines, but because the pop-up is hosted in a BubbleWidget, which is a separate top-level window with its own focus manager, I could not rely on a given focus manager to take care of the focus change notifications. To get around the above issue, I added a new type of focus listener that can listen on native-window focus change events. I added invocations to this listener throughout the Widget classes in the system so that registered listeners will be notified on focus change. I found some of the focus change events problematic, as the system will arbitrarily reassign the focus to the main browser window when shifting activation between chrome windows. (SeefocusManagerWin::ClearNativeFocus). To prevent this focus bounce from confusing focus listeners, I added a means to suppress notification of focus change during these operations. I added GTK and Mac stubs for the new widget functions that will assert when called. GTK and Cocoa development is not my expertise, so I thought // TODO(port) would be wiser.I'm uncertain of the best means to unit-test these changes. Direction in this regard would be appreciated. BUG=None TEST=None Review URL: http://codereview.chromium.org/552167 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38685 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/focus/focus_manager.cc')
-rw-r--r--views/focus/focus_manager.cc50
1 files changed, 49 insertions, 1 deletions
diff --git a/views/focus/focus_manager.cc b/views/focus/focus_manager.cc
index 9942854..f637e09 100644
--- a/views/focus/focus_manager.cc
+++ b/views/focus/focus_manager.cc
@@ -22,6 +22,46 @@
namespace views {
+// FocusManager::WidgetFocusManager ---------------------------------
+
+void FocusManager::WidgetFocusManager::AddFocusChangeListener(
+ WidgetFocusChangeListener* listener) {
+ DCHECK(std::find(focus_change_listeners_.begin(),
+ focus_change_listeners_.end(), listener) ==
+ focus_change_listeners_.end()) <<
+ "Adding a WidgetFocusChangeListener twice.";
+ focus_change_listeners_.push_back(listener);
+}
+
+void FocusManager::WidgetFocusManager::RemoveFocusChangeListener(
+ WidgetFocusChangeListener* listener) {
+ WidgetFocusChangeListenerList::iterator iter(std::find(
+ focus_change_listeners_.begin(),
+ focus_change_listeners_.end(),
+ listener));
+ if (iter != focus_change_listeners_.end()) {
+ focus_change_listeners_.erase(iter);
+ } else {
+ NOTREACHED() <<
+ "Attempting to remove an unregistered WidgetFocusChangeListener.";
+ }
+}
+
+void FocusManager::WidgetFocusManager::OnWidgetFocusEvent(
+ gfx::NativeView focused_before,
+ gfx::NativeView focused_now) {
+ if (!enabled_)
+ return;
+
+ // Perform a safe iteration over the focus listeners, as the array of
+ // may change during notification.
+ WidgetFocusChangeListenerList local_listeners(focus_change_listeners_);
+ WidgetFocusChangeListenerList::iterator iter(local_listeners.begin());
+ for (;iter != local_listeners.end(); ++iter) {
+ (*iter)->NativeFocusWillChange(focused_before, focused_now);
+ }
+}
+
// FocusManager -----------------------------------------------------
FocusManager::FocusManager(Widget* widget)
@@ -277,7 +317,15 @@ void FocusManager::StoreFocusedView() {
view_storage->StoreView(stored_focused_view_storage_id_, focused_view_);
View* v = focused_view_;
- ClearFocus();
+
+ {
+ // Temporarily disable notification. ClearFocus() will set the focus to the
+ // main browser window. This extra focus bounce which happens during
+ // deactivation can confuse registered WidgetFocusListeners, as the focus
+ // is not changing due to a user-initiated event.
+ AutoNativeNotificationDisabler local_notification_disabler;
+ ClearFocus();
+ }
if (v)
v->SchedulePaint(); // Remove focus border.