Commit 472de00a authored by mlamouri@chromium.org's avatar mlamouri@chromium.org

Listen to Display reconfiguration and notify DisplayObservers on Mac.

This is including some refactoring with the DestopScreenX11 implementation.

TBR=sky@chromium.org (for BUILD.gn changes because brettw@ doens't formally own it)

BUG=122863,162827

Review URL: https://codereview.chromium.org/341983008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284227 0039d316-1c4b-4281-b951-d872f2087c98
parent e7aa19e6
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "third_party/WebKit/public/web/WebCompositionUnderline.h" #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "ui/base/cocoa/base_view.h" #include "ui/base/cocoa/base_view.h"
#include "ui/base/cocoa/remote_layer_api.h" #include "ui/base/cocoa/remote_layer_api.h"
#include "ui/gfx/display_observer.h"
struct ViewHostMsg_TextInputState_Params; struct ViewHostMsg_TextInputState_Params;
...@@ -219,7 +220,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac ...@@ -219,7 +220,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
public BrowserCompositorViewMacClient, public BrowserCompositorViewMacClient,
public IPC::Sender, public IPC::Sender,
public SoftwareFrameManagerClient, public SoftwareFrameManagerClient,
public CompositingIOSurfaceLayerClient { public CompositingIOSurfaceLayerClient,
public gfx::DisplayObserver {
public: public:
// The view will associate itself with the given widget. The native view must // The view will associate itself with the given widget. The native view must
// be hooked up immediately to the view hierarchy, or else when it is // be hooked up immediately to the view hierarchy, or else when it is
...@@ -350,6 +352,12 @@ class CONTENT_EXPORT RenderWidgetHostViewMac ...@@ -350,6 +352,12 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// CompositingIOSurfaceLayerClient implementation. // CompositingIOSurfaceLayerClient implementation.
virtual void AcceleratedLayerDidDrawFrame(bool succeeded) OVERRIDE; virtual void AcceleratedLayerDidDrawFrame(bool succeeded) OVERRIDE;
// gfx::DisplayObserver implementation.
virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE;
virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE;
virtual void OnDisplayMetricsChanged(const gfx::Display& display,
uint32_t metrics) OVERRIDE;
// Forwards the mouse event to the renderer. // Forwards the mouse event to the renderer.
void ForwardMouseEvent(const blink::WebMouseEvent& event); void ForwardMouseEvent(const blink::WebMouseEvent& event);
......
...@@ -537,10 +537,14 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) ...@@ -537,10 +537,14 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
delegated_frame_host_.reset(new DelegatedFrameHost(this)); delegated_frame_host_.reset(new DelegatedFrameHost(this));
} }
gfx::Screen::GetScreenFor(cocoa_view_)->AddObserver(this);
render_widget_host_->SetView(this); render_widget_host_->SetView(this);
} }
RenderWidgetHostViewMac::~RenderWidgetHostViewMac() { RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
gfx::Screen::GetScreenFor(cocoa_view_)->RemoveObserver(this);
// This is being called from |cocoa_view_|'s destructor, so invalidate the // This is being called from |cocoa_view_|'s destructor, so invalidate the
// pointer. // pointer.
cocoa_view_ = nil; cocoa_view_ = nil;
...@@ -2263,6 +2267,24 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) { ...@@ -2263,6 +2267,24 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
GotAcceleratedCompositingError(); GotAcceleratedCompositingError();
} }
////////////////////////////////////////////////////////////////////////////////
// gfx::DisplayObserver, public:
void RenderWidgetHostViewMac::OnDisplayAdded(const gfx::Display& display) {
}
void RenderWidgetHostViewMac::OnDisplayRemoved(const gfx::Display& display) {
}
void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
const gfx::Display& display, uint32_t metrics) {
gfx::Screen* screen = gfx::Screen::GetScreenFor(cocoa_view_);
if (display.id() != screen->GetDisplayNearestWindow(cocoa_view_).id())
return;
UpdateScreenInfo(cocoa_view_);
}
} // namespace content } // namespace content
// RenderWidgetHostViewCocoa --------------------------------------------------- // RenderWidgetHostViewCocoa ---------------------------------------------------
......
...@@ -79,6 +79,8 @@ component("gfx") { ...@@ -79,6 +79,8 @@ component("gfx") {
"color_utils.h", "color_utils.h",
"display.cc", "display.cc",
"display.h", "display.h",
"display_change_notifier.cc",
"display_change_notifier.h",
"display_observer.cc", "display_observer.cc",
"display_observer.h", "display_observer.h",
"favicon_size.cc", "favicon_size.cc",
......
// Copyright 2014 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/gfx/display_change_notifier.h"
#include "ui/gfx/display.h"
#include "ui/gfx/display_observer.h"
namespace gfx {
namespace {
class DisplayComparator {
public:
explicit DisplayComparator(const Display& display)
: display_id_(display.id())
{}
bool operator()(const Display& display) const {
return display.id() == display_id_;
}
private:
int64 display_id_;
};
} // anonymous namespace
DisplayChangeNotifier::DisplayChangeNotifier() {
}
DisplayChangeNotifier::~DisplayChangeNotifier() {
}
void DisplayChangeNotifier::AddObserver(DisplayObserver* obs) {
observer_list_.AddObserver(obs);
}
void DisplayChangeNotifier::RemoveObserver(DisplayObserver* obs) {
observer_list_.RemoveObserver(obs);
}
void DisplayChangeNotifier::NotifyDisplaysChanged(
const std::vector<Display>& old_displays,
const std::vector<Display>& new_displays) {
// Display present in old_displays but not in new_displays has been removed.
std::vector<Display>::const_iterator old_it = old_displays.begin();
for (; old_it != old_displays.end(); ++old_it) {
if (std::find_if(new_displays.begin(), new_displays.end(),
DisplayComparator(*old_it)) == new_displays.end()) {
FOR_EACH_OBSERVER(DisplayObserver, observer_list_,
OnDisplayRemoved(*old_it));
}
}
// Display present in new_displays but not in old_displays has been added.
// Display present in both might have been modified.
for (std::vector<Display>::const_iterator new_it =
new_displays.begin(); new_it != new_displays.end(); ++new_it) {
std::vector<Display>::const_iterator old_it = std::find_if(
old_displays.begin(), old_displays.end(), DisplayComparator(*new_it));
if (old_it == old_displays.end()) {
FOR_EACH_OBSERVER(DisplayObserver, observer_list_,
OnDisplayAdded(*new_it));
continue;
}
uint32_t metrics = DisplayObserver::DISPLAY_METRIC_NONE;
if (new_it->bounds() != old_it->bounds())
metrics |= DisplayObserver::DISPLAY_METRIC_BOUNDS;
if (new_it->rotation() != old_it->rotation())
metrics |= DisplayObserver::DISPLAY_METRIC_ROTATION;
if (new_it->work_area() != old_it->work_area())
metrics |= DisplayObserver::DISPLAY_METRIC_WORK_AREA;
if (new_it->device_scale_factor() != old_it->device_scale_factor())
metrics |= DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
if (metrics != DisplayObserver::DISPLAY_METRIC_NONE) {
FOR_EACH_OBSERVER(DisplayObserver,
observer_list_,
OnDisplayMetricsChanged(*new_it, metrics));
}
}
}
} // namespace gfx
// Copyright 2014 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_GFX_DISPLAY_CHANGE_NOTIFIER_H_
#define UI_GFX_DISPLAY_CHANGE_NOTIFIER_H_
#include <vector>
#include "base/observer_list.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
class Display;
class DisplayObserver;
// DisplayChangeNotifier is a class implementing the handling of DisplayObserver
// notification for Screen.
class GFX_EXPORT DisplayChangeNotifier {
public:
DisplayChangeNotifier();
~DisplayChangeNotifier();
void AddObserver(DisplayObserver* observer);
void RemoveObserver(DisplayObserver* observer);
void NotifyDisplaysChanged(const std::vector<Display>& old_displays,
const std::vector<Display>& new_displays);
private:
// The observers that need to be notified when a display is modified, added
// or removed.
ObserverList<DisplayObserver> observer_list_;
DISALLOW_COPY_AND_ASSIGN(DisplayChangeNotifier);
};
} // namespace gfx
#endif // UI_GFX_DISPLAY_CHANGE_NOTIFIER_H_
This diff is collapsed.
...@@ -152,6 +152,8 @@ ...@@ -152,6 +152,8 @@
'color_utils.h', 'color_utils.h',
'display.cc', 'display.cc',
'display.h', 'display.h',
'display_change_notifier.cc',
'display_change_notifier.h',
'display_observer.cc', 'display_observer.cc',
'display_observer.h', 'display_observer.h',
'favicon_size.cc', 'favicon_size.cc',
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
'codec/png_codec_unittest.cc', 'codec/png_codec_unittest.cc',
'color_analysis_unittest.cc', 'color_analysis_unittest.cc',
'color_utils_unittest.cc', 'color_utils_unittest.cc',
'display_change_notifier_unittest.cc',
'display_unittest.cc', 'display_unittest.cc',
'font_list_unittest.cc', 'font_list_unittest.cc',
'font_render_params_linux_unittest.cc', 'font_render_params_linux_unittest.cc',
...@@ -124,6 +125,11 @@ ...@@ -124,6 +125,11 @@
'dependencies': [ 'dependencies': [
'../../testing/android/native_test.gyp:native_test_native_code', '../../testing/android/native_test.gyp:native_test_native_code',
], ],
# Do not run display_change_notifier_unittest.cc on Android because it
# does not compile display_observer.cc
'sources!': [
'display_change_notifier_unittest.cc',
],
}], }],
['OS=="android" or OS=="ios"', { ['OS=="android" or OS=="ios"', {
'sources!': [ 'sources!': [
......
...@@ -11,10 +11,16 @@ ...@@ -11,10 +11,16 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/mac/sdk_forward_declarations.h" #include "base/mac/sdk_forward_declarations.h"
#include "base/timer/timer.h"
#include "ui/gfx/display.h" #include "ui/gfx/display.h"
#include "ui/gfx/display_change_notifier.h"
namespace { namespace {
// The delay to handle the display configuration changes.
// See comments in ScreenMac::HandleDisplayReconfiguration.
const int64 kConfigureDelayMs = 500;
gfx::Rect ConvertCoordinateSystem(NSRect ns_rect) { gfx::Rect ConvertCoordinateSystem(NSRect ns_rect) {
// Primary monitor is defined as the monitor with the menubar, // Primary monitor is defined as the monitor with the menubar,
// which is always at index 0. // which is always at index 0.
...@@ -78,7 +84,12 @@ gfx::Display GetDisplayForScreen(NSScreen* screen) { ...@@ -78,7 +84,12 @@ gfx::Display GetDisplayForScreen(NSScreen* screen) {
class ScreenMac : public gfx::Screen { class ScreenMac : public gfx::Screen {
public: public:
ScreenMac() {} ScreenMac() {
displays_ = BuildDisplaysFromQuartz();
CGDisplayRegisterReconfigurationCallback(
ScreenMac::DisplayReconfigurationCallBack, this);
}
virtual bool IsDIPEnabled() OVERRIDE { virtual bool IsDIPEnabled() OVERRIDE {
return true; return true;
...@@ -109,52 +120,7 @@ class ScreenMac : public gfx::Screen { ...@@ -109,52 +120,7 @@ class ScreenMac : public gfx::Screen {
} }
virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE {
// Don't just return all online displays. This would include displays return displays_;
// that mirror other displays, which are not desired in this list. It's
// tempting to use the count returned by CGGetActiveDisplayList, but active
// displays exclude sleeping displays, and those are desired.
// It would be ridiculous to have this many displays connected, but
// CGDirectDisplayID is just an integer, so supporting up to this many
// doesn't hurt.
CGDirectDisplayID online_displays[128];
CGDisplayCount online_display_count = 0;
if (CGGetOnlineDisplayList(arraysize(online_displays),
online_displays,
&online_display_count) != kCGErrorSuccess) {
return std::vector<gfx::Display>(1, GetPrimaryDisplay());
}
typedef std::map<int64, NSScreen*> ScreenIdsToScreensMap;
ScreenIdsToScreensMap screen_ids_to_screens;
for (NSScreen* screen in [NSScreen screens]) {
NSDictionary* screen_device_description = [screen deviceDescription];
int64 screen_id = [[screen_device_description
objectForKey:@"NSScreenNumber"] unsignedIntValue];
screen_ids_to_screens[screen_id] = screen;
}
std::vector<gfx::Display> displays;
for (CGDisplayCount online_display_index = 0;
online_display_index < online_display_count;
++online_display_index) {
CGDirectDisplayID online_display = online_displays[online_display_index];
if (CGDisplayMirrorsDisplay(online_display) == kCGNullDirectDisplay) {
// If this display doesn't mirror any other, include it in the list.
// The primary display in a mirrored set will be counted, but those that
// mirror it will not be.
ScreenIdsToScreensMap::iterator foundScreen =
screen_ids_to_screens.find(online_display);
if (foundScreen != screen_ids_to_screens.end()) {
displays.push_back(GetDisplayForScreen(foundScreen->second));
}
}
}
if (!displays.size())
return std::vector<gfx::Display>(1, GetPrimaryDisplay());
return displays;
} }
virtual gfx::Display GetDisplayNearestWindow( virtual gfx::Display GetDisplayNearestWindow(
...@@ -202,14 +168,105 @@ class ScreenMac : public gfx::Screen { ...@@ -202,14 +168,105 @@ class ScreenMac : public gfx::Screen {
} }
virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE { virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE {
// TODO(oshima): crbug.com/122863. change_notifier_.AddObserver(observer);
} }
virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE { virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE {
// TODO(oshima): crbug.com/122863. change_notifier_.RemoveObserver(observer);
}
static void DisplayReconfigurationCallBack(CGDirectDisplayID display,
CGDisplayChangeSummaryFlags flags,
void* userInfo) {
if (flags & kCGDisplayBeginConfigurationFlag)
return;
static_cast<ScreenMac*>(userInfo)->HandleDisplayReconfiguration();
}
void HandleDisplayReconfiguration() {
// Given that we need to rebuild the list of displays, we want to coalesce
// the events. For that, we use a timer that will be reset every time we get
// a new event and will be fulfilled kConfigureDelayMs after the latest.
if (configure_timer_.get() && configure_timer_->IsRunning()) {
configure_timer_->Reset();
return;
}
configure_timer_.reset(new base::OneShotTimer<ScreenMac>());
configure_timer_->Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
this,
&ScreenMac::ConfigureTimerFired);
} }
private: private:
void ConfigureTimerFired() {
std::vector<gfx::Display> old_displays = displays_;
displays_ = BuildDisplaysFromQuartz();
change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
}
std::vector<gfx::Display> BuildDisplaysFromQuartz() const {
// Don't just return all online displays. This would include displays
// that mirror other displays, which are not desired in this list. It's
// tempting to use the count returned by CGGetActiveDisplayList, but active
// displays exclude sleeping displays, and those are desired.
// It would be ridiculous to have this many displays connected, but
// CGDirectDisplayID is just an integer, so supporting up to this many
// doesn't hurt.
CGDirectDisplayID online_displays[128];
CGDisplayCount online_display_count = 0;
if (CGGetOnlineDisplayList(arraysize(online_displays),
online_displays,
&online_display_count) != kCGErrorSuccess) {
return std::vector<gfx::Display>(1, GetPrimaryDisplay());
}
typedef std::map<int64, NSScreen*> ScreenIdsToScreensMap;
ScreenIdsToScreensMap screen_ids_to_screens;
for (NSScreen* screen in [NSScreen screens]) {
NSDictionary* screen_device_description = [screen deviceDescription];
int64 screen_id = [[screen_device_description
objectForKey:@"NSScreenNumber"] unsignedIntValue];
screen_ids_to_screens[screen_id] = screen;
}
std::vector<gfx::Display> displays;
for (CGDisplayCount online_display_index = 0;
online_display_index < online_display_count;
++online_display_index) {
CGDirectDisplayID online_display = online_displays[online_display_index];
if (CGDisplayMirrorsDisplay(online_display) == kCGNullDirectDisplay) {
// If this display doesn't mirror any other, include it in the list.
// The primary display in a mirrored set will be counted, but those that
// mirror it will not be.
ScreenIdsToScreensMap::iterator foundScreen =
screen_ids_to_screens.find(online_display);
if (foundScreen != screen_ids_to_screens.end()) {
displays.push_back(GetDisplayForScreen(foundScreen->second));
}
}
}
if (!displays.size())
return std::vector<gfx::Display>(1, GetPrimaryDisplay());
return displays;
}
// The displays currently attached to the device.
std::vector<gfx::Display> displays_;
// The timer to delay configuring outputs. See also the comments in
// HandleDisplayReconfiguration().
scoped_ptr<base::OneShotTimer<ScreenMac> > configure_timer_;
gfx::DisplayChangeNotifier change_notifier_;
DISALLOW_COPY_AND_ASSIGN(ScreenMac); DISALLOW_COPY_AND_ASSIGN(ScreenMac);
}; };
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "ui/display/util/x11/edid_parser_x11.h" #include "ui/display/util/x11/edid_parser_x11.h"
#include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/display.h" #include "ui/gfx/display.h"
#include "ui/gfx/display_observer.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
...@@ -110,68 +109,6 @@ DesktopScreenX11::~DesktopScreenX11() { ...@@ -110,68 +109,6 @@ DesktopScreenX11::~DesktopScreenX11() {
ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
} }
void DesktopScreenX11::ProcessDisplayChange(
const std::vector<gfx::Display>& incoming) {
std::vector<gfx::Display> old_displays = displays_;
displays_ = incoming;
typedef std::vector<gfx::Display>::const_iterator DisplayIt;
std::vector<gfx::Display>::const_iterator old_it = old_displays.begin();
for (; old_it != old_displays.end(); ++old_it) {
bool found = false;
for (std::vector<gfx::Display>::const_iterator new_it =
displays_.begin(); new_it != displays_.end(); ++new_it) {
if (old_it->id() == new_it->id()) {
found = true;
break;
}
}
if (!found) {
FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
OnDisplayRemoved(*old_it));
}
}
std::vector<gfx::Display>::const_iterator new_it = displays_.begin();
for (; new_it != displays_.end(); ++new_it) {
bool found = false;
for (std::vector<gfx::Display>::const_iterator old_it =
old_displays.begin(); old_it != old_displays.end(); ++old_it) {
if (new_it->id() != old_it->id())
continue;
uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
if (new_it->bounds() != old_it->bounds())
metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS;
if (new_it->rotation() != old_it->rotation())
metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
if (new_it->work_area() != old_it->work_area())
metrics |= gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
if (new_it->device_scale_factor() != old_it->device_scale_factor())
metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
FOR_EACH_OBSERVER(gfx::DisplayObserver,
observer_list_,
OnDisplayMetricsChanged(*new_it, metrics));
}
found = true;
break;
}
if (!found) {
FOR_EACH_OBSERVER(gfx::DisplayObserver, observer_list_,
OnDisplayAdded(*new_it));
}
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// DesktopScreenX11, gfx::Screen implementation: // DesktopScreenX11, gfx::Screen implementation:
...@@ -273,11 +210,11 @@ gfx::Display DesktopScreenX11::GetPrimaryDisplay() const { ...@@ -273,11 +210,11 @@ gfx::Display DesktopScreenX11::GetPrimaryDisplay() const {
} }
void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) { void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) {
observer_list_.AddObserver(observer); change_notifier_.AddObserver(observer);
} }
void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) { void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) {
observer_list_.RemoveObserver(observer); change_notifier_.RemoveObserver(observer);
} }
bool DesktopScreenX11::CanDispatchEvent(const ui::PlatformEvent& event) { bool DesktopScreenX11::CanDispatchEvent(const ui::PlatformEvent& event) {
...@@ -416,8 +353,10 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() { ...@@ -416,8 +353,10 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
} }
void DesktopScreenX11::ConfigureTimerFired() { void DesktopScreenX11::ConfigureTimerFired() {
std::vector<gfx::Display> new_displays = BuildDisplaysFromXRandRInfo(); std::vector<gfx::Display> old_displays = displays_;
ProcessDisplayChange(new_displays); displays_ = BuildDisplaysFromXRandRInfo();
change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_
#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_X11_H_
#include "base/observer_list.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "ui/events/platform/platform_event_dispatcher.h" #include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/display_change_notifier.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
#include "ui/views/views_export.h" #include "ui/views/views_export.h"
...@@ -30,10 +30,6 @@ class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen, ...@@ -30,10 +30,6 @@ class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen,
virtual ~DesktopScreenX11(); virtual ~DesktopScreenX11();
// Takes a set of displays and dispatches the screen change events to
// listeners. Exposed for testing.
void ProcessDisplayChange(const std::vector<gfx::Display>& displays);
// Overridden from gfx::Screen: // Overridden from gfx::Screen:
virtual bool IsDIPEnabled() OVERRIDE; virtual bool IsDIPEnabled() OVERRIDE;
virtual gfx::Point GetCursorScreenPoint() OVERRIDE; virtual gfx::Point GetCursorScreenPoint() OVERRIDE;
...@@ -86,7 +82,7 @@ class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen, ...@@ -86,7 +82,7 @@ class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen,
// Dispatch(). // Dispatch().
scoped_ptr<base::OneShotTimer<DesktopScreenX11> > configure_timer_; scoped_ptr<base::OneShotTimer<DesktopScreenX11> > configure_timer_;
ObserverList<gfx::DisplayObserver> observer_list_; gfx::DisplayChangeNotifier change_notifier_;
DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11); DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11);
}; };
......
...@@ -79,6 +79,12 @@ class DesktopScreenX11Test : public views::ViewsTestBase, ...@@ -79,6 +79,12 @@ class DesktopScreenX11Test : public views::ViewsTestBase,
DesktopScreenX11* screen() { return screen_.get(); } DesktopScreenX11* screen() { return screen_.get(); }
void NotifyDisplaysChanged(const std::vector<gfx::Display>& displays) {
DesktopScreenX11* screen = screen_.get();
screen->change_notifier_.NotifyDisplaysChanged(screen->displays_, displays);
screen->displays_ = displays;
}
void ResetDisplayChanges() { void ResetDisplayChanges() {
changed_display_.clear(); changed_display_.clear();
added_display_.clear(); added_display_.clear();
...@@ -126,7 +132,7 @@ class DesktopScreenX11Test : public views::ViewsTestBase, ...@@ -126,7 +132,7 @@ class DesktopScreenX11Test : public views::ViewsTestBase,
TEST_F(DesktopScreenX11Test, BoundsChangeSingleMonitor) { TEST_F(DesktopScreenX11Test, BoundsChangeSingleMonitor) {
std::vector<gfx::Display> displays; std::vector<gfx::Display> displays;
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 1024, 768))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(1u, changed_display_.size()); EXPECT_EQ(1u, changed_display_.size());
EXPECT_EQ(0u, added_display_.size()); EXPECT_EQ(0u, added_display_.size());
...@@ -138,7 +144,7 @@ TEST_F(DesktopScreenX11Test, AddMonitorToTheRight) { ...@@ -138,7 +144,7 @@ TEST_F(DesktopScreenX11Test, AddMonitorToTheRight) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back(gfx::Display(kSecondDisplay, displays.push_back(gfx::Display(kSecondDisplay,
gfx::Rect(640, 0, 1024, 768))); gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(0u, changed_display_.size()); EXPECT_EQ(0u, changed_display_.size());
EXPECT_EQ(1u, added_display_.size()); EXPECT_EQ(1u, added_display_.size());
...@@ -149,7 +155,7 @@ TEST_F(DesktopScreenX11Test, AddMonitorToTheLeft) { ...@@ -149,7 +155,7 @@ TEST_F(DesktopScreenX11Test, AddMonitorToTheLeft) {
std::vector<gfx::Display> displays; std::vector<gfx::Display> displays;
displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768))); displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768)));
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(1024, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(1024, 0, 640, 480)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(1u, changed_display_.size()); EXPECT_EQ(1u, changed_display_.size());
EXPECT_EQ(1u, added_display_.size()); EXPECT_EQ(1u, added_display_.size());
...@@ -161,13 +167,13 @@ TEST_F(DesktopScreenX11Test, RemoveMonitorOnRight) { ...@@ -161,13 +167,13 @@ TEST_F(DesktopScreenX11Test, RemoveMonitorOnRight) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back(gfx::Display(kSecondDisplay, displays.push_back(gfx::Display(kSecondDisplay,
gfx::Rect(640, 0, 1024, 768))); gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
ResetDisplayChanges(); ResetDisplayChanges();
displays.clear(); displays.clear();
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(0u, changed_display_.size()); EXPECT_EQ(0u, changed_display_.size());
EXPECT_EQ(0u, added_display_.size()); EXPECT_EQ(0u, added_display_.size());
...@@ -179,13 +185,13 @@ TEST_F(DesktopScreenX11Test, RemoveMonitorOnLeft) { ...@@ -179,13 +185,13 @@ TEST_F(DesktopScreenX11Test, RemoveMonitorOnLeft) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back(gfx::Display(kSecondDisplay, displays.push_back(gfx::Display(kSecondDisplay,
gfx::Rect(640, 0, 1024, 768))); gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
ResetDisplayChanges(); ResetDisplayChanges();
displays.clear(); displays.clear();
displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768))); displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(1u, changed_display_.size()); EXPECT_EQ(1u, changed_display_.size());
EXPECT_EQ(0u, added_display_.size()); EXPECT_EQ(0u, added_display_.size());
...@@ -197,7 +203,7 @@ TEST_F(DesktopScreenX11Test, GetDisplayNearestPoint) { ...@@ -197,7 +203,7 @@ TEST_F(DesktopScreenX11Test, GetDisplayNearestPoint) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back(gfx::Display(kSecondDisplay, displays.push_back(gfx::Display(kSecondDisplay,
gfx::Rect(640, 0, 1024, 768))); gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(kSecondDisplay, EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayNearestPoint(gfx::Point(650, 10)).id()); screen()->GetDisplayNearestPoint(gfx::Point(650, 10)).id());
...@@ -212,7 +218,7 @@ TEST_F(DesktopScreenX11Test, GetDisplayMatchingBasic) { ...@@ -212,7 +218,7 @@ TEST_F(DesktopScreenX11Test, GetDisplayMatchingBasic) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back(gfx::Display(kSecondDisplay, displays.push_back(gfx::Display(kSecondDisplay,
gfx::Rect(640, 0, 1024, 768))); gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(kSecondDisplay, EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayMatching(gfx::Rect(700, 20, 100, 100)).id()); screen()->GetDisplayMatching(gfx::Rect(700, 20, 100, 100)).id());
...@@ -223,7 +229,7 @@ TEST_F(DesktopScreenX11Test, GetDisplayMatchingOverlap) { ...@@ -223,7 +229,7 @@ TEST_F(DesktopScreenX11Test, GetDisplayMatchingOverlap) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back(gfx::Display(kSecondDisplay, displays.push_back(gfx::Display(kSecondDisplay,
gfx::Rect(640, 0, 1024, 768))); gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(kSecondDisplay, EXPECT_EQ(kSecondDisplay,
screen()->GetDisplayMatching(gfx::Rect(630, 20, 100, 100)).id()); screen()->GetDisplayMatching(gfx::Rect(630, 20, 100, 100)).id());
...@@ -234,7 +240,7 @@ TEST_F(DesktopScreenX11Test, GetPrimaryDisplay) { ...@@ -234,7 +240,7 @@ TEST_F(DesktopScreenX11Test, GetPrimaryDisplay) {
displays.push_back(gfx::Display(kFirstDisplay, displays.push_back(gfx::Display(kFirstDisplay,
gfx::Rect(640, 0, 1024, 768))); gfx::Rect(640, 0, 1024, 768)));
displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 640, 480)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
// The first display in the list is always the primary, even if other // The first display in the list is always the primary, even if other
// displays are to the left in screen layout. // displays are to the left in screen layout.
...@@ -247,7 +253,7 @@ TEST_F(DesktopScreenX11Test, GetDisplayNearestWindow) { ...@@ -247,7 +253,7 @@ TEST_F(DesktopScreenX11Test, GetDisplayNearestWindow) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back(gfx::Display(kSecondDisplay, displays.push_back(gfx::Display(kSecondDisplay,
gfx::Rect(640, 0, 1024, 768))); gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
Widget* window_one = BuildTopLevelDesktopWidget(gfx::Rect(10, 10, 10, 10), Widget* window_one = BuildTopLevelDesktopWidget(gfx::Rect(10, 10, 10, 10),
false); false);
...@@ -357,28 +363,28 @@ TEST_F(DesktopScreenX11Test, RotationChange) { ...@@ -357,28 +363,28 @@ TEST_F(DesktopScreenX11Test, RotationChange) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back( displays.push_back(
gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
ResetDisplayChanges(); ResetDisplayChanges();
displays[0].set_rotation(gfx::Display::ROTATE_90); displays[0].set_rotation(gfx::Display::ROTATE_90);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(1u, changed_display_.size()); EXPECT_EQ(1u, changed_display_.size());
displays[1].set_rotation(gfx::Display::ROTATE_90); displays[1].set_rotation(gfx::Display::ROTATE_90);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(2u, changed_display_.size()); EXPECT_EQ(2u, changed_display_.size());
displays[0].set_rotation(gfx::Display::ROTATE_270); displays[0].set_rotation(gfx::Display::ROTATE_270);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(3u, changed_display_.size()); EXPECT_EQ(3u, changed_display_.size());
displays[0].set_rotation(gfx::Display::ROTATE_270); displays[0].set_rotation(gfx::Display::ROTATE_270);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(3u, changed_display_.size()); EXPECT_EQ(3u, changed_display_.size());
displays[0].set_rotation(gfx::Display::ROTATE_0); displays[0].set_rotation(gfx::Display::ROTATE_0);
displays[1].set_rotation(gfx::Display::ROTATE_0); displays[1].set_rotation(gfx::Display::ROTATE_0);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(5u, changed_display_.size()); EXPECT_EQ(5u, changed_display_.size());
} }
...@@ -388,28 +394,28 @@ TEST_F(DesktopScreenX11Test, WorkareaChange) { ...@@ -388,28 +394,28 @@ TEST_F(DesktopScreenX11Test, WorkareaChange) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back( displays.push_back(
gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
ResetDisplayChanges(); ResetDisplayChanges();
displays[0].set_work_area(gfx::Rect(0, 0, 300, 300)); displays[0].set_work_area(gfx::Rect(0, 0, 300, 300));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(1u, changed_display_.size()); EXPECT_EQ(1u, changed_display_.size());
displays[1].set_work_area(gfx::Rect(0, 0, 300, 300)); displays[1].set_work_area(gfx::Rect(0, 0, 300, 300));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(2u, changed_display_.size()); EXPECT_EQ(2u, changed_display_.size());
displays[0].set_work_area(gfx::Rect(0, 0, 300, 300)); displays[0].set_work_area(gfx::Rect(0, 0, 300, 300));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(2u, changed_display_.size()); EXPECT_EQ(2u, changed_display_.size());
displays[1].set_work_area(gfx::Rect(0, 0, 300, 300)); displays[1].set_work_area(gfx::Rect(0, 0, 300, 300));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(2u, changed_display_.size()); EXPECT_EQ(2u, changed_display_.size());
displays[0].set_work_area(gfx::Rect(0, 0, 640, 480)); displays[0].set_work_area(gfx::Rect(0, 0, 640, 480));
displays[1].set_work_area(gfx::Rect(640, 0, 1024, 768)); displays[1].set_work_area(gfx::Rect(640, 0, 1024, 768));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(4u, changed_display_.size()); EXPECT_EQ(4u, changed_display_.size());
} }
...@@ -419,28 +425,28 @@ TEST_F(DesktopScreenX11Test, DeviceScaleFactorChange) { ...@@ -419,28 +425,28 @@ TEST_F(DesktopScreenX11Test, DeviceScaleFactorChange) {
displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480)));
displays.push_back( displays.push_back(
gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768)));
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
ResetDisplayChanges(); ResetDisplayChanges();
displays[0].set_device_scale_factor(2.5f); displays[0].set_device_scale_factor(2.5f);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(1u, changed_display_.size()); EXPECT_EQ(1u, changed_display_.size());
displays[1].set_device_scale_factor(2.5f); displays[1].set_device_scale_factor(2.5f);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(2u, changed_display_.size()); EXPECT_EQ(2u, changed_display_.size());
displays[0].set_device_scale_factor(2.5f); displays[0].set_device_scale_factor(2.5f);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(2u, changed_display_.size()); EXPECT_EQ(2u, changed_display_.size());
displays[1].set_device_scale_factor(2.5f); displays[1].set_device_scale_factor(2.5f);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(2u, changed_display_.size()); EXPECT_EQ(2u, changed_display_.size());
displays[0].set_device_scale_factor(1.f); displays[0].set_device_scale_factor(1.f);
displays[1].set_device_scale_factor(1.f); displays[1].set_device_scale_factor(1.f);
screen()->ProcessDisplayChange(displays); NotifyDisplaysChanged(displays);
EXPECT_EQ(4u, changed_display_.size()); EXPECT_EQ(4u, changed_display_.size());
} }
......
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