diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-22 18:02:52 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-22 18:02:52 +0000 |
commit | f2404967a8d9da71ba86fa75d2986bbb989d705c (patch) | |
tree | e6f477d8fb91a6274c488898287ebd8888145ae4 /ash/display | |
parent | 399cf2b6045850ee2bc3189326a85689fb06a8d5 (diff) | |
download | chromium_src-f2404967a8d9da71ba86fa75d2986bbb989d705c.zip chromium_src-f2404967a8d9da71ba86fa75d2986bbb989d705c.tar.gz chromium_src-f2404967a8d9da71ba86fa75d2986bbb989d705c.tar.bz2 |
Restore focus/activation after the root window has been completely deleted.
Otherwise restoring focused/active window may try to use stale display.
BUG=229158
Review URL: https://chromiumcodereview.appspot.com/14188054
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195552 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/display')
-rw-r--r-- | ash/display/display_controller.cc | 76 | ||||
-rw-r--r-- | ash/display/display_controller.h | 3 |
2 files changed, 78 insertions, 1 deletions
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc index 89f2d3e..cba80e2 100644 --- a/ash/display/display_controller.cc +++ b/ash/display/display_controller.cc @@ -26,12 +26,16 @@ #include "base/strings/string_piece.h" #include "base/values.h" #include "third_party/skia/include/utils/SkMatrix44.h" +#include "ui/aura/client/activation_client.h" +#include "ui/aura/client/capture_client.h" #include "ui/aura/client/cursor_client.h" +#include "ui/aura/client/focus_client.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/aura/window_property.h" +#include "ui/aura/window_tracker.h" #include "ui/compositor/compositor.h" #include "ui/compositor/dip_util.h" #include "ui/gfx/display.h" @@ -227,6 +231,73 @@ void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, } // namespace +namespace internal { + +// A utility class to store/restore focused/active window +// when the display configuration has changed. +class FocusActivationStore { + public: + FocusActivationStore() + : activation_client_(NULL), + capture_client_(NULL), + focus_client_(NULL), + focused_(NULL), + active_(NULL) { + } + + void Store() { + if (!activation_client_) { + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + activation_client_ = aura::client::GetActivationClient(root); + capture_client_ = aura::client::GetCaptureClient(root); + focus_client_ = aura::client::GetFocusClient(root); + } + focused_ = focus_client_->GetFocusedWindow(); + if (focused_) + tracker_.Add(focused_); + active_ = activation_client_->GetActiveWindow(); + if (active_ && focused_ != active_) + tracker_.Add(active_); + + // Deactivate the window to close menu / bubble windows. + activation_client_->DeactivateWindow(active_); + // Release capture if any. + capture_client_->SetCapture(NULL); + // Clear the focused window if any. This is necessary because a + // window may be deleted when losing focus (fullscreen flash for + // example). If the focused window is still alive after move, it'll + // be re-focused below. + focus_client_->FocusWindow(NULL); + } + + void Restore() { + // Restore focused or active window if it's still alive. + if (focused_ && tracker_.Contains(focused_)) { + focus_client_->FocusWindow(focused_); + } else if (active_ && tracker_.Contains(active_)) { + activation_client_->ActivateWindow(active_); + } + if (focused_) + tracker_.Remove(focused_); + if (active_) + tracker_.Remove(active_); + focused_ = NULL; + active_ = NULL; + } + + private: + aura::client::ActivationClient* activation_client_; + aura::client::CaptureClient* capture_client_; + aura::client::FocusClient* focus_client_; + aura::WindowTracker tracker_; + aura::Window* focused_; + aura::Window* active_; + + DISALLOW_COPY_AND_ASSIGN(FocusActivationStore); +}; + +} // namespace internal + //////////////////////////////////////////////////////////////////////////////// // DisplayLayout @@ -341,7 +412,8 @@ bool DisplayController::DisplayChangeLimiter::IsThrottled() const { DisplayController::DisplayController() : primary_root_window_for_replace_(NULL), - in_bootstrap_(true) { + in_bootstrap_(true), + focus_activation_store_(new internal::FocusActivationStore()) { CommandLine* command_line = CommandLine::ForCurrentProcess(); #if defined(OS_CHROMEOS) if (!command_line->HasSwitch(switches::kAshDisableDisplayChangeLimiter) && @@ -980,11 +1052,13 @@ void DisplayController::NotifyDisplayConfigurationChanging() { if (in_bootstrap()) return; FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanging()); + focus_activation_store_->Store(); } void DisplayController::NotifyDisplayConfigurationChanged() { if (in_bootstrap()) return; + focus_activation_store_->Restore(); internal::DisplayManager* display_manager = GetDisplayManager(); if (display_manager->num_connected_displays() > 1) { diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h index 5313073..ae6e3af 100644 --- a/ash/display/display_controller.h +++ b/ash/display/display_controller.h @@ -31,6 +31,7 @@ template <typename T> class JSONValueConverter; namespace ash { namespace internal { class DisplayManager; +class FocusActivationStore; class RootWindowController; } @@ -272,6 +273,8 @@ class ASH_EXPORT DisplayController : public gfx::DisplayObserver { bool in_bootstrap_; + scoped_ptr<internal::FocusActivationStore> focus_activation_store_; + DISALLOW_COPY_AND_ASSIGN(DisplayController); }; |