Commit 196e945a authored by mukai@chromium.org's avatar mukai@chromium.org

Add Fade-out/Fade-in animation during output-configuration change.


BUG=127493
TEST=manually checked on lumpy


Review URL: https://chromiumcodereview.appspot.com/10817028

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149382 0039d316-1c4b-4281-b951-d872f2087c98
parent 9d29124d
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "ash/wm/window_cycle_controller.h" #include "ash/wm/window_cycle_controller.h"
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
#include "ash/wm/workspace/snap_sizer.h" #include "ash/wm/workspace/snap_sizer.h"
#include "base/bind.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "ui/aura/event.h" #include "ui/aura/event.h"
#include "ui/aura/root_window.h" #include "ui/aura/root_window.h"
...@@ -50,6 +51,7 @@ ...@@ -50,6 +51,7 @@
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "ash/display/output_configurator_animation.h"
#include "chromeos/display/output_configurator.h" #include "chromeos/display/output_configurator.h"
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
...@@ -406,9 +408,14 @@ bool AcceleratorController::PerformAction(int action, ...@@ -406,9 +408,14 @@ bool AcceleratorController::PerformAction(int action,
return HandleCrosh(); return HandleCrosh();
case TOGGLE_SPOKEN_FEEDBACK: case TOGGLE_SPOKEN_FEEDBACK:
return HandleToggleSpokenFeedback(); return HandleToggleSpokenFeedback();
case CYCLE_DISPLAY_MODE: case CYCLE_DISPLAY_MODE: {
ash::Shell::GetInstance()->output_configurator()->CycleDisplayMode(); internal::OutputConfiguratorAnimation* animation =
Shell::GetInstance()->output_configurator_animation();
animation->StartFadeOutAnimation(base::Bind(
base::IgnoreResult(&chromeos::OutputConfigurator::CycleDisplayMode),
base::Unretained(Shell::GetInstance()->output_configurator())));
return true; return true;
}
#endif #endif
case OPEN_FEEDBACK_PAGE: case OPEN_FEEDBACK_PAGE:
ash::Shell::GetInstance()->delegate()->OpenFeedbackPage(); ash::Shell::GetInstance()->delegate()->OpenFeedbackPage();
......
...@@ -61,6 +61,18 @@ ...@@ -61,6 +61,18 @@
'desktop_background/desktop_background_resources.h', 'desktop_background/desktop_background_resources.h',
'desktop_background/desktop_background_view.cc', 'desktop_background/desktop_background_view.cc',
'desktop_background/desktop_background_view.h', 'desktop_background/desktop_background_view.h',
'display/display_controller.cc',
'display/display_controller.h',
'display/mouse_cursor_event_filter.cc',
'display/mouse_cursor_event_filter.h',
'display/multi_display_manager.cc',
'display/multi_display_manager.h',
'display/output_configurator_animation.cc',
'display/output_configurator_animation.h',
'display/screen_position_controller.cc',
'display/screen_position_controller.h',
'display/secondary_display_view.cc',
'display/secondary_display_view.h',
'drag_drop/drag_drop_controller.cc', 'drag_drop/drag_drop_controller.cc',
'drag_drop/drag_drop_controller.h', 'drag_drop/drag_drop_controller.h',
'drag_drop/drag_image_view.cc', 'drag_drop/drag_image_view.cc',
...@@ -101,16 +113,6 @@ ...@@ -101,16 +113,6 @@
'launcher/tabbed_launcher_button.h', 'launcher/tabbed_launcher_button.h',
'magnifier/magnification_controller.cc', 'magnifier/magnification_controller.cc',
'magnifier/magnification_controller.h', 'magnifier/magnification_controller.h',
'display/display_controller.cc',
'display/display_controller.h',
'display/mouse_cursor_event_filter.cc',
'display/mouse_cursor_event_filter.h',
'display/multi_display_manager.cc',
'display/multi_display_manager.h',
'display/screen_position_controller.cc',
'display/screen_position_controller.h',
'display/secondary_display_view.cc',
'display/secondary_display_view.h',
'keyboard_overlay/keyboard_overlay_delegate.cc', 'keyboard_overlay/keyboard_overlay_delegate.cc',
'keyboard_overlay/keyboard_overlay_delegate.h', 'keyboard_overlay/keyboard_overlay_delegate.h',
'keyboard_overlay/keyboard_overlay_view.cc', 'keyboard_overlay/keyboard_overlay_view.cc',
...@@ -357,6 +359,11 @@ ...@@ -357,6 +359,11 @@
'dependencies': [ 'dependencies': [
'../chromeos/chromeos.gyp:chromeos', '../chromeos/chromeos.gyp:chromeos',
], ],
}, { # else: chromeos!=1
'sources/': [
['exclude', 'display/output_configurator_animation.cc'],
['exclude', 'display/output_configurator_animation.h'],
],
}], }],
], ],
}, },
......
// 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 "ash/display/output_configurator_animation.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/time.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
namespace ash {
namespace internal {
namespace {
const int kFadingAnimationDurationInMS = 200;
const int kFadingTimeoutDurationInSeconds = 10;
// CallbackRunningObserver accepts multiple layer animations and
// runs the specified |callback| when all of the animations have finished.
class CallbackRunningObserver {
public:
CallbackRunningObserver(base::Closure callback)
: completed_counter_(0),
animation_aborted_(false),
callback_(callback) {}
void AddNewAnimator(ui::LayerAnimator* animator) {
Observer* observer = new Observer(animator, this);
animator->AddObserver(observer);
observer_list_.push_back(observer);
}
private:
void OnSingleTaskCompleted() {
completed_counter_++;
if (completed_counter_ >= observer_list_.size()) {
MessageLoopForUI::current()->DeleteSoon(FROM_HERE, this);
if (!animation_aborted_)
MessageLoopForUI::current()->PostTask(FROM_HERE, callback_);
}
}
void OnSingleTaskAborted() {
animation_aborted_ = true;
OnSingleTaskCompleted();
}
// The actual observer to listen each animation completion.
class Observer : public ui::LayerAnimationObserver {
public:
Observer(ui::LayerAnimator* animator,
CallbackRunningObserver* observer)
: animator_(animator),
observer_(observer) {}
protected:
// ui::LayerAnimationObserver overrides:
virtual void OnLayerAnimationEnded(
ui::LayerAnimationSequence* sequence) OVERRIDE {
animator_->RemoveObserver(this);
observer_->OnSingleTaskCompleted();
}
virtual void OnLayerAnimationAborted(
ui::LayerAnimationSequence* sequence) OVERRIDE {
animator_->RemoveObserver(this);
observer_->OnSingleTaskAborted();
}
virtual void OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) OVERRIDE {
}
virtual bool RequiresNotificationWhenAnimatorDestroyed() const OVERRIDE {
return true;
}
private:
ui::LayerAnimator* animator_;
CallbackRunningObserver* observer_;
DISALLOW_COPY_AND_ASSIGN(Observer);
};
size_t completed_counter_;
bool animation_aborted_;
ScopedVector<Observer> observer_list_;
base::Closure callback_;
DISALLOW_COPY_AND_ASSIGN(CallbackRunningObserver);
};
} // namespace
OutputConfiguratorAnimation::OutputConfiguratorAnimation() {
}
OutputConfiguratorAnimation::~OutputConfiguratorAnimation() {
ClearHidingLayers();
}
void OutputConfiguratorAnimation::StartFadeOutAnimation(
base::Closure callback) {
CallbackRunningObserver* observer = new CallbackRunningObserver(callback);
ClearHidingLayers();
// Make the fade-out animation for all root windows. Instead of actually
// hiding the root windows, we put a black layer over a root window for
// safety. These layers remain to hide root windows and will be deleted
// after the animation of OnDisplayModeChanged().
Shell::RootWindowList root_windows =
Shell::GetInstance()->GetAllRootWindows();
for (Shell::RootWindowList::const_iterator it = root_windows.begin();
it != root_windows.end(); ++it) {
aura::RootWindow* root_window = *it;
ui::Layer* hiding_layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
hiding_layer->SetColor(SK_ColorBLACK);
hiding_layer->SetBounds(root_window->bounds());
ui::Layer* parent = ash::Shell::GetContainer(
root_window,
ash::internal::kShellWindowId_OverlayContainer)->layer();
parent->Add(hiding_layer);
hiding_layer->SetOpacity(0.0);
ui::ScopedLayerAnimationSettings settings(hiding_layer->GetAnimator());
settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
kFadingAnimationDurationInMS));
observer->AddNewAnimator(hiding_layer->GetAnimator());
hiding_layer->SetOpacity(1.0f);
hiding_layer->SetVisible(true);
hiding_layers_[root_window] = hiding_layer;
}
// In case that OnDisplayModeChanged() isn't called or its animator is
// canceled due to some unknown errors, we set a timer to clear these
// hiding layers.
timer_.reset(new base::OneShotTimer<OutputConfiguratorAnimation>());
timer_->Start(FROM_HERE,
base::TimeDelta::FromSeconds(kFadingTimeoutDurationInSeconds),
this,
&OutputConfiguratorAnimation::ClearHidingLayers);
}
void OutputConfiguratorAnimation::StartFadeInAnimation() {
// We want to make sure clearing all of hiding layers after the animation
// finished. Note that this callback can be canceled, but the cancel only
// happens when the next animation is scheduled. Thus the hiding layers
// should be deleted eventually.
CallbackRunningObserver* observer = new CallbackRunningObserver(
base::Bind(&OutputConfiguratorAnimation::ClearHidingLayers,
base::Unretained(this)));
// Ensure that layers are not animating.
for (std::map<aura::RootWindow*, ui::Layer*>::iterator it =
hiding_layers_.begin(); it != hiding_layers_.end(); ++it) {
ui::LayerAnimator* animator = it->second->GetAnimator();
if (animator->is_animating())
animator->StopAnimating();
}
// Schedules the fade-in effect for all root windows. Because we put the
// black layers for fade-out, here we actually turn those black layers
// invisible.
Shell::RootWindowList root_windows =
Shell::GetInstance()->GetAllRootWindows();
for (Shell::RootWindowList::const_iterator it = root_windows.begin();
it != root_windows.end(); ++it) {
aura::RootWindow* root_window = *it;
ui::Layer* hiding_layer = NULL;
if (hiding_layers_.find(root_window) == hiding_layers_.end()) {
// In case of the transition from mirroring->non-mirroring, new root
// windows appear and we do not have the black layers for them. Thus
// we need to create the layer and make it visible.
hiding_layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
hiding_layer->SetColor(SK_ColorBLACK);
hiding_layer->SetBounds(root_window->bounds());
ui::Layer* parent = ash::Shell::GetContainer(
root_window,
ash::internal::kShellWindowId_OverlayContainer)->layer();
parent->Add(hiding_layer);
hiding_layer->SetOpacity(1.0f);
hiding_layer->SetVisible(true);
hiding_layers_[root_window] = hiding_layer;
} else {
hiding_layer = hiding_layers_[root_window];
}
ui::ScopedLayerAnimationSettings settings(hiding_layer->GetAnimator());
settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
kFadingAnimationDurationInMS));
observer->AddNewAnimator(hiding_layer->GetAnimator());
hiding_layer->SetOpacity(0.0f);
hiding_layer->SetVisible(false);
}
}
void OutputConfiguratorAnimation::OnDisplayModeChanged() {
StartFadeInAnimation();
}
void OutputConfiguratorAnimation::ClearHidingLayers() {
if (timer_.get()) {
timer_->Stop();
timer_.reset();
}
STLDeleteContainerPairSecondPointers(
hiding_layers_.begin(), hiding_layers_.end());
hiding_layers_.clear();
}
} // namespace internal
} // namespace ash
// 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 ASH_DISPLAY_OUTPUT_CONFIGURATOR_ANIMATION_H_
#define ASH_DISPLAY_OUTPUT_CONFIGURATOR_ANIMATION_H_
#include <map>
#include "ash/ash_export.h"
#include "base/callback.h"
#include "base/timer.h"
#include "chromeos/display/output_configurator.h"
namespace aura {
class RootWindow;
} // namespace aura
namespace ui {
class Layer;
} // namespace ui
namespace ash {
namespace internal {
// OutputConfiguratorAnimation provides the visual effects for
// chromeos::OutputConfigurator, such like fade-out/in during changing
// the display mode.
class ASH_EXPORT OutputConfiguratorAnimation
: public chromeos::OutputConfigurator::Observer {
public:
OutputConfiguratorAnimation();
virtual ~OutputConfiguratorAnimation();
// Starts the fade-out animation for the all root windows. It will
// call |callback| once all of the animations have finished.
void StartFadeOutAnimation(base::Closure callback);
// Starts the animation to clear the fade-out animation effect
// for the all root windows.
void StartFadeInAnimation();
protected:
// chromeos::OutputConfigurator::Observer overrides:
virtual void OnDisplayModeChanged() OVERRIDE;
private:
// Clears all hiding layers. Note that in case that this method is called
// during an animation, the method call will cancel all of the animations
// and *not* call the registered callback.
void ClearHidingLayers();
std::map<aura::RootWindow*, ui::Layer*> hiding_layers_;
scoped_ptr<base::OneShotTimer<OutputConfiguratorAnimation> > timer_;
DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorAnimation);
};
} // namespace internal
} // namespace ash
#endif // ASH_DISPLAY_OUTPUT_CONFIGURATION_CONTROLLER_H_
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
#endif #endif
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "ash/display/output_configurator_animation.h"
#include "chromeos/display/output_configurator.h" #include "chromeos/display/output_configurator.h"
#include "ui/aura/dispatcher_linux.h" #include "ui/aura/dispatcher_linux.h"
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
...@@ -182,6 +183,8 @@ Shell::Shell(ShellDelegate* delegate) ...@@ -182,6 +183,8 @@ Shell::Shell(ShellDelegate* delegate)
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
output_configurator_(new chromeos::OutputConfigurator( output_configurator_(new chromeos::OutputConfigurator(
internal::DisplayController::IsExtendedDesktopEnabled())), internal::DisplayController::IsExtendedDesktopEnabled())),
output_configurator_animation_(
new internal::OutputConfiguratorAnimation()),
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
shelf_(NULL), shelf_(NULL),
panel_layout_manager_(NULL), panel_layout_manager_(NULL),
...@@ -190,7 +193,7 @@ Shell::Shell(ShellDelegate* delegate) ...@@ -190,7 +193,7 @@ Shell::Shell(ShellDelegate* delegate)
gfx::Screen::SetInstance(screen_); gfx::Screen::SetInstance(screen_);
ui_controls::InstallUIControlsAura(internal::CreateUIControls()); ui_controls::InstallUIControlsAura(internal::CreateUIControls());
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
// OutputConfigurator needs to get events regarding added/removed outputs. output_configurator_->AddObserver(output_configurator_animation_.get());
static_cast<aura::DispatcherLinux*>( static_cast<aura::DispatcherLinux*>(
aura::Env::GetInstance()->GetDispatcher())->AddDispatcherForRootWindow( aura::Env::GetInstance()->GetDispatcher())->AddDispatcherForRootWindow(
output_configurator()); output_configurator());
...@@ -272,6 +275,7 @@ Shell::~Shell() { ...@@ -272,6 +275,7 @@ Shell::~Shell() {
instance_ = NULL; instance_ = NULL;
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
output_configurator_->RemoveObserver(output_configurator_animation_.get());
// Remove OutputConfigurator from Dispatcher. // Remove OutputConfigurator from Dispatcher.
static_cast<aura::DispatcherLinux*>( static_cast<aura::DispatcherLinux*>(
aura::Env::GetInstance()->GetDispatcher())->RemoveDispatcherForRootWindow( aura::Env::GetInstance()->GetDispatcher())->RemoveDispatcherForRootWindow(
......
...@@ -85,6 +85,7 @@ class EventRewriterEventFilter; ...@@ -85,6 +85,7 @@ class EventRewriterEventFilter;
class FocusCycler; class FocusCycler;
class MagnificationController; class MagnificationController;
class MouseCursorEventFilter; class MouseCursorEventFilter;
class OutputConfiguratorAnimation;
class OverlayEventFilter; class OverlayEventFilter;
class PanelLayoutManager; class PanelLayoutManager;
class ResizeShadowController; class ResizeShadowController;
...@@ -358,6 +359,9 @@ class ASH_EXPORT Shell : ash::CursorDelegate { ...@@ -358,6 +359,9 @@ class ASH_EXPORT Shell : ash::CursorDelegate {
chromeos::OutputConfigurator* output_configurator() { chromeos::OutputConfigurator* output_configurator() {
return output_configurator_.get(); return output_configurator_.get();
} }
internal::OutputConfiguratorAnimation* output_configurator_animation() {
return output_configurator_animation_.get();
}
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
private: private:
...@@ -467,6 +471,8 @@ class ASH_EXPORT Shell : ash::CursorDelegate { ...@@ -467,6 +471,8 @@ class ASH_EXPORT Shell : ash::CursorDelegate {
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
// Controls video output device state. // Controls video output device state.
scoped_ptr<chromeos::OutputConfigurator> output_configurator_; scoped_ptr<chromeos::OutputConfigurator> output_configurator_;
scoped_ptr<internal::OutputConfiguratorAnimation>
output_configurator_animation_;
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
CursorManager cursor_manager_; CursorManager cursor_manager_;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <string> #include <string>
#include "ash/display/display_controller.h" #include "ash/display/display_controller.h"
#include "ash/display/output_configurator_animation.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/json/json_value_converter.h" #include "base/json/json_value_converter.h"
...@@ -125,6 +126,24 @@ void DisplayOptionsHandler::SendDisplayInfo() { ...@@ -125,6 +126,24 @@ void DisplayOptionsHandler::SendDisplayInfo() {
mirroring, displays, layout); mirroring, displays, layout);
} }
void DisplayOptionsHandler::FadeOutForMirroringFinished(bool is_mirroring) {
// We use 'PRIMARY_ONLY' for non-mirroring state for now.
// TODO(mukai): fix this and support multiple display modes.
chromeos::OutputState new_state =
is_mirroring ? STATE_DUAL_MIRROR : STATE_DUAL_PRIMARY_ONLY;
ash::Shell::GetInstance()->output_configurator()->SetDisplayMode(new_state);
SendDisplayInfo();
// Not necessary to start fade-in animation. OutputConfigurator will do that.
}
void DisplayOptionsHandler::FadeOutForDisplayLayoutFinished(int layout) {
PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs();
pref_service->SetInteger(prefs::kSecondaryDisplayLayout, layout);
SendDisplayInfo();
ash::Shell::GetInstance()->output_configurator_animation()->
StartFadeInAnimation();
}
void DisplayOptionsHandler::HandleDisplayInfo( void DisplayOptionsHandler::HandleDisplayInfo(
const base::ListValue* unused_args) { const base::ListValue* unused_args) {
SendDisplayInfo(); SendDisplayInfo();
...@@ -134,12 +153,11 @@ void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) { ...@@ -134,12 +153,11 @@ void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) {
DCHECK(!args->empty()); DCHECK(!args->empty());
bool is_mirroring = false; bool is_mirroring = false;
args->GetBoolean(0, &is_mirroring); args->GetBoolean(0, &is_mirroring);
// We use 'PRIMARY_ONLY' for non-mirroring state for now. ash::Shell::GetInstance()->output_configurator_animation()->
// TODO(mukai): fix this and support multiple display modes. StartFadeOutAnimation(base::Bind(
chromeos::OutputState new_state = &DisplayOptionsHandler::FadeOutForMirroringFinished,
is_mirroring ? STATE_DUAL_MIRROR : STATE_DUAL_PRIMARY_ONLY; base::Unretained(this),
ash::Shell::GetInstance()->output_configurator()->SetDisplayMode(new_state); is_mirroring));
SendDisplayInfo();
} }
void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) { void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
...@@ -150,10 +168,11 @@ void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) { ...@@ -150,10 +168,11 @@ void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
} }
DCHECK_LE(DisplayController::TOP, layout); DCHECK_LE(DisplayController::TOP, layout);
DCHECK_GE(DisplayController::LEFT, layout); DCHECK_GE(DisplayController::LEFT, layout);
ash::Shell::GetInstance()->output_configurator_animation()->
PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs(); StartFadeOutAnimation(base::Bind(
pref_service->SetInteger(prefs::kSecondaryDisplayLayout, layout); &DisplayOptionsHandler::FadeOutForDisplayLayoutFinished,
SendDisplayInfo(); base::Unretained(this),
static_cast<int>(layout)));
} }
} // namespace options2 } // namespace options2
......
...@@ -46,6 +46,13 @@ class DisplayOptionsHandler : public ::options2::OptionsPageUIHandler, ...@@ -46,6 +46,13 @@ class DisplayOptionsHandler : public ::options2::OptionsPageUIHandler,
// Sends the current display information to the web_ui of options page. // Sends the current display information to the web_ui of options page.
void SendDisplayInfo(); void SendDisplayInfo();
// Called when the fade-out animation for mirroring status change is finished.
void FadeOutForMirroringFinished(bool is_mirroring);
// Called when the fade-out animation for secondary display layout change is
// finished.
void FadeOutForDisplayLayoutFinished(int layout);
// Handlers of JS messages. // Handlers of JS messages.
void HandleDisplayInfo(const base::ListValue* unused_args); void HandleDisplayInfo(const base::ListValue* unused_args);
void HandleMirroring(const base::ListValue* args); void HandleMirroring(const base::ListValue* args);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#undef Status #undef Status
#undef RootWindow #undef RootWindow
#include "base/bind.h"
#include "base/chromeos/chromeos_version.h" #include "base/chromeos/chromeos_version.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/message_pump_aurax11.h" #include "base/message_pump_aurax11.h"
...@@ -399,6 +400,11 @@ bool OutputConfigurator::SetDisplayMode(OutputState new_state) { ...@@ -399,6 +400,11 @@ bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
new_state); new_state);
XRRFreeScreenResources(screen); XRRFreeScreenResources(screen);
XUngrabServer(display); XUngrabServer(display);
MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&OutputConfigurator::NotifyOnDisplayChanged,
base::Unretained(this)));
return true; return true;
} }
...@@ -424,6 +430,14 @@ bool OutputConfigurator::Dispatch(const base::NativeEvent& event) { ...@@ -424,6 +430,14 @@ bool OutputConfigurator::Dispatch(const base::NativeEvent& event) {
return true; return true;
} }
void OutputConfigurator::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void OutputConfigurator::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
bool OutputConfigurator::TryRecacheOutputs(Display* display, bool OutputConfigurator::TryRecacheOutputs(Display* display,
XRRScreenResources* screen) { XRRScreenResources* screen) {
bool outputs_did_change = false; bool outputs_did_change = false;
...@@ -843,4 +857,8 @@ void OutputConfigurator::CheckIsProjectingAndNotify() { ...@@ -843,4 +857,8 @@ void OutputConfigurator::CheckIsProjectingAndNotify() {
dbus::ObjectProxy::EmptyResponseCallback()); dbus::ObjectProxy::EmptyResponseCallback());
} }
void OutputConfigurator::NotifyOnDisplayChanged() {
FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
}
} // namespace chromeos } // namespace chromeos
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/event_types.h" #include "base/event_types.h"
#include "base/observer_list.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "chromeos/chromeos_export.h" #include "chromeos/chromeos_export.h"
...@@ -40,6 +41,13 @@ enum OutputState { ...@@ -40,6 +41,13 @@ enum OutputState {
// it. // it.
class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher { class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
public: public:
class Observer {
public:
// Called when the change of the display mode finished. It will usually
// start the fading in the displays.
virtual void OnDisplayModeChanged() = 0;
};
explicit OutputConfigurator(bool is_extended_display_enabled); explicit OutputConfigurator(bool is_extended_display_enabled);
virtual ~OutputConfigurator(); virtual ~OutputConfigurator();
...@@ -67,6 +75,9 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher { ...@@ -67,6 +75,9 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
// Spurious events will have no effect. // Spurious events will have no effect.
virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
private: private:
// The information we need to cache from an output to implement operations // The information we need to cache from an output to implement operations
// such as power state but also to eliminate duplicate operations within a // such as power state but also to eliminate duplicate operations within a
...@@ -124,6 +135,9 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher { ...@@ -124,6 +135,9 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
// with the result. // with the result.
void CheckIsProjectingAndNotify(); void CheckIsProjectingAndNotify();
// Fires OnDisplayModeChanged() event to the observers.
void NotifyOnDisplayChanged();
// This is detected by the constructor to determine whether or not we should // This is detected by the constructor to determine whether or not we should
// be enabled. If we aren't running on ChromeOS, we can't assume that the // be enabled. If we aren't running on ChromeOS, we can't assume that the
// Xrandr X11 extension is supported. // Xrandr X11 extension is supported.
...@@ -161,6 +175,8 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher { ...@@ -161,6 +175,8 @@ class CHROMEOS_EXPORT OutputConfigurator : public MessageLoop::Dispatcher {
// This is used for rotating display modes. // This is used for rotating display modes.
OutputState output_state_; OutputState output_state_;
ObserverList<Observer> observers_;
DISALLOW_COPY_AND_ASSIGN(OutputConfigurator); DISALLOW_COPY_AND_ASSIGN(OutputConfigurator);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment