typedef std::vector<const DisplayMode*> DisplayModeList;
-// The delay to perform configuration after RRNotify. See the comment
-// in |Dispatch()|.
+// The delay to perform configuration after RRNotify. See the comment for
+// |configure_timer_|.
const int kConfigureDelayMs = 500;
+// The delay spent before reading the display configuration after coming out of
+// suspend. While coming out of suspend the display state may be updating. This
+// is used to wait until the hardware had a chance to update the display state
+// such that we read an up to date state.
+const int kResumeDelayMs = 500;
+
// Returns a string describing |state|.
std::string DisplayPowerStateToString(chromeos::DisplayPowerState state) {
switch (state) {
} // namespace
-DisplayConfigurator::CoordinateTransformation::CoordinateTransformation()
- : x_scale(1.0),
- x_offset(0.0),
- y_scale(1.0),
- y_offset(0.0) {}
+
+const int DisplayConfigurator::kSetDisplayPowerNoFlags = 0;
+const int DisplayConfigurator::kSetDisplayPowerForceProbe = 1 << 0;
+const int
+DisplayConfigurator::kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1;
DisplayConfigurator::DisplayState::DisplayState()
: display(NULL),
mirror_mode(NULL) {}
bool DisplayConfigurator::TestApi::TriggerConfigureTimeout() {
- if (configurator_->configure_timer_.get() &&
- configurator_->configure_timer_->IsRunning()) {
- configurator_->configure_timer_.reset();
- configurator_->ConfigureDisplays();
+ if (configurator_->configure_timer_.IsRunning()) {
+ configurator_->configure_timer_.user_task().Run();
+ configurator_->configure_timer_.Stop();
return true;
} else {
return false;
DCHECK(!native_display_delegate_);
DCHECK(!touchscreen_delegate_);
- InitializeDelegates(display_delegate.Pass(), touchscreen_delegate.Pass());
+ native_display_delegate_ = display_delegate.Pass();
+ touchscreen_delegate_ = touchscreen_delegate.Pass();
configure_display_ = true;
}
if (!configure_display_)
return;
- PlatformInitialize();
-}
-
-void DisplayConfigurator::InitializeDelegates(
- scoped_ptr<NativeDisplayDelegate> display_delegate,
- scoped_ptr<TouchscreenDelegate> touchscreen_delegate) {
- if (!native_display_delegate_ && !touchscreen_delegate_) {
- native_display_delegate_ = display_delegate.Pass();
- touchscreen_delegate_ = touchscreen_delegate.Pass();
-
+ // If the delegates are already initialized don't update them (For example,
+ // tests set their own delegates).
+ if (!native_display_delegate_) {
+ native_display_delegate_ = CreatePlatformNativeDisplayDelegate();
native_display_delegate_->AddObserver(this);
}
+
+ if (!touchscreen_delegate_)
+ touchscreen_delegate_ = CreatePlatformTouchscreenDelegate();
}
void DisplayConfigurator::ForceInitialConfigure(
NotifyObservers(success, new_state);
}
+bool DisplayConfigurator::IsMirroring() const {
+ return display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR ||
+ (mirroring_controller_ &&
+ mirroring_controller_->SoftwareMirroringEnabled());
+}
+
bool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) {
for (DisplayStateList::const_iterator it = cached_displays_.begin();
it != cached_displays_.end();
++it) {
uint32_t all_desired = 0;
- ContentProtections::const_iterator request_it =
- requests.find(it->display->display_id());
- if (request_it != requests.end())
- all_desired = request_it->second;
+
+ // In mirror mode, protection request of all displays need to be fulfilled.
+ // In non-mirror mode, only request of client's display needs to be
+ // fulfilled.
+ ContentProtections::const_iterator request_it;
+ if (IsMirroring()) {
+ for (request_it = requests.begin();
+ request_it != requests.end();
+ ++request_it)
+ all_desired |= request_it->second;
+ } else {
+ request_it = requests.find(it->display->display_id());
+ if (request_it != requests.end())
+ all_desired = request_it->second;
+ }
+
switch (it->display->type()) {
case DISPLAY_CONNECTION_TYPE_UNKNOWN:
return false;
for (DisplayStateList::const_iterator it = cached_displays_.begin();
it != cached_displays_.end();
++it) {
- if (it->display->display_id() != display_id)
+ // Query display if it is in mirror mode or client on the same display.
+ if (!IsMirroring() && it->display->display_id() != display_id)
continue;
+
*link_mask |= it->display->type();
switch (it->display->type()) {
case DISPLAY_CONNECTION_TYPE_UNKNOWN:
VLOG(1) << "SetDisplayPower: power_state="
<< DisplayPowerStateToString(power_state) << " flags=" << flags
<< ", configure timer="
- << ((configure_timer_.get() && configure_timer_->IsRunning()) ?
- "Running" : "Stopped");
+ << (configure_timer_.IsRunning() ? "Running" : "Stopped");
if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe))
return true;
void DisplayConfigurator::OnConfigurationChanged() {
// Configure displays with |kConfigureDelayMs| delay,
// so that time-consuming ConfigureDisplays() won't be called multiple times.
- if (configure_timer_.get()) {
- configure_timer_->Reset();
+ if (configure_timer_.IsRunning()) {
+ // Note: when the timer is running it is possible that a different task
+ // (SetDisplayPower()) is scheduled. In these cases, prefer the already
+ // scheduled task to ConfigureDisplays() since ConfigureDisplays() performs
+ // only basic configuration while SetDisplayPower() will perform additional
+ // operations.
+ configure_timer_.Reset();
} else {
- configure_timer_.reset(new base::OneShotTimer<DisplayConfigurator>());
- configure_timer_->Start(
+ configure_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
this,
void DisplayConfigurator::ResumeDisplays() {
// Force probing to ensure that we pick up any changes that were made
// while the system was suspended.
- SetDisplayPower(power_state_, kSetDisplayPowerForceProbe);
+ configure_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kResumeDelayMs),
+ base::Bind(base::IgnoreResult(&DisplayConfigurator::SetDisplayPower),
+ base::Unretained(this),
+ power_state_,
+ kSetDisplayPowerForceProbe));
}
void DisplayConfigurator::UpdateCachedDisplays() {
}
void DisplayConfigurator::ConfigureDisplays() {
- configure_timer_.reset();
-
if (!configure_display_)
return;
if (display_power[i] || cached_displays_.size() == 1) {
const DisplayMode* mode_info = state->selected_mode;
- if (!mode_info)
+ if (!mode_info) {
+ LOG(WARNING) << "No selected mode when configuring display: "
+ << state->display->ToString();
return false;
+ }
if (mode_info->size() == gfx::Size(1024, 768)) {
VLOG(1) << "Potentially misdetecting display(1024x768):"
<< " displays size=" << cached_displays_.size()
}
const DisplayMode* mode_info = cached_displays_[0].mirror_mode;
- if (!mode_info)
+ if (!mode_info) {
+ LOG(WARNING) << "No mirror mode when configuring display: "
+ << cached_displays_[0].display->ToString();
return false;
+ }
size = mode_info->size();
for (size_t i = 0; i < cached_displays_.size(); ++i) {
DisplayState* state = &cached_displays_[i];
new_mode[i] = display_power[i] ? state->mirror_mode : NULL;
- if (state->touch_device_id) {
- // CTM needs to be calculated if aspect preserving scaling is used.
- // Otherwise, assume it is full screen, and use identity CTM.
- if (state->mirror_mode != state->display->native_mode() &&
- state->display->is_aspect_preserving_scaling()) {
- state->transform = GetMirrorModeCTM(*state);
- mirrored_display_area_ratio_map_[state->touch_device_id] =
- GetMirroredDisplayAreaRatio(*state);
- }
- }
}
break;
}
// same desktop configuration can be restored when the displays are
// turned back on.
const DisplayMode* mode_info = cached_displays_[i].selected_mode;
- if (!mode_info)
+ if (!mode_info) {
+ LOG(WARNING) << "No selected mode when configuring display: "
+ << state->display->ToString();
return false;
+ }
size.set_width(std::max<int>(size.width(), mode_info->size().width()));
size.set_height(size.height() + (size.height() ? kVerticalGap : 0) +
mode_info->size().height());
}
-
- for (size_t i = 0; i < cached_displays_.size(); ++i) {
- DisplayState* state = &cached_displays_[i];
- if (state->touch_device_id)
- state->transform = GetExtendedModeCTM(*state, new_origins[i], size);
- }
break;
}
}
break;
}
- if (configure_succeeded) {
- if (state.touch_device_id)
- touchscreen_delegate_->ConfigureCTM(state.touch_device_id,
- state.transform);
- } else {
+ if (!configure_succeeded)
all_succeeded = false;
- }
// If we are trying to set mirror mode and one of the modesets fails,
// then the two monitors will be mis-matched. In this case, return
if (all_succeeded) {
display_state_ = display_state;
power_state_ = power_state;
+ framebuffer_size_ = size;
}
return all_succeeded;
}
return MULTIPLE_DISPLAY_STATE_INVALID;
}
-DisplayConfigurator::CoordinateTransformation
-DisplayConfigurator::GetMirrorModeCTM(const DisplayState& display_state) {
- CoordinateTransformation ctm; // Default to identity
- const DisplayMode* native_mode_info = display_state.display->native_mode();
- const DisplayMode* mirror_mode_info = display_state.mirror_mode;
-
- if (!native_mode_info || !mirror_mode_info ||
- native_mode_info->size().height() == 0 ||
- mirror_mode_info->size().height() == 0 ||
- native_mode_info->size().width() == 0 ||
- mirror_mode_info->size().width() == 0)
- return ctm;
-
- float native_mode_ar = static_cast<float>(native_mode_info->size().width()) /
- static_cast<float>(native_mode_info->size().height());
- float mirror_mode_ar = static_cast<float>(mirror_mode_info->size().width()) /
- static_cast<float>(mirror_mode_info->size().height());
-
- if (mirror_mode_ar > native_mode_ar) { // Letterboxing
- ctm.x_scale = 1.0;
- ctm.x_offset = 0.0;
- ctm.y_scale = mirror_mode_ar / native_mode_ar;
- ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5;
- return ctm;
- }
- if (native_mode_ar > mirror_mode_ar) { // Pillarboxing
- ctm.y_scale = 1.0;
- ctm.y_offset = 0.0;
- ctm.x_scale = native_mode_ar / mirror_mode_ar;
- ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5;
- return ctm;
- }
-
- return ctm; // Same aspect ratio - return identity
-}
-
-DisplayConfigurator::CoordinateTransformation
-DisplayConfigurator::GetExtendedModeCTM(const DisplayState& display_state,
- const gfx::Point& new_origin,
- const gfx::Size& framebuffer_size) {
- CoordinateTransformation ctm; // Default to identity
- const DisplayMode* mode_info = display_state.selected_mode;
- DCHECK(mode_info);
- if (!mode_info)
- return ctm;
- // An example of how to calculate the CTM.
- // Suppose we have 2 monitors, the first one has size 1366 x 768.
- // The second one has size 2560 x 1600
- // The total size of framebuffer is 2560 x 2428
- // where 2428 = 768 + 60 (hidden gap) + 1600
- // and the sceond monitor is translated to Point (0, 828) in the
- // framebuffer.
- // X will first map input event location to [0, 2560) x [0, 2428),
- // then apply CTM on it.
- // So to compute CTM, for monitor1, we have
- // x_scale = (1366 - 1) / (2560 - 1)
- // x_offset = 0 / (2560 - 1)
- // y_scale = (768 - 1) / (2428 - 1)
- // y_offset = 0 / (2428 -1)
- // For Monitor 2, we have
- // x_scale = (2560 - 1) / (2560 - 1)
- // x_offset = 0 / (2560 - 1)
- // y_scale = (1600 - 1) / (2428 - 1)
- // y_offset = 828 / (2428 -1)
- // See the unittest DisplayConfiguratorTest.CTMForMultiScreens.
- ctm.x_scale = static_cast<float>(mode_info->size().width() - 1) /
- (framebuffer_size.width() - 1);
- ctm.x_offset =
- static_cast<float>(new_origin.x()) / (framebuffer_size.width() - 1);
- ctm.y_scale = static_cast<float>(mode_info->size().height() - 1) /
- (framebuffer_size.height() - 1);
- ctm.y_offset =
- static_cast<float>(new_origin.y()) / (framebuffer_size.height() - 1);
- return ctm;
-}
-
-float DisplayConfigurator::GetMirroredDisplayAreaRatio(
- const DisplayState& display_state) {
- float area_ratio = 1.0f;
- const DisplayMode* native_mode_info = display_state.display->native_mode();
- const DisplayMode* mirror_mode_info = display_state.mirror_mode;
-
- if (!native_mode_info || !mirror_mode_info ||
- native_mode_info->size().height() == 0 ||
- mirror_mode_info->size().height() == 0 ||
- native_mode_info->size().width() == 0 ||
- mirror_mode_info->size().width() == 0)
- return area_ratio;
-
- float width_ratio = static_cast<float>(mirror_mode_info->size().width()) /
- static_cast<float>(native_mode_info->size().width());
- float height_ratio = static_cast<float>(mirror_mode_info->size().height()) /
- static_cast<float>(native_mode_info->size().height());
-
- area_ratio = width_ratio * height_ratio;
- return area_ratio;
-}
-
} // namespace ui