summaryrefslogtreecommitdiffstats
path: root/chromeos/display/output_configurator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromeos/display/output_configurator.cc')
-rw-r--r--chromeos/display/output_configurator.cc1080
1 files changed, 152 insertions, 928 deletions
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc
index fb1c9c0..a07a9de 100644
--- a/chromeos/display/output_configurator.cc
+++ b/chromeos/display/output_configurator.cc
@@ -4,107 +4,22 @@
#include "chromeos/display/output_configurator.h"
-#include <cmath>
-
-#include <X11/Xatom.h>
#include <X11/Xlib.h>
-#include <X11/extensions/dpms.h>
-#include <X11/extensions/XInput.h>
-#include <X11/extensions/XInput2.h>
#include <X11/extensions/Xrandr.h>
-// Xlib defines Status as int which causes our include of dbus/bus.h to fail
-// when it tries to name an enum Status. Thus, we need to undefine it (note
-// that this will cause a problem if code needs to use the Status type).
-// RootWindow causes similar problems in that there is a Chromium type with that
-// name.
-#undef Status
-#undef RootWindow
-
#include "base/bind.h"
#include "base/chromeos/chromeos_version.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
-#include "base/message_pump_aurax11.h"
-#include "base/metrics/histogram.h"
-#include "base/perftimer.h"
#include "base/strings/string_number_conversions.h"
#include "base/time.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_manager_client.h"
+#include "chromeos/display/real_output_configurator_delegate.h"
namespace chromeos {
-struct OutputSnapshot {
- RROutput output;
- RRCrtc crtc;
- RRMode current_mode;
- int height;
- int y;
- RRMode native_mode;
- RRMode mirror_mode;
- bool is_internal;
- bool is_aspect_preserving_scaling;
- int touch_device_id;
- int output_index;
-};
-
-struct CoordinateTransformation {
- // Initialize to identity transformation
- CoordinateTransformation()
- : x_scale(1.0),
- x_offset(0.0),
- y_scale(1.0),
- y_offset(0.0) {
- }
-
- float x_scale;
- float x_offset;
- float y_scale;
- float y_offset;
-};
-
-struct CrtcConfig {
- CrtcConfig()
- : crtc(None),
- x(0),
- y(0),
- mode(None),
- output(None) {}
-
- CrtcConfig(RRCrtc crtc, int x, int y, RRMode mode, RROutput output)
- : crtc(crtc),
- x(x),
- y(y),
- mode(mode),
- output(output) {}
-
- RRCrtc crtc;
- int x;
- int y;
- RRMode mode;
- RROutput output;
-};
-
-enum MirrorModeType {
- MIRROR_MODE_NONE,
- MIRROR_MODE_ASPECT_PRESERVING,
- MIRROR_MODE_FALLBACK,
- MIRROR_MODE_TYPE_COUNT
-};
-
namespace {
-// DPI measurements.
-const float kMmInInch = 25.4;
-const float kDpi96 = 96.0;
-const float kPixelsToMmScale = kMmInInch / kDpi96;
-
-// The DPI threshold to detech high density screen.
-// Higher DPI than this will use device_scale_factor=2
-// Should be kept in sync with display_change_observer_x11.cc
-const unsigned int kHighDensityDIPThreshold = 160;
-
// Prefixes for the built-in displays.
const char kInternal_LVDS[] = "LVDS";
const char kInternal_eDP[] = "eDP";
@@ -138,223 +53,8 @@ std::string DisplayPowerStateToString(DisplayPowerState state) {
}
}
-// TODO: Determine if we need to organize modes in a way which provides better
-// than O(n) lookup time. In many call sites, for example, the "next" mode is
-// typically what we are looking for so using this helper might be too
-// expensive.
-XRRModeInfo* ModeInfoForID(XRRScreenResources* screen, RRMode modeID) {
- XRRModeInfo* result = NULL;
- for (int i = 0; (i < screen->nmode) && (result == NULL); i++)
- if (modeID == screen->modes[i].id)
- result = &screen->modes[i];
-
- return result;
-}
-
-// A helper to call XRRSetCrtcConfig with the given options but some of our
-// default output count and rotation arguments.
-void ConfigureCrtc(Display* display,
- XRRScreenResources* screen,
- CrtcConfig* config) {
- VLOG(1) << "ConfigureCrtc crtc: " << config->crtc
- << ", mode " << config->mode
- << ", output " << config->output
- << ", x " << config->x
- << ", y " << config->y;
-
- const Rotation kRotate = RR_Rotate_0;
- RROutput* outputs = NULL;
- int num_outputs = 0;
-
- // Check the output and mode argument - if either are None, we should disable.
- if ((config->output != None) && (config->mode != None)) {
- outputs = &config->output;
- num_outputs = 1;
- }
-
- XRRSetCrtcConfig(display,
- screen,
- config->crtc,
- CurrentTime,
- config->x,
- config->y,
- config->mode,
- kRotate,
- outputs,
- num_outputs);
-}
-
-// Destroys unused Crtcs, and parks used Crtcs in a way which allows a
-// framebuffer resize. This is faster than turning them off, resizing,
-// then turning them back on.
-void DestroyUnusedCrtcs(Display* display,
- XRRScreenResources* screen,
- Window window,
- CrtcConfig* config1,
- CrtcConfig* config2) {
- // Setting the screen size will fail if any CRTC doesn't fit afterwards.
- // At the same time, turning CRTCs off and back on uses up a lot of time.
- // This function tries to be smart to avoid too many off/on cycles:
- // - We disable all the CRTCs we won't need after the FB resize.
- // - We set the new modes on CRTCs, if they fit in both the old and new
- // FBs, and park them at (0,0)
- // - We disable the CRTCs we will need but don't fit in the old FB. Those
- // will be reenabled after the resize.
- // We don't worry about the cached state of the outputs here since we are
- // not interested in the state we are setting - we just try to get the CRTCs
- // out of the way so we can rebuild the frame buffer.
- for (int i = 0; i < screen->ncrtc; ++i) {
- // Default config is to disable the crtcs.
- CrtcConfig config(screen->crtcs[i], 0, 0, None, None);
-
- // If we are going to use that CRTC later, prepare it now.
- if (config1 && screen->crtcs[i] == config1->crtc) {
- config = *config1;
- config.x = 0;
- config.y = 0;
- } else if (config2 && screen->crtcs[i] == config2->crtc) {
- config = *config2;
- config.x = 0;
- config.y = 0;
- }
-
- if (config.mode != None) {
- // In case our CRTC doesn't fit in our current framebuffer, disable it.
- // It'll get reenabled after we resize the framebuffer.
- XRRModeInfo* mode_info = ModeInfoForID(screen, config.mode);
- int current_width = DisplayWidth(display, DefaultScreen(display));
- int current_height = DisplayHeight(display, DefaultScreen(display));
- if (static_cast<int>(mode_info->width) > current_width ||
- static_cast<int>(mode_info->height) > current_height) {
- config.mode = None;
- config.output = None;
- }
- }
-
- ConfigureCrtc(display, screen, &config);
- }
-}
-
-// Called to set the frame buffer (underling XRR "screen") size. Has a
-// side-effect of disabling all CRTCs.
-void CreateFrameBuffer(Display* display,
- XRRScreenResources* screen,
- Window window,
- int width,
- int height,
- CrtcConfig* config1,
- CrtcConfig* config2) {
- TRACE_EVENT0("chromeos", "OutputConfigurator::CreateFrameBuffer");
-
- int current_width = DisplayWidth(display, DefaultScreen(display));
- int current_height = DisplayHeight(display, DefaultScreen(display));
- VLOG(1) << "CreateFrameBuffer " << width << " x " << height
- << " (current=" << current_width << " x " << current_height << ")";
- if (width == current_width && height == current_height)
- return;
-
- DestroyUnusedCrtcs(display, screen, window, config1, config2);
- int mm_width = width * kPixelsToMmScale;
- int mm_height = height * kPixelsToMmScale;
- XRRSetScreenSize(display, window, width, height, mm_width, mm_height);
-}
-
-// Configures X input's Coordinate Transformation Matrix property.
-// |display| is used to make X calls.
-// |touch_device_id| is X's id of touchscreen device to configure.
-// |ctm| contains the desired transformation parameters.
-// The offsets in it should be normalized,
-// so that 1 corresponds to x or y axis size for the respectful offset.
-void ConfigureCTM(Display* display,
- int touch_device_id,
- const CoordinateTransformation& ctm) {
- int ndevices;
- XIDeviceInfo* info = XIQueryDevice(display, touch_device_id, &ndevices);
- Atom prop = XInternAtom(display, "Coordinate Transformation Matrix", False);
- Atom float_atom = XInternAtom(display, "FLOAT", False);
- if (ndevices == 1 && prop != None && float_atom != None) {
- Atom type;
- int format;
- unsigned long num_items;
- unsigned long bytes_after;
- unsigned char* data = NULL;
- // Verify that the property exists with correct format, type, etc.
- int status = XIGetProperty(display,
- info->deviceid,
- prop,
- 0, // Irrelevant - we are not interested in data
- 0, // Irrelevant - we are not interested in data
- False, // Leave the property as is
- AnyPropertyType,
- &type,
- &format,
- &num_items,
- &bytes_after,
- &data);
- if (data)
- XFree(data);
- if (status == Success && type == float_atom && format == 32) {
- float value[3][3] = {
- { ctm.x_scale, 0.0, ctm.x_offset },
- { 0.0, ctm.y_scale, ctm.y_offset },
- { 0.0, 0.0, 1.0 }
- };
- XIChangeProperty(display,
- info->deviceid,
- prop,
- type,
- format,
- PropModeReplace,
- reinterpret_cast<unsigned char*>(value),
- 9);
- }
- }
- XIFreeDeviceInfo(info);
-}
-
-// Computes the relevant transformation for mirror mode.
-// |screen| is used to make X calls.
-// |output| is the output on which mirror mode is being applied.
-// Returns the transformation, which would be identity if computations fail.
-CoordinateTransformation GetMirrorModeCTM(XRRScreenResources* screen,
- const OutputSnapshot* output) {
- CoordinateTransformation ctm; // Default to identity
- XRRModeInfo* native_mode_info = ModeInfoForID(screen, output->native_mode);
- XRRModeInfo* mirror_mode_info = ModeInfoForID(screen, output->mirror_mode);
- if (native_mode_info == NULL || mirror_mode_info == NULL)
- return ctm;
-
- if (native_mode_info->height == 0 || mirror_mode_info->height == 0 ||
- native_mode_info->width == 0 || mirror_mode_info->width == 0)
- return ctm;
-
- float native_mode_ar = static_cast<float>(native_mode_info->width) /
- static_cast<float>(native_mode_info->height);
- float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) /
- static_cast<float>(mirror_mode_info->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
-}
-
-OutputState InferCurrentState(Display* display,
- XRRScreenResources* screen,
- const std::vector<OutputSnapshot>& outputs) {
- TRACE_EVENT0("chromeos", "OutputConfigurator::InferCurrentState");
+OutputState InferCurrentState(
+ const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
OutputState state = STATE_INVALID;
switch (outputs.size()) {
case 0:
@@ -367,7 +67,7 @@ OutputState InferCurrentState(Display* display,
RRMode primary_mode = outputs[0].current_mode;
RRMode secondary_mode = outputs[1].current_mode;
- if ((outputs[0].y == 0) && (outputs[1].y == 0)) {
+ if (outputs[0].y == 0 && outputs[1].y == 0) {
// Displays in the same spot so this is either mirror or unknown.
// Note that we should handle no configured CRTC as a "wildcard" since
// that allows us to preserve mirror mode state while power is switched
@@ -396,7 +96,7 @@ OutputState InferCurrentState(Display* display,
if (primary_native && secondary_native) {
// Just check the relative locations.
int secondary_offset = outputs[0].height + kVerticalGap;
- if ((outputs[0].y == 0) && (outputs[1].y == secondary_offset)) {
+ if (outputs[0].y == 0 && outputs[1].y == secondary_offset) {
state = STATE_DUAL_EXTENDED;
} else {
// Unexpected locations.
@@ -415,40 +115,10 @@ OutputState InferCurrentState(Display* display,
return state;
}
-RRCrtc GetNextCrtcAfter(Display* display,
- XRRScreenResources* screen,
- RROutput output,
- RRCrtc previous) {
- RRCrtc crtc = None;
- XRROutputInfo* output_info = XRRGetOutputInfo(display, screen, output);
-
- for (int i = 0; (i < output_info->ncrtc) && (crtc == None); ++i) {
- RRCrtc this_crtc = output_info->crtcs[i];
-
- if (previous != this_crtc)
- crtc = this_crtc;
- }
- XRRFreeOutputInfo(output_info);
- return crtc;
-}
-
-XRRScreenResources* GetScreenResourcesAndRecordUMA(Display* display,
- Window window) {
- // This call to XRRGetScreenResources is implicated in a hang bug so
- // instrument it to see its typical running time (crbug.com/134449).
- // TODO(disher): Remove these UMA calls once crbug.com/134449 is resolved.
- UMA_HISTOGRAM_BOOLEAN("Display.XRRGetScreenResources_completed", false);
- PerfTimer histogram_timer;
- XRRScreenResources* screen = XRRGetScreenResources(display, window);
- base::TimeDelta duration = histogram_timer.Elapsed();
- UMA_HISTOGRAM_BOOLEAN("Display.XRRGetScreenResources_completed", true);
- UMA_HISTOGRAM_LONG_TIMES("Display.XRRGetScreenResources_duration", duration);
- return screen;
-}
-
// Determine if there is an "internal" output and how many outputs are
// connected.
-bool IsProjecting(const std::vector<OutputSnapshot>& outputs) {
+bool IsProjecting(
+ const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
bool has_internal_output = false;
int connected_output_count = outputs.size();
for (size_t i = 0; i < outputs.size(); ++i)
@@ -459,152 +129,98 @@ bool IsProjecting(const std::vector<OutputSnapshot>& outputs) {
return has_internal_output && (connected_output_count > 1);
}
-// Returns whether the |output| is configured to preserve aspect when scaling.
-bool IsOutputAspectPreservingScaling(Display* display,
- RROutput output) {
- bool ret = false;
+} // namespace
- Atom scaling_prop = XInternAtom(display, "scaling mode", False);
- Atom full_aspect_atom = XInternAtom(display, "Full aspect", False);
- if (scaling_prop == None || full_aspect_atom == None)
- return false;
+OutputConfigurator::OutputSnapshot::OutputSnapshot()
+ : output(None),
+ crtc(None),
+ current_mode(None),
+ native_mode(None),
+ mirror_mode(None),
+ y(0),
+ height(0),
+ is_internal(false),
+ is_aspect_preserving_scaling(false),
+ touch_device_id(0) {}
+
+OutputConfigurator::CoordinateTransformation::CoordinateTransformation()
+ : x_scale(1.0),
+ x_offset(0.0),
+ y_scale(1.0),
+ y_offset(0.0) {}
+
+OutputConfigurator::CrtcConfig::CrtcConfig()
+ : crtc(None),
+ x(0),
+ y(0),
+ mode(None),
+ output(None) {}
- int nprop = 0;
- Atom* props = XRRListOutputProperties(display, output, &nprop);
- for (int j = 0; j < nprop && !ret; j++) {
- Atom prop = props[j];
- if (scaling_prop == prop) {
- unsigned char* values = NULL;
- int actual_format;
- unsigned long nitems;
- unsigned long bytes_after;
- Atom actual_type;
- int success;
-
- success = XRRGetOutputProperty(display,
- output,
- prop,
- 0,
- 100,
- False,
- False,
- AnyPropertyType,
- &actual_type,
- &actual_format,
- &nitems,
- &bytes_after,
- &values);
- if (success == Success && actual_type == XA_ATOM &&
- actual_format == 32 && nitems == 1) {
- Atom value = reinterpret_cast<Atom*>(values)[0];
- if (full_aspect_atom == value)
- ret = true;
- }
- if (values)
- XFree(values);
- }
- }
- if (props)
- XFree(props);
+OutputConfigurator::CrtcConfig::CrtcConfig(RRCrtc crtc,
+ int x, int y,
+ RRMode mode,
+ RROutput output)
+ : crtc(crtc),
+ x(x),
+ y(y),
+ mode(mode),
+ output(output) {}
- return ret;
+// static
+bool OutputConfigurator::IsInternalOutputName(const std::string& name) {
+ return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0;
}
-} // namespace
-
OutputConfigurator::OutputConfigurator()
- // If we aren't running on ChromeOS (like linux desktop),
- // don't try to configure display.
- : delegate_(NULL),
+ : state_controller_(NULL),
+ delegate_(new RealOutputConfiguratorDelegate()),
configure_display_(base::chromeos::IsRunningOnChromeOS()),
- is_panel_fitting_enabled_(false),
connected_output_count_(0),
xrandr_event_base_(0),
output_state_(STATE_INVALID),
- power_state_(DISPLAY_POWER_ALL_ON),
- mirror_mode_will_preserve_aspect_(false),
- mirror_mode_preserved_aspect_(false),
- last_enter_state_time_() {
+ power_state_(DISPLAY_POWER_ALL_ON) {
}
-OutputConfigurator::~OutputConfigurator() {
- RecordPreviousStateUMA();
-}
+OutputConfigurator::~OutputConfigurator() {}
void OutputConfigurator::Init(bool is_panel_fitting_enabled,
uint32 background_color_argb) {
- TRACE_EVENT0("chromeos", "OutputConfigurator::Init");
if (!configure_display_)
return;
- is_panel_fitting_enabled_ = is_panel_fitting_enabled;
// Cache the initial output state.
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
- CHECK(display != NULL);
- Window window = DefaultRootWindow(display);
- XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
- CHECK(screen != NULL);
- std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen);
- if (outputs.size() > 1 && background_color_argb) {
- // Configuring CRTCs/Framebuffer clears the boot screen image.
- // Set the same background color while configuring the
- // display to minimize the duration of black screen at boot
- // time. The background is filled with black later in
- // ash::DisplayManager.
- // crbug.com/171050.
- XSetWindowAttributes swa = {0};
- XColor color;
- Colormap colormap = DefaultColormap(display, 0);
- // XColor uses 16 bits per color.
- color.red = (background_color_argb & 0x00FF0000) >> 8;
- color.green = (background_color_argb & 0x0000FF00);
- color.blue = (background_color_argb & 0x000000FF) << 8;
- color.flags = DoRed | DoGreen | DoBlue;
- XAllocColor(display, colormap, &color);
- swa.background_pixel = color.pixel;
- XChangeWindowAttributes(display, window, CWBackPixel, &swa);
- XFreeColors(display, colormap, &color.pixel, 1, 0);
- }
- XRRFreeScreenResources(screen);
+ delegate_->SetPanelFittingEnabled(is_panel_fitting_enabled);
+ delegate_->GrabServer();
+ std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
+ if (outputs.size() > 1 && background_color_argb)
+ delegate_->SetBackgroundColor(background_color_argb);
+ delegate_->UngrabServer();
}
void OutputConfigurator::Start() {
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
- Window window = DefaultRootWindow(display);
-
- XGrabServer(display);
- XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
- CHECK(screen != NULL);
+ delegate_->GrabServer();
// Detect our initial state.
- std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen);
+ std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
connected_output_count_ = outputs.size();
- output_state_ = InferCurrentState(display, screen, outputs);
+ output_state_ = InferCurrentState(outputs);
// Ensure that we are in a supported state with all connected displays powered
// on.
- OutputState starting_state = GetNextState(display,
- screen,
- STATE_INVALID,
- outputs);
+ OutputState starting_state = GetNextState(outputs);
if (output_state_ != starting_state &&
- EnterState(display, screen, window, starting_state, power_state_,
- outputs)) {
+ EnterState(starting_state, power_state_, outputs)) {
output_state_ = starting_state;
}
bool is_projecting = IsProjecting(outputs);
- // Find xrandr_event_base_ since we need it to interpret events, later.
- int error_base_ignored = 0;
- XRRQueryExtension(display, &xrandr_event_base_, &error_base_ignored);
+ delegate_->InitXRandRExtension(&xrandr_event_base_);
// Force the DPMS on chrome startup as the driver doesn't always detect
// that all displays are on when signing out.
- CHECK(DPMSEnable(display));
- CHECK(DPMSForceLevel(display, DPMSModeOn));
+ delegate_->ForceDPMSOn();
// Relinquish X resources.
- XRRFreeScreenResources(screen);
- XUngrabServer(display);
+ delegate_->UngrabServer();
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
SetIsProjecting(is_projecting);
@@ -616,7 +232,6 @@ void OutputConfigurator::Stop() {
bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state,
int flags) {
- TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayPower");
VLOG(1) << "SetDisplayPower: power_state="
<< DisplayPowerStateToString(power_state) << " flags=" << flags;
@@ -625,37 +240,28 @@ bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state,
if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe))
return true;
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
- CHECK(display);
- XGrabServer(display);
- Window window = DefaultRootWindow(display);
- XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
- CHECK(screen);
- std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen);
+ delegate_->GrabServer();
+ std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
connected_output_count_ = outputs.size();
bool only_if_single_internal_display =
flags & kSetDisplayPowerOnlyIfSingleInternalDisplay;
bool single_internal_display = outputs.size() == 1 && outputs[0].is_internal;
if ((single_internal_display || !only_if_single_internal_display) &&
- EnterState(display, screen, window, output_state_, power_state,
- outputs)) {
+ EnterState(output_state_, power_state, outputs)) {
power_state_ = power_state;
if (power_state != DISPLAY_POWER_ALL_OFF) {
// Force the DPMS on since the driver doesn't always detect that it
// should turn on. This is needed when coming back from idle suspend.
- CHECK(DPMSEnable(display));
- CHECK(DPMSForceLevel(display, DPMSModeOn));
+ delegate_->ForceDPMSOn();
}
}
- XRRFreeScreenResources(screen);
- XUngrabServer(display);
+ delegate_->UngrabServer();
return true;
}
bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
- TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayMode");
if (output_state_ == STATE_INVALID ||
output_state_ == STATE_HEADLESS ||
output_state_ == STATE_SINGLE)
@@ -664,20 +270,12 @@ bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
if (output_state_ == new_state)
return true;
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
- CHECK(display != NULL);
- XGrabServer(display);
- Window window = DefaultRootWindow(display);
- XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
- CHECK(screen != NULL);
-
- std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen);
+ delegate_->GrabServer();
+ std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
connected_output_count_ = outputs.size();
- if (EnterState(display, screen, window, new_state, power_state_, outputs))
+ if (EnterState(new_state, power_state_, outputs))
output_state_ = new_state;
-
- XRRFreeScreenResources(screen);
- XUngrabServer(display);
+ delegate_->UngrabServer();
if (output_state_ == new_state) {
NotifyOnDisplayChanged();
@@ -689,9 +287,8 @@ bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
}
bool OutputConfigurator::Dispatch(const base::NativeEvent& event) {
- TRACE_EVENT0("chromeos", "OutputConfigurator::Dispatch");
if (event->type - xrandr_event_base_ == RRScreenChangeNotify)
- XRRUpdateConfiguration(event);
+ delegate_->UpdateXRandRConfiguration(event);
// Ignore this event if the Xrandr extension isn't supported, or
// the device is being shutdown.
if (!configure_display_ ||
@@ -727,31 +324,21 @@ bool OutputConfigurator::Dispatch(const base::NativeEvent& event) {
}
void OutputConfigurator::ConfigureOutputs() {
- TRACE_EVENT0("chromeos", "OutputConfigurator::ConfigureOutputs");
configure_timer_.reset();
- Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
- CHECK(display != NULL);
- XGrabServer(display);
- Window window = DefaultRootWindow(display);
- XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window);
- CHECK(screen != NULL);
-
- std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen);
+ delegate_->GrabServer();
+ std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
int new_output_count = outputs.size();
// Don't skip even if the output counts didn't change because
// a display might have been swapped during the suspend.
connected_output_count_ = new_output_count;
- OutputState new_state =
- GetNextState(display, screen, STATE_INVALID, outputs);
+ OutputState new_state = GetNextState(outputs);
// When a display was swapped, the state moves from
// STATE_DUAL_EXTENDED to STATE_DUAL_EXTENDED, so don't rely on
// the state chagne to tell if it was successful.
- bool success =
- EnterState(display, screen, window, new_state, power_state_, outputs);
+ bool success = EnterState(new_state, power_state_, outputs);
bool is_projecting = IsProjecting(outputs);
- XRRFreeScreenResources(screen);
- XUngrabServer(display);
+ delegate_->UngrabServer();
if (success) {
output_state_ = new_state;
@@ -772,11 +359,6 @@ void OutputConfigurator::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
-// static
-bool OutputConfigurator::IsInternalOutputName(const std::string& name) {
- return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0;
-}
-
void OutputConfigurator::SuspendDisplays() {
// If the display is off due to user inactivity and there's only a single
// internal display connected, switch to the all-on state before
@@ -791,7 +373,7 @@ void OutputConfigurator::SuspendDisplays() {
// We need to make sure that the monitor configuration we just did actually
// completes before we return, because otherwise the X message could be
// racing with the HandleSuspendReadiness message.
- XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), 0);
+ delegate_->SyncWithServer();
}
void OutputConfigurator::ResumeDisplays() {
@@ -801,341 +383,17 @@ void OutputConfigurator::ResumeDisplays() {
}
void OutputConfigurator::NotifyOnDisplayChanged() {
- TRACE_EVENT0("chromeos", "OutputConfigurator::NotifyOnDisplayChanged");
FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
}
-std::vector<OutputSnapshot> OutputConfigurator::GetDualOutputs(
- Display* display,
- XRRScreenResources* screen) {
- std::vector<OutputSnapshot> outputs;
- XRROutputInfo* one_info = NULL;
- XRROutputInfo* two_info = NULL;
-
- for (int i = 0; (i < screen->noutput) && (outputs.size() < 2); ++i) {
- RROutput this_id = screen->outputs[i];
- XRROutputInfo* output_info = XRRGetOutputInfo(display, screen, this_id);
- bool is_connected = (output_info->connection == RR_Connected);
-
- if (is_connected) {
- OutputSnapshot to_populate;
- to_populate.output_index = i;
-
- if (outputs.size() == 0) {
- one_info = output_info;
- } else {
- two_info = output_info;
- }
-
- to_populate.output = this_id;
- // Now, look up the corresponding CRTC and any related info.
- to_populate.crtc = output_info->crtc;
- if (None != to_populate.crtc) {
- XRRCrtcInfo* crtc_info =
- XRRGetCrtcInfo(display, screen, to_populate.crtc);
- to_populate.current_mode = crtc_info->mode;
- to_populate.height = crtc_info->height;
- to_populate.y = crtc_info->y;
- XRRFreeCrtcInfo(crtc_info);
- } else {
- to_populate.current_mode = 0;
- to_populate.height = 0;
- to_populate.y = 0;
- }
- // Find the native_mode and leave the mirror_mode for the pass after the
- // loop.
- to_populate.native_mode = GetOutputNativeMode(output_info);
- to_populate.mirror_mode = 0;
-
- // See if this output refers to an internal display.
- to_populate.is_internal = IsInternalOutput(output_info);
-
- to_populate.is_aspect_preserving_scaling =
- IsOutputAspectPreservingScaling(display, this_id);
- to_populate.touch_device_id = None;
-
- VLOG(1) << "Found display #" << outputs.size()
- << " with output " << (int)to_populate.output
- << " crtc " << (int)to_populate.crtc
- << " current mode " << (int)to_populate.current_mode;
- outputs.push_back(to_populate);
- } else {
- XRRFreeOutputInfo(output_info);
- }
- }
-
- if (outputs.size() == 2) {
- bool one_is_internal = IsInternalOutput(one_info);
- bool two_is_internal = IsInternalOutput(two_info);
- int internal_outputs = (one_is_internal ? 1 : 0) +
- (two_is_internal ? 1 : 0);
-
- DCHECK(internal_outputs < 2);
- LOG_IF(WARNING, internal_outputs == 2) << "Two internal outputs detected.";
-
- bool can_mirror = false;
-
- for (int attempt = 0; attempt < 2 && !can_mirror; attempt++) {
- // Try preserving external output's aspect ratio on the first attempt
- // If that fails, fall back to the highest matching resolution
- bool preserve_aspect = attempt == 0;
-
- if (internal_outputs == 1) {
- if (one_is_internal) {
- can_mirror = FindOrCreateMirrorMode(display,
- screen,
- one_info,
- two_info,
- outputs[0].output,
- is_panel_fitting_enabled_,
- preserve_aspect,
- &outputs[0].mirror_mode,
- &outputs[1].mirror_mode);
- } else { // if (two_is_internal)
- can_mirror = FindOrCreateMirrorMode(display,
- screen,
- two_info,
- one_info,
- outputs[1].output,
- is_panel_fitting_enabled_,
- preserve_aspect,
- &outputs[1].mirror_mode,
- &outputs[0].mirror_mode);
- }
- } else { // if (internal_outputs == 0)
- // No panel fitting for external outputs, so fall back to exact match
- can_mirror = FindOrCreateMirrorMode(display,
- screen,
- one_info,
- two_info,
- outputs[0].output,
- false,
- preserve_aspect,
- &outputs[0].mirror_mode,
- &outputs[1].mirror_mode);
- if (!can_mirror && preserve_aspect) {
- // FindOrCreateMirrorMode will try to preserve aspect ratio of
- // what it thinks is external display, so if it didn't succeed
- // with one, maybe it will succeed with the other.
- // This way we will have correct aspect ratio on at least one of them.
- can_mirror = FindOrCreateMirrorMode(display,
- screen,
- two_info,
- one_info,
- outputs[1].output,
- false,
- preserve_aspect,
- &outputs[1].mirror_mode,
- &outputs[0].mirror_mode);
- }
- }
-
- if (can_mirror) {
- if (preserve_aspect) {
- UMA_HISTOGRAM_ENUMERATION(
- "Display.GetDualOutputs.detected_mirror_mode",
- MIRROR_MODE_ASPECT_PRESERVING,
- MIRROR_MODE_TYPE_COUNT);
- } else {
- UMA_HISTOGRAM_ENUMERATION(
- "Display.GetDualOutputs.detected_mirror_mode",
- MIRROR_MODE_FALLBACK,
- MIRROR_MODE_TYPE_COUNT);
- }
- mirror_mode_will_preserve_aspect_ = preserve_aspect;
- }
- }
-
- if (!can_mirror) {
- // We can't mirror so set mirror_mode to None.
- outputs[0].mirror_mode = None;
- outputs[1].mirror_mode = None;
-
- UMA_HISTOGRAM_ENUMERATION(
- "Display.GetDualOutputs.detected_mirror_mode",
- MIRROR_MODE_NONE,
- MIRROR_MODE_TYPE_COUNT);
- mirror_mode_will_preserve_aspect_ = false;
- }
- }
-
- GetTouchscreens(display, screen, outputs);
-
- XRRFreeOutputInfo(one_info);
- XRRFreeOutputInfo(two_info);
- return outputs;
-}
-
-bool OutputConfigurator::FindOrCreateMirrorMode(Display* display,
- XRRScreenResources* screen,
- XRROutputInfo* internal_info,
- XRROutputInfo* external_info,
- RROutput internal_output_id,
- bool try_creating,
- bool preserve_aspect,
- RRMode* internal_mirror_mode,
- RRMode* external_mirror_mode) {
- RRMode internal_mode_id = GetOutputNativeMode(internal_info);
- RRMode external_mode_id = GetOutputNativeMode(external_info);
-
- if (internal_mode_id == None || external_mode_id == None)
- return false;
-
- XRRModeInfo* internal_native_mode = ModeInfoForID(screen, internal_mode_id);
- XRRModeInfo* external_native_mode = ModeInfoForID(screen, external_mode_id);
-
- // Check if some external output resolution can be mirrored on internal.
- // Prefer the modes in the order that X sorts them,
- // assuming this is the order in which they look better on the monitor.
- // If X's order is not satisfactory, we can either fix X's sorting,
- // or implement our sorting here.
- for (int i = 0; i < external_info->nmode; i++) {
- external_mode_id = external_info->modes[i];
- XRRModeInfo* external_mode = ModeInfoForID(screen, external_mode_id);
- bool is_native_aspect_ratio =
- external_native_mode->width * external_mode->height ==
- external_native_mode->height * external_mode->width;
- if (preserve_aspect && !is_native_aspect_ratio)
- continue; // Allow only aspect ratio preserving modes for mirroring
-
- // Try finding exact match
- for (int j = 0; j < internal_info->nmode; j++) {
- internal_mode_id = internal_info->modes[j];
- XRRModeInfo* internal_mode = ModeInfoForID(screen, internal_mode_id);
- bool is_internal_interlaced = internal_mode->modeFlags & RR_Interlace;
- bool is_external_interlaced = external_mode->modeFlags & RR_Interlace;
- if (internal_mode->width == external_mode->width &&
- internal_mode->height == external_mode->height &&
- is_internal_interlaced == is_external_interlaced) {
- *internal_mirror_mode = internal_mode_id;
- *external_mirror_mode = external_mode_id;
- return true; // Mirror mode found
- }
- }
-
- // Try to create a matching internal output mode by panel fitting
- if (try_creating) {
- // We can downscale by 1.125, and upscale indefinitely
- // Downscaling looks ugly, so, can fit == can upscale
- // Also, internal panels don't support fitting interlaced modes
- bool can_fit =
- internal_native_mode->width >= external_mode->width &&
- internal_native_mode->height >= external_mode->height &&
- !(external_mode->modeFlags & RR_Interlace);
- if (can_fit) {
- XRRAddOutputMode(display, internal_output_id, external_mode_id);
- *internal_mirror_mode = *external_mirror_mode = external_mode_id;
- return true; // Mirror mode created
- }
- }
- }
-
- return false;
-}
-
-void OutputConfigurator::GetTouchscreens(Display* display,
- XRRScreenResources* screen,
- std::vector<OutputSnapshot>& outputs) {
- int ndevices = 0;
- Atom valuator_x = XInternAtom(display, "Abs MT Position X", False);
- Atom valuator_y = XInternAtom(display, "Abs MT Position Y", False);
- if (valuator_x == None || valuator_y == None)
- return;
-
- XIDeviceInfo* info = XIQueryDevice(display, XIAllDevices, &ndevices);
- for (int i = 0; i < ndevices; i++) {
- if (!info[i].enabled || info[i].use != XIFloatingSlave)
- continue; // Assume all touchscreens are floating slaves
-
- double width = -1.0;
- double height = -1.0;
- bool is_direct_touch = false;
-
- for (int j = 0; j < info[i].num_classes; j++) {
- XIAnyClassInfo* class_info = info[i].classes[j];
-
- if (class_info->type == XIValuatorClass) {
- XIValuatorClassInfo* valuator_info =
- reinterpret_cast<XIValuatorClassInfo*>(class_info);
-
- if (valuator_x == valuator_info->label) {
- // Ignore X axis valuator with unexpected properties
- if (valuator_info->number == 0 && valuator_info->mode == Absolute &&
- valuator_info->min == 0.0) {
- width = valuator_info->max;
- }
- } else if (valuator_y == valuator_info->label) {
- // Ignore Y axis valuator with unexpected properties
- if (valuator_info->number == 1 && valuator_info->mode == Absolute &&
- valuator_info->min == 0.0) {
- height = valuator_info->max;
- }
- }
- }
-#if defined(USE_XI2_MT)
- if (class_info->type == XITouchClass) {
- XITouchClassInfo* touch_info =
- reinterpret_cast<XITouchClassInfo*>(class_info);
- is_direct_touch = touch_info->mode == XIDirectTouch;
- }
-#endif
- }
-
- // Touchscreens should have absolute X and Y axes,
- // and be direct touch devices.
- if (width > 0.0 && height > 0.0 && is_direct_touch) {
- size_t k = 0;
- for (; k < outputs.size(); k++) {
- if (outputs[k].native_mode == None ||
- outputs[k].touch_device_id != None)
- continue;
- XRRModeInfo* native_mode = ModeInfoForID(screen,
- outputs[k].native_mode);
- if (native_mode == NULL)
- continue;
-
- // Allow 1 pixel difference between screen and touchscreen resolutions.
- // Because in some cases for monitor resolution 1024x768 touchscreen's
- // resolution would be 1024x768, but for some 1023x767.
- // It really depends on touchscreen's firmware configuration.
- if (std::abs(native_mode->width - width) <= 1.0 &&
- std::abs(native_mode->height - height) <= 1.0) {
- outputs[k].touch_device_id = info[i].deviceid;
-
- VLOG(1) << "Found touchscreen for output #" << k
- << " id " << outputs[k].touch_device_id
- << " width " << width
- << " height " << height;
- break;
- }
- }
-
- VLOG_IF(1, k == outputs.size())
- << "No matching output - ignoring touchscreen id " << info[i].deviceid
- << " width " << width
- << " height " << height;
- }
- }
-
- XIFreeDeviceInfo(info);
-}
-
bool OutputConfigurator::EnterState(
- Display* display,
- XRRScreenResources* screen,
- Window window,
OutputState output_state,
DisplayPowerState power_state,
const std::vector<OutputSnapshot>& outputs) {
- TRACE_EVENT0("chromeos", "OutputConfigurator::EnterState");
-
- std::vector<RRCrtc> crtcs(outputs.size());
std::vector<bool> output_power(outputs.size());
bool all_outputs_off = true;
- RRCrtc prev_crtc = None;
- for (size_t i = 0; i < outputs.size(); prev_crtc = crtcs[i], ++i) {
- crtcs[i] = GetNextCrtcAfter(display, screen, outputs[i].output, prev_crtc);
+ for (size_t i = 0; i < outputs.size(); ++i) {
output_power[i] = power_state == DISPLAY_POWER_ALL_ON ||
(power_state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON &&
!outputs[i].is_internal) ||
@@ -1151,71 +409,69 @@ bool OutputConfigurator::EnterState(
break;
case 1: {
// Re-allocate the framebuffer to fit.
- XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].native_mode);
- if (!mode_info) {
- UMA_HISTOGRAM_COUNTS("Display.EnterState.single_failures", 1);
+ int width = 0, height = 0;
+ if (!delegate_->GetModeDetails(
+ outputs[0].native_mode, &width, &height, NULL)) {
return false;
}
- CrtcConfig config(crtcs[0], 0, 0,
+ CrtcConfig config(outputs[0].crtc, 0, 0,
output_power[0] ? outputs[0].native_mode : None,
outputs[0].output);
- CreateFrameBuffer(display, screen, window, mode_info->width,
- mode_info->height, &config, NULL);
- ConfigureCrtc(display, screen, &config);
+ delegate_->CreateFrameBuffer(width, height, &config, NULL);
+ delegate_->ConfigureCrtc(&config);
if (outputs[0].touch_device_id) {
// Restore identity transformation for single monitor in native mode.
- ConfigureCTM(display, outputs[0].touch_device_id,
- CoordinateTransformation());
+ delegate_->ConfigureCTM(outputs[0].touch_device_id,
+ CoordinateTransformation());
}
break;
}
case 2: {
if (output_state == STATE_DUAL_MIRROR) {
- XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].mirror_mode);
- if (!mode_info) {
- UMA_HISTOGRAM_COUNTS("Display.EnterState.mirror_failures", 1);
+ int width = 0, height = 0;
+ if (!delegate_->GetModeDetails(
+ outputs[0].mirror_mode, &width, &height, NULL)) {
return false;
}
std::vector<CrtcConfig> configs(outputs.size());
for (size_t i = 0; i < outputs.size(); ++i) {
configs[i] = CrtcConfig(
- crtcs[i], 0, 0,
+ outputs[i].crtc, 0, 0,
output_power[i] ? outputs[i].mirror_mode : None,
outputs[i].output);
}
- CreateFrameBuffer(display, screen, window, mode_info->width,
- mode_info->height, &configs[0], &configs[1]);
+ delegate_->CreateFrameBuffer(width, height, &configs[0], &configs[1]);
for (size_t i = 0; i < outputs.size(); ++i) {
- ConfigureCrtc(display, screen, &configs[i]);
+ delegate_->ConfigureCrtc(&configs[i]);
if (outputs[i].touch_device_id) {
CoordinateTransformation ctm;
// CTM needs to be calculated if aspect preserving scaling is used.
// Otherwise, assume it is full screen, and use identity CTM.
if (outputs[i].mirror_mode != outputs[i].native_mode &&
outputs[i].is_aspect_preserving_scaling) {
- ctm = GetMirrorModeCTM(screen, &outputs[i]);
+ ctm = GetMirrorModeCTM(&outputs[i]);
}
- ConfigureCTM(display, outputs[i].touch_device_id, ctm);
+ delegate_->ConfigureCTM(outputs[i].touch_device_id, ctm);
}
}
} else { // STATE_DUAL_EXTENDED
- std::vector<XRRModeInfo*> mode_infos(outputs.size());
+ // Pairs are [width, height] corresponding to the given output's mode.
+ std::vector<std::pair<int, int> > mode_sizes(outputs.size());
std::vector<CrtcConfig> configs(outputs.size());
int width = 0, height = 0;
for (size_t i = 0; i < outputs.size(); ++i) {
- mode_infos[i] = ModeInfoForID(screen, outputs[i].native_mode);
- if (!mode_infos[i]) {
- UMA_HISTOGRAM_COUNTS("Display.EnterState.dual_failures", 1);
+ if (!delegate_->GetModeDetails(outputs[i].native_mode,
+ &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) {
return false;
}
configs[i] = CrtcConfig(
- crtcs[i], 0, height,
+ outputs[i].crtc, 0, height,
output_power[i] ? outputs[i].native_mode : None,
outputs[i].output);
@@ -1223,23 +479,22 @@ bool OutputConfigurator::EnterState(
// desktop configuration can be restored when the outputs are
// turned back on.
if (output_power[i] || all_outputs_off) {
- width = std::max<int>(width, mode_infos[i]->width);
- height += (height ? kVerticalGap : 0) + mode_infos[i]->height;
+ width = std::max<int>(width, mode_sizes[i].first);
+ height += (height ? kVerticalGap : 0) + mode_sizes[i].second;
}
}
- CreateFrameBuffer(display, screen, window, width, height,
- &configs[0], &configs[1]);
+ delegate_->CreateFrameBuffer(width, height, &configs[0], &configs[1]);
for (size_t i = 0; i < outputs.size(); ++i) {
- ConfigureCrtc(display, screen, &configs[i]);
+ delegate_->ConfigureCrtc(&configs[i]);
if (outputs[i].touch_device_id) {
CoordinateTransformation ctm;
- ctm.x_scale = static_cast<float>(mode_infos[i]->width) / width;
+ ctm.x_scale = static_cast<float>(mode_sizes[i].first) / width;
ctm.x_offset = static_cast<float>(configs[i].x) / width;
- ctm.y_scale = static_cast<float>(mode_infos[i]->height) / height;
+ ctm.y_scale = static_cast<float>(mode_sizes[i].second) / height;
ctm.y_offset = static_cast<float>(configs[i].y) / height;
- ConfigureCTM(display, outputs[i].touch_device_id, ctm);
+ delegate_->ConfigureCTM(outputs[i].touch_device_id, ctm);
}
}
}
@@ -1249,99 +504,68 @@ bool OutputConfigurator::EnterState(
NOTREACHED() << "Got " << outputs.size() << " outputs";
}
- RecordPreviousStateUMA();
return true;
}
-void OutputConfigurator::RecordPreviousStateUMA() {
- base::TimeDelta duration = base::TimeTicks::Now() - last_enter_state_time_;
-
- // |output_state_| can be used for the state being left,
- // since RecordPreviousStateUMA is called from EnterState,
- // and |output_state_| is always updated after EnterState is called.
- switch (output_state_) {
- case STATE_SINGLE:
- UMA_HISTOGRAM_LONG_TIMES("Display.EnterState.single_duration", duration);
- break;
- case STATE_DUAL_MIRROR:
- if (mirror_mode_preserved_aspect_)
- UMA_HISTOGRAM_LONG_TIMES("Display.EnterState.mirror_aspect_duration",
- duration);
- else
- UMA_HISTOGRAM_LONG_TIMES("Display.EnterState.mirror_fallback_duration",
- duration);
- break;
- case STATE_DUAL_EXTENDED:
- UMA_HISTOGRAM_LONG_TIMES("Display.EnterState.dual_primary_duration",
- duration);
- break;
- default:
- break;
- }
-
- mirror_mode_preserved_aspect_ = mirror_mode_will_preserve_aspect_;
- last_enter_state_time_ = base::TimeTicks::Now();
-}
-
OutputState OutputConfigurator::GetNextState(
- Display* display,
- XRRScreenResources* screen,
- OutputState current_state,
const std::vector<OutputSnapshot>& output_snapshots) const {
- TRACE_EVENT0("chromeos", "OutputConfigurator::GetNextState");
- OutputState state = STATE_INVALID;
-
switch (output_snapshots.size()) {
case 0:
- state = STATE_HEADLESS;
- break;
+ return STATE_HEADLESS;
case 1:
- state = STATE_SINGLE;
- break;
+ return STATE_SINGLE;
case 2: {
- bool mirror_supported = (0 != output_snapshots[0].mirror_mode) &&
- (0 != output_snapshots[1].mirror_mode);
- switch (current_state) {
- case STATE_DUAL_EXTENDED:
- state =
- mirror_supported ? STATE_DUAL_MIRROR : STATE_DUAL_EXTENDED;
- break;
- case STATE_DUAL_MIRROR:
- state = STATE_DUAL_EXTENDED;
- break;
- case STATE_INVALID: {
- std::vector<OutputInfo> outputs;
- for (size_t i = 0; i < output_snapshots.size(); ++i) {
- outputs.push_back(OutputInfo());
- outputs[i].output = output_snapshots[i].output;
- outputs[i].output_index = output_snapshots[i].output_index;
- }
- state = delegate_->GetStateForOutputs(outputs);
- break;
- }
- default:
- state = STATE_DUAL_EXTENDED;
+ std::vector<OutputInfo> outputs;
+ for (size_t i = 0; i < output_snapshots.size(); ++i) {
+ outputs.push_back(OutputInfo());
+ outputs[i].output = output_snapshots[i].output;
+ outputs[i].output_index = i;
}
- break;
+ return state_controller_->GetStateForOutputs(outputs);
}
default:
- CHECK(false);
+ NOTREACHED();
}
- return state;
+ return STATE_INVALID;
}
-// static
-bool OutputConfigurator::IsInternalOutput(const XRROutputInfo* output_info) {
- return IsInternalOutputName(std::string(output_info->name));
-}
+OutputConfigurator::CoordinateTransformation
+OutputConfigurator::GetMirrorModeCTM(
+ const OutputConfigurator::OutputSnapshot* output) {
+ CoordinateTransformation ctm; // Default to identity
+ int native_mode_width = 0, native_mode_height = 0;
+ int mirror_mode_width = 0, mirror_mode_height = 0;
+ if (!delegate_->GetModeDetails(output->native_mode,
+ &native_mode_width, &native_mode_height, NULL) ||
+ !delegate_->GetModeDetails(output->mirror_mode,
+ &mirror_mode_width, &mirror_mode_height, NULL))
+ return ctm;
-// static
-RRMode OutputConfigurator::GetOutputNativeMode(
- const XRROutputInfo* output_info) {
- if (output_info->nmode <= 0)
- return None;
+ if (native_mode_height == 0 || mirror_mode_height == 0 ||
+ native_mode_width == 0 || mirror_mode_width == 0)
+ return ctm;
+
+ float native_mode_ar = static_cast<float>(native_mode_width) /
+ static_cast<float>(native_mode_height);
+ float mirror_mode_ar = static_cast<float>(mirror_mode_width) /
+ static_cast<float>(mirror_mode_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 output_info->modes[0];
+ return ctm; // Same aspect ratio - return identity
}
} // namespace chromeos