diff options
author | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-22 21:47:30 +0000 |
---|---|---|
committer | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-22 21:47:30 +0000 |
commit | 28f57b316a5fc14cf36026af2438f0a68aa0922c (patch) | |
tree | 8e080f45b975727f19c738c6e9cb4c267404e3cb /ui | |
parent | c33dc2e2ec14c521ad0884c39d668d3181497735 (diff) | |
download | chromium_src-28f57b316a5fc14cf36026af2438f0a68aa0922c.zip chromium_src-28f57b316a5fc14cf36026af2438f0a68aa0922c.tar.gz chromium_src-28f57b316a5fc14cf36026af2438f0a68aa0922c.tar.bz2 |
linux_aura: Redo how activation is handled.
This is an almost complete overhaul of how activation works.
oshima@ recently changed ActivationController/FocusManager so that there was a single one per desktop instead of per RootWindow. Because of this, our code that listens for activation changes from X11 is wrong, and has been moved to its own class which also owns the singleton ActivationController.
DesktopActivationController had a wrong model. It should be activating the toplevel window like BrowserFrameAura, even across RootWindows. This has been fixed.
Also moved the utility class ScopedObserver to base/.
TODO: This fixes all activation problems I've seen except for trying to cause a bubble to show when the chrome window is deactivated while a non-chrome window is active.
BUG=130798,133055,133089
TEST=none
Review URL: https://chromiumcodereview.appspot.com/10631008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@143716 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/aura/desktop/desktop_activation_client.cc | 53 | ||||
-rw-r--r-- | ui/aura/desktop/desktop_activation_client.h | 28 | ||||
-rw-r--r-- | ui/aura/env_observer.h | 3 | ||||
-rw-r--r-- | ui/views/views.gyp | 2 | ||||
-rw-r--r-- | ui/views/widget/desktop_native_widget_helper_aura.cc | 18 | ||||
-rw-r--r-- | ui/views/widget/native_widget_aura.cc | 3 | ||||
-rw-r--r-- | ui/views/widget/x11_desktop_handler.cc | 104 | ||||
-rw-r--r-- | ui/views/widget/x11_desktop_handler.h | 72 | ||||
-rw-r--r-- | ui/views/widget/x11_window_event_filter.cc | 53 | ||||
-rw-r--r-- | ui/views/widget/x11_window_event_filter.h | 9 |
10 files changed, 254 insertions, 91 deletions
diff --git a/ui/aura/desktop/desktop_activation_client.cc b/ui/aura/desktop/desktop_activation_client.cc index 7b2e08e..d948203 100644 --- a/ui/aura/desktop/desktop_activation_client.cc +++ b/ui/aura/desktop/desktop_activation_client.cc @@ -5,8 +5,10 @@ #include "ui/aura/desktop/desktop_activation_client.h" #include "base/auto_reset.h" +#include "base/compiler_specific.h" #include "ui/aura/client/activation_delegate.h" #include "ui/aura/client/activation_change_observer.h" +#include "ui/aura/env.h" #include "ui/aura/focus_manager.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" @@ -24,21 +26,18 @@ bool IsChildOfRootWindow(aura::Window* window) { namespace aura { -DesktopActivationClient::DesktopActivationClient(RootWindow* root_window) - : root_window_(root_window), +DesktopActivationClient::DesktopActivationClient(FocusManager* focus_manager) + : focus_manager_(focus_manager), current_active_(NULL), - updating_activation_(false) { - root_window_->GetFocusManager()->AddObserver(this); + updating_activation_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(observer_manager_(this)) { + aura::Env::GetInstance()->AddObserver(this); + focus_manager->AddObserver(this); } DesktopActivationClient::~DesktopActivationClient() { - root_window_->GetFocusManager()->RemoveObserver(this); -} - - -void DesktopActivationClient::SetActivateWindowInResponseToSystem( - Window* window) { - current_active_ = window; + focus_manager_->RemoveObserver(this); + aura::Env::GetInstance()->RemoveObserver(this); } void DesktopActivationClient::AddObserver( @@ -71,16 +70,18 @@ void DesktopActivationClient::ActivateWindow(Window* window) { window->GetFocusManager()->SetFocusedWindow(window, NULL); } - // Send a deactivation to the old window - if (current_active_ && client::GetActivationDelegate(current_active_)) - client::GetActivationDelegate(current_active_)->OnLostActive(); - aura::Window* old_active = current_active_; current_active_ = window; FOR_EACH_OBSERVER(client::ActivationChangeObserver, observers_, OnWindowActivated(window, old_active)); + // Invoke OnLostActive after we've changed the active window. That way if the + // delegate queries for active state it doesn't think the window is still + // active. + if (old_active && client::GetActivationDelegate(old_active)) + client::GetActivationDelegate(old_active)->OnLostActive(); + // Send an activation event to the new window if (window && client::GetActivationDelegate(window)) client::GetActivationDelegate(window)->OnActivated(); @@ -100,6 +101,23 @@ bool DesktopActivationClient::OnWillFocusWindow(Window* window, return CanActivateWindow(GetActivatableWindow(window)); } +void DesktopActivationClient::OnWindowDestroying(aura::Window* window) { + if (current_active_ == window) { + current_active_ = NULL; + FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver, + observers_, + OnWindowActivated(NULL, window)); + + // ash::ActivationController will also activate the next window here; we + // don't do this because that's the desktop environment's job. + } + observer_manager_.Remove(window); +} + +void DesktopActivationClient::OnWindowInitialized(aura::Window* window) { + observer_manager_.Add(window); +} + void DesktopActivationClient::OnWindowFocused(aura::Window* window) { ActivateWindow(GetActivatableWindow(window)); } @@ -117,8 +135,11 @@ aura::Window* DesktopActivationClient::GetActivatableWindow( aura::Window* parent = window->parent(); aura::Window* child = window; while (parent) { - if (CanActivateWindow(child)) + if (CanActivateWindow(child)) { + if (child->transient_parent()) + child = GetActivatableWindow(child->transient_parent()); return child; + } // If |child| isn't activatable, but has transient parent, trace // that path instead. if (child->transient_parent()) diff --git a/ui/aura/desktop/desktop_activation_client.h b/ui/aura/desktop/desktop_activation_client.h index a7c620a..884ff45 100644 --- a/ui/aura/desktop/desktop_activation_client.h +++ b/ui/aura/desktop/desktop_activation_client.h @@ -8,13 +8,16 @@ #include "base/basictypes.h" #include "base/observer_list.h" +#include "base/scoped_observer.h" #include "ui/aura/aura_export.h" #include "ui/aura/client/activation_client.h" +#include "ui/aura/env_observer.h" #include "ui/aura/focus_change_observer.h" #include "ui/aura/root_window_observer.h" +#include "ui/aura/window_observer.h" namespace aura { -class RootWindow; +class FocusManager; namespace client { class ActivationChangeObserver; } @@ -23,16 +26,13 @@ class ActivationChangeObserver; // RootWindow. Used only on the Desktop where there can be multiple RootWindow // objects. class AURA_EXPORT DesktopActivationClient : public client::ActivationClient, + public WindowObserver, + public EnvObserver, public FocusChangeObserver { public: - explicit DesktopActivationClient(RootWindow* root_window); + explicit DesktopActivationClient(FocusManager* focus_manager); virtual ~DesktopActivationClient(); - // Changes |current_active_| without doing normal activation change. This - // should only be used to respond to changes that come from the native - // system. - void SetActivateWindowInResponseToSystem(Window* window); - // ActivationClient: virtual void AddObserver(client::ActivationChangeObserver* observer) OVERRIDE; virtual void RemoveObserver( @@ -43,7 +43,13 @@ class AURA_EXPORT DesktopActivationClient : public client::ActivationClient, virtual bool OnWillFocusWindow(Window* window, const Event* event) OVERRIDE; virtual bool CanActivateWindow(Window* window) const OVERRIDE; - // FocusChangeObserver: + // Overridden from aura::WindowObserver: + virtual void OnWindowDestroying(aura::Window* window) OVERRIDE; + + // Overridden from aura::EnvObserver: + virtual void OnWindowInitialized(aura::Window* window) OVERRIDE; + + // Overridden from aura::FocusChangeObserver: virtual void OnWindowFocused(aura::Window* window) OVERRIDE; protected: @@ -51,8 +57,8 @@ class AURA_EXPORT DesktopActivationClient : public client::ActivationClient, // try to activate |window|. aura::Window* GetActivatableWindow(aura::Window* window); - // The root window that we handle. - RootWindow* root_window_; + // The focus manager that we collaborate with. + FocusManager* focus_manager_; // The current active window. Window* current_active_; @@ -63,6 +69,8 @@ class AURA_EXPORT DesktopActivationClient : public client::ActivationClient, ObserverList<client::ActivationChangeObserver> observers_; + ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_; + DISALLOW_COPY_AND_ASSIGN(DesktopActivationClient); }; diff --git a/ui/aura/env_observer.h b/ui/aura/env_observer.h index 351f14b..cac4e3f 100644 --- a/ui/aura/env_observer.h +++ b/ui/aura/env_observer.h @@ -17,6 +17,9 @@ class AURA_EXPORT EnvObserver { // Called when |window| has been initialized. virtual void OnWindowInitialized(Window* window) = 0; + // Called right before Env is destroyed. + virtual void OnWillDestroyEnv() {} + protected: virtual ~EnvObserver() {} }; diff --git a/ui/views/views.gyp b/ui/views/views.gyp index d21b64e..6af8739 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -348,6 +348,8 @@ 'widget/widget_hwnd_utils.h', 'widget/widget_message_filter.cc', 'widget/widget_message_filter.h', + 'widget/x11_desktop_handler.cc', + 'widget/x11_desktop_handler.h', 'widget/x11_window_event_filter.cc', 'widget/x11_window_event_filter.h', 'window/client_view.cc', diff --git a/ui/views/widget/desktop_native_widget_helper_aura.cc b/ui/views/widget/desktop_native_widget_helper_aura.cc index 5272acb..e256eb5 100644 --- a/ui/views/widget/desktop_native_widget_helper_aura.cc +++ b/ui/views/widget/desktop_native_widget_helper_aura.cc @@ -21,6 +21,7 @@ #include "ui/base/win/hwnd_subclass.h" #include "ui/views/widget/widget_message_filter.h" #elif defined(USE_X11) +#include "ui/views/widget/x11_desktop_handler.h" #include "ui/views/widget/x11_window_event_filter.h" #endif @@ -126,10 +127,22 @@ void DesktopNativeWidgetHelperAura::PreInitialize( // TODO(erg): Implement aura::CursorManager::Delegate to control // cursor's shape and visibility. + aura::FocusManager* focus_manager = NULL; + aura::DesktopActivationClient* activation_client = NULL; +#if defined(USE_X11) + focus_manager = X11DesktopHandler::get()->get_focus_manager(); + activation_client = X11DesktopHandler::get()->get_activation_client(); +#else + // TODO(ben): This is almost certainly wrong; I suspect that the windows + // build will need a singleton like above. + focus_manager = new aura::FocusManager; + activation_client = new aura::DesktopActivationClient(focus_manager); +#endif + root_window_.reset(new aura::RootWindow(bounds)); root_window_->SetProperty(kViewsWindowForRootWindow, window); root_window_->Init(); - root_window_->set_focus_manager(new aura::FocusManager); + root_window_->set_focus_manager(focus_manager); // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow. root_window_event_filter_ = new aura::shared::CompoundEventFilter; @@ -143,9 +156,6 @@ void DesktopNativeWidgetHelperAura::PreInitialize( capture_client_.reset( new aura::shared::RootWindowCaptureClient(root_window_.get())); - aura::DesktopActivationClient* activation_client = - new aura::DesktopActivationClient(root_window_.get()); - #if defined(USE_X11) x11_window_event_filter_.reset( new X11WindowEventFilter(root_window_.get(), activation_client, widget_)); diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 76761ec..3553512 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -188,6 +188,9 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) { delegate_->OnNativeWidgetCreated(); if (desktop_helper_.get() && desktop_helper_->GetRootWindow()) { + if (!params.child && params.GetParent()) + params.GetParent()->AddTransientChild(window_); + window_->SetParent(desktop_helper_->GetRootWindow()); } else if (params.child) { window_->SetParent(params.GetParent()); diff --git a/ui/views/widget/x11_desktop_handler.cc b/ui/views/widget/x11_desktop_handler.cc new file mode 100644 index 0000000..06b580b --- /dev/null +++ b/ui/views/widget/x11_desktop_handler.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/widget/x11_desktop_handler.h" + +#include "ui/views/widget/desktop_native_widget_helper_aura.h" +#include "ui/aura/desktop/desktop_activation_client.h" +#include "ui/aura/dispatcher_linux.h" +#include "ui/aura/env.h" +#include "ui/aura/focus_manager.h" +#include "ui/aura/root_window.h" +#include "ui/base/x/x11_util.h" + +namespace { + +const char* kAtomsToCache[] = { + "_NET_ACTIVE_WINDOW", + NULL +}; + +// Our global instance. Deleted when our Env() is deleted. +views::X11DesktopHandler* g_handler = NULL; + +} // namespace + +namespace views { + +// static +X11DesktopHandler* X11DesktopHandler::get() { + if (!g_handler) + g_handler = new X11DesktopHandler; + + return g_handler; +} + +X11DesktopHandler::X11DesktopHandler() + : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()), + x_root_window_(DefaultRootWindow(xdisplay_)), + atom_cache_(xdisplay_, kAtomsToCache), + focus_manager_(new aura::FocusManager), + desktop_activation_client_( + new aura::DesktopActivationClient(focus_manager_.get())) { + static_cast<aura::DispatcherLinux*>( + aura::Env::GetInstance()->GetDispatcher())-> + AddDispatcherForRootWindow(this); + aura::Env::GetInstance()->AddObserver(this); + + XWindowAttributes attr; + XGetWindowAttributes(xdisplay_, x_root_window_, &attr); + XSelectInput(xdisplay_, x_root_window_, + attr.your_event_mask | PropertyChangeMask | + StructureNotifyMask | SubstructureNotifyMask); +} + +X11DesktopHandler::~X11DesktopHandler() { + aura::Env::GetInstance()->RemoveObserver(this); + static_cast<aura::DispatcherLinux*>( + aura::Env::GetInstance()->GetDispatcher())-> + RemoveDispatcherForRootWindow(this); +} + +bool X11DesktopHandler::Dispatch(const base::NativeEvent& event) { + // Check for a change to the active window. + switch (event->type) { + case PropertyNotify: { + ::Atom active_window = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"); + + if (event->xproperty.window == x_root_window_ && + event->xproperty.atom == active_window) { + int window; + if (ui::GetIntProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window) && + window) { + OnActiveWindowChanged(static_cast< ::Window>(window)); + } + } + break; + } + } + + return false; +} + +void X11DesktopHandler::OnWindowInitialized(aura::Window* window) { +} + +void X11DesktopHandler::OnWillDestroyEnv() { + g_handler = NULL; + delete this; +} + +// This code should live elsewhere and should only trigger if a non-RootWindow +// has been selected. +void X11DesktopHandler::OnActiveWindowChanged(::Window xid) { + aura::RootWindow* root_window = + aura::RootWindow::GetForAcceleratedWidget(xid); + aura::Window* window = root_window ? + views::DesktopNativeWidgetHelperAura::GetViewsWindowForRootWindow( + root_window) : NULL; + + desktop_activation_client_->ActivateWindow(window); +} + +} // namespace views diff --git a/ui/views/widget/x11_desktop_handler.h b/ui/views/widget/x11_desktop_handler.h new file mode 100644 index 0000000..c3a9ba0 --- /dev/null +++ b/ui/views/widget/x11_desktop_handler.h @@ -0,0 +1,72 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_WIDGET_X11_DESKTOP_HANDLER_H_ +#define UI_VIEWS_WIDGET_X11_DESKTOP_HANDLER_H_ +#pragma once + +#include <X11/Xlib.h> +// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. +#undef RootWindow + +#include "base/message_loop.h" +#include "ui/aura/env_observer.h" +#include "ui/aura/x11_atom_cache.h" +#include "ui/views/views_export.h" + +namespace aura { +class FocusManager; +class DesktopActivationClient; +} + +namespace views { + +// A singleton that owns global objects related to the desktop and listens for +// X11 events on the X11 root window. Destroys itself when aura::Env is +// deleted. +class VIEWS_EXPORT X11DesktopHandler : public MessageLoop::Dispatcher, + public aura::EnvObserver { + public: + // Returns the singleton handler. + static X11DesktopHandler* get(); + + aura::FocusManager* get_focus_manager() const { + return focus_manager_.get(); + } + aura::DesktopActivationClient* get_activation_client() const { + return desktop_activation_client_.get(); + } + + // Overridden from MessageLoop::Dispatcher: + virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; + + // Overridden from aura::EnvObserver: + virtual void OnWindowInitialized(aura::Window* window) OVERRIDE; + virtual void OnWillDestroyEnv() OVERRIDE; + + private: + explicit X11DesktopHandler(); + virtual ~X11DesktopHandler(); + + // Handles changes in activation. + void OnActiveWindowChanged(::Window window); + + // The display and the native X window hosting the root window. + Display* xdisplay_; + + // The native root window. + ::Window x_root_window_; + + aura::X11AtomCache atom_cache_; + + // Global focus/activation managers. + scoped_ptr<aura::FocusManager> focus_manager_; + scoped_ptr<aura::DesktopActivationClient> desktop_activation_client_; + + DISALLOW_COPY_AND_ASSIGN(X11DesktopHandler); +}; + +} // namespace views + +#endif // UI_VIEWS_WIDGET_X11_DESKTOP_HANDLER_H_ diff --git a/ui/views/widget/x11_window_event_filter.cc b/ui/views/widget/x11_window_event_filter.cc index 10b5e8f..4956c51 100644 --- a/ui/views/widget/x11_window_event_filter.cc +++ b/ui/views/widget/x11_window_event_filter.cc @@ -11,12 +11,9 @@ #include "base/message_pump_aurax11.h" #include "ui/aura/desktop/desktop_activation_client.h" -#include "ui/aura/dispatcher_linux.h" -#include "ui/aura/env.h" #include "ui/aura/root_window.h" #include "ui/aura/window_delegate.h" #include "ui/base/hit_test.h" -#include "ui/base/x/x11_util.h" #include "ui/views/widget/native_widget_aura.h" namespace { @@ -51,7 +48,6 @@ const unsigned long kHintsDecorations = (1L << 1); const char* kAtomsToCache[] = { "_MOTIF_WM_HINTS", - "_NET_ACTIVE_WINDOW", "_NET_WM_MOVERESIZE", NULL }; @@ -71,21 +67,9 @@ X11WindowEventFilter::X11WindowEventFilter( x_root_window_(DefaultRootWindow(xdisplay_)), atom_cache_(xdisplay_, kAtomsToCache), is_active_(false) { - static_cast<aura::DispatcherLinux*>( - aura::Env::GetInstance()->GetDispatcher())-> - AddDispatcherForRootWindow(this); - - XWindowAttributes attr; - XGetWindowAttributes(xdisplay_, x_root_window_, &attr); - XSelectInput(xdisplay_, x_root_window_, - attr.your_event_mask | PropertyChangeMask | - StructureNotifyMask | SubstructureNotifyMask); } X11WindowEventFilter::~X11WindowEventFilter() { - static_cast<aura::DispatcherLinux*>( - aura::Env::GetInstance()->GetDispatcher())-> - RemoveDispatcherForRootWindow(this); } void X11WindowEventFilter::SetUseHostWindowBorders(bool use_os_border) { @@ -156,25 +140,6 @@ ui::GestureStatus X11WindowEventFilter::PreHandleGestureEvent( return ui::GESTURE_STATUS_UNKNOWN; } -bool X11WindowEventFilter::Dispatch(const base::NativeEvent& event) { - // Check for a change to the active window. - switch (event->type) { - case PropertyNotify: { - ::Atom active_window = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"); - - if (event->xproperty.window == x_root_window_ && - event->xproperty.atom == active_window) { - int window; - if (ui::GetIntProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window)) - OnActiveWindowChanged(static_cast< ::Window>(window)); - } - break; - } - } - - return false; -} - bool X11WindowEventFilter::DispatchHostWindowDragMovement( int hittest, const gfx::Point& screen_location) { @@ -237,23 +202,5 @@ bool X11WindowEventFilter::DispatchHostWindowDragMovement( return true; } -void X11WindowEventFilter::OnActiveWindowChanged(::Window window) { - if (xwindow_ == window) { - if (!is_active_) { - is_active_ = true; - - // Update activation client. - activation_client_->SetActivateWindowInResponseToSystem( - widget_->GetNativeView()); - widget_->OnActivated(); - } - } else if (is_active_) { - is_active_ = false; - - activation_client_->SetActivateWindowInResponseToSystem(NULL); - widget_->OnLostActive(); - } -} - } // namespace views diff --git a/ui/views/widget/x11_window_event_filter.h b/ui/views/widget/x11_window_event_filter.h index fa0cd6c..9ff00e7 100644 --- a/ui/views/widget/x11_window_event_filter.h +++ b/ui/views/widget/x11_window_event_filter.h @@ -27,8 +27,7 @@ namespace views { class NativeWidgetAura; // An EventFilter that sets properties on X11 windows. -class VIEWS_EXPORT X11WindowEventFilter : public aura::EventFilter, - public MessageLoop::Dispatcher { +class VIEWS_EXPORT X11WindowEventFilter : public aura::EventFilter { public: explicit X11WindowEventFilter( aura::RootWindow* root_window, @@ -50,18 +49,12 @@ class VIEWS_EXPORT X11WindowEventFilter : public aura::EventFilter, aura::Window* target, aura::GestureEvent* event) OVERRIDE; - // Overridden from MessageLoop::Dispatcher: - virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; - private: // Dispatches a _NET_WM_MOVERESIZE message to the window manager to tell it // to act as if a border or titlebar drag occurred. bool DispatchHostWindowDragMovement(int hittest, const gfx::Point& screen_location); - // Handles changes in activation. - void OnActiveWindowChanged(::Window window); - NativeWidgetAura* widget_; aura::DesktopActivationClient* activation_client_; |