|  | // 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/display/chromeos/x11/native_display_delegate_x11.h" | 
|  |  | 
|  | #include <X11/Xatom.h> | 
|  | #include <X11/Xlib.h> | 
|  | #include <X11/extensions/dpms.h> | 
|  | #include <X11/extensions/Xrandr.h> | 
|  | #include <X11/extensions/XInput2.h> | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "base/stl_util.h" | 
|  | #include "ui/display/chromeos/x11/display_mode_x11.h" | 
|  | #include "ui/display/chromeos/x11/display_snapshot_x11.h" | 
|  | #include "ui/display/chromeos/x11/display_util_x11.h" | 
|  | #include "ui/display/chromeos/x11/native_display_event_dispatcher_x11.h" | 
|  | #include "ui/display/types/native_display_observer.h" | 
|  | #include "ui/display/util/x11/edid_parser_x11.h" | 
|  | #include "ui/events/platform/platform_event_source.h" | 
|  | #include "ui/gfx/geometry/rect.h" | 
|  | #include "ui/gfx/x/x11_error_tracker.h" | 
|  | #include "ui/gfx/x/x11_types.h" | 
|  |  | 
|  | namespace ui { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // DPI measurements. | 
|  | const float kMmInInch = 25.4; | 
|  | const float kDpi96 = 96.0; | 
|  | const float kPixelsToMmScale = kMmInInch / kDpi96; | 
|  |  | 
|  | const char kContentProtectionAtomName[] = "Content Protection"; | 
|  | const char kProtectionUndesiredAtomName[] = "Undesired"; | 
|  | const char kProtectionDesiredAtomName[] = "Desired"; | 
|  | const char kProtectionEnabledAtomName[] = "Enabled"; | 
|  |  | 
|  | RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { | 
|  | return output_info->nmode > 0 ? output_info->modes[0] : None; | 
|  | } | 
|  |  | 
|  | XRRCrtcGamma* ResampleGammaRamp(XRRCrtcGamma* gamma_ramp, int gamma_ramp_size) { | 
|  | if (gamma_ramp->size == gamma_ramp_size) | 
|  | return gamma_ramp; | 
|  |  | 
|  | #define RESAMPLE(array, i, r) \ | 
|  | array[i] + (array[i + 1] - array[i]) * r / gamma_ramp_size | 
|  |  | 
|  | XRRCrtcGamma* resampled = XRRAllocGamma(gamma_ramp_size); | 
|  | for (int i = 0; i < gamma_ramp_size; ++i) { | 
|  | int base_index = gamma_ramp->size * i / gamma_ramp_size; | 
|  | int remaining = gamma_ramp->size * i % gamma_ramp_size; | 
|  | if (base_index < gamma_ramp->size - 1) { | 
|  | resampled->red[i] = RESAMPLE(gamma_ramp->red, base_index, remaining); | 
|  | resampled->green[i] = RESAMPLE(gamma_ramp->green, base_index, remaining); | 
|  | resampled->blue[i] = RESAMPLE(gamma_ramp->blue, base_index, remaining); | 
|  | } else { | 
|  | resampled->red[i] = gamma_ramp->red[gamma_ramp->size - 1]; | 
|  | resampled->green[i] = gamma_ramp->green[gamma_ramp->size - 1]; | 
|  | resampled->blue[i] = gamma_ramp->blue[gamma_ramp->size - 1]; | 
|  | } | 
|  | } | 
|  |  | 
|  | #undef RESAMPLE | 
|  | XRRFreeGamma(gamma_ramp); | 
|  | return resampled; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // NativeDisplayDelegateX11::HelperDelegateX11 | 
|  |  | 
|  | class NativeDisplayDelegateX11::HelperDelegateX11 | 
|  | : public NativeDisplayDelegateX11::HelperDelegate { | 
|  | public: | 
|  | HelperDelegateX11(NativeDisplayDelegateX11* delegate) : delegate_(delegate) {} | 
|  | virtual ~HelperDelegateX11() {} | 
|  |  | 
|  | // NativeDisplayDelegateX11::HelperDelegate overrides: | 
|  | virtual void UpdateXRandRConfiguration(const base::NativeEvent& event) | 
|  | override { | 
|  | XRRUpdateConfiguration(event); | 
|  | } | 
|  | virtual const std::vector<DisplaySnapshot*>& GetCachedDisplays() const | 
|  | override { | 
|  | return delegate_->cached_outputs_.get(); | 
|  | } | 
|  | virtual void NotifyDisplayObservers() override { | 
|  | FOR_EACH_OBSERVER( | 
|  | NativeDisplayObserver, delegate_->observers_, OnConfigurationChanged()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | NativeDisplayDelegateX11* delegate_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(HelperDelegateX11); | 
|  | }; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // NativeDisplayDelegateX11 implementation: | 
|  |  | 
|  | NativeDisplayDelegateX11::NativeDisplayDelegateX11() | 
|  | : display_(gfx::GetXDisplay()), | 
|  | window_(DefaultRootWindow(display_)), | 
|  | screen_(NULL), | 
|  | background_color_argb_(0) {} | 
|  |  | 
|  | NativeDisplayDelegateX11::~NativeDisplayDelegateX11() { | 
|  | if (ui::PlatformEventSource::GetInstance()) { | 
|  | ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher( | 
|  | platform_event_dispatcher_.get()); | 
|  | } | 
|  |  | 
|  | STLDeleteContainerPairSecondPointers(modes_.begin(), modes_.end()); | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::Initialize() { | 
|  | int error_base_ignored = 0; | 
|  | int xrandr_event_base = 0; | 
|  | XRRQueryExtension(display_, &xrandr_event_base, &error_base_ignored); | 
|  |  | 
|  | helper_delegate_.reset(new HelperDelegateX11(this)); | 
|  | platform_event_dispatcher_.reset(new NativeDisplayEventDispatcherX11( | 
|  | helper_delegate_.get(), xrandr_event_base)); | 
|  |  | 
|  | if (ui::PlatformEventSource::GetInstance()) { | 
|  | ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher( | 
|  | platform_event_dispatcher_.get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::GrabServer() { | 
|  | CHECK(!screen_) << "Server already grabbed"; | 
|  | XGrabServer(display_); | 
|  | screen_ = XRRGetScreenResources(display_, window_); | 
|  | CHECK(screen_); | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::UngrabServer() { | 
|  | CHECK(screen_) << "Server not grabbed"; | 
|  | XRRFreeScreenResources(screen_); | 
|  | screen_ = NULL; | 
|  | XUngrabServer(display_); | 
|  | // crbug.com/366125 | 
|  | XFlush(display_); | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::SyncWithServer() { XSync(display_, 0); } | 
|  |  | 
|  | void NativeDisplayDelegateX11::SetBackgroundColor(uint32_t color_argb) { | 
|  | background_color_argb_ = color_argb; | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::ForceDPMSOn() { | 
|  | CHECK(DPMSEnable(display_)); | 
|  | CHECK(DPMSForceLevel(display_, DPMSModeOn)); | 
|  | } | 
|  |  | 
|  | std::vector<DisplaySnapshot*> NativeDisplayDelegateX11::GetDisplays() { | 
|  | CHECK(screen_) << "Server not grabbed"; | 
|  |  | 
|  | cached_outputs_.clear(); | 
|  | RRCrtc last_used_crtc = None; | 
|  |  | 
|  | InitModes(); | 
|  | for (int i = 0; i < screen_->noutput && cached_outputs_.size() < 2; ++i) { | 
|  | RROutput output_id = screen_->outputs[i]; | 
|  | XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id); | 
|  | if (output_info->connection == RR_Connected) { | 
|  | DisplaySnapshotX11* output = | 
|  | InitDisplaySnapshot(output_id, output_info, &last_used_crtc, i); | 
|  | cached_outputs_.push_back(output); | 
|  | } | 
|  | XRRFreeOutputInfo(output_info); | 
|  | } | 
|  |  | 
|  | return cached_outputs_.get(); | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::AddMode(const DisplaySnapshot& output, | 
|  | const DisplayMode* mode) { | 
|  | CHECK(screen_) << "Server not grabbed"; | 
|  | CHECK(mode) << "Must add valid mode"; | 
|  |  | 
|  | const DisplaySnapshotX11& x11_output = | 
|  | static_cast<const DisplaySnapshotX11&>(output); | 
|  | RRMode mode_id = static_cast<const DisplayModeX11*>(mode)->mode_id(); | 
|  |  | 
|  | VLOG(1) << "AddDisplayMode: output=" << x11_output.output() | 
|  | << " mode=" << mode_id; | 
|  | XRRAddOutputMode(display_, x11_output.output(), mode_id); | 
|  | } | 
|  |  | 
|  | bool NativeDisplayDelegateX11::Configure(const DisplaySnapshot& output, | 
|  | const DisplayMode* mode, | 
|  | const gfx::Point& origin) { | 
|  | const DisplaySnapshotX11& x11_output = | 
|  | static_cast<const DisplaySnapshotX11&>(output); | 
|  | RRMode mode_id = None; | 
|  | if (mode) | 
|  | mode_id = static_cast<const DisplayModeX11*>(mode)->mode_id(); | 
|  |  | 
|  | return ConfigureCrtc( | 
|  | x11_output.crtc(), mode_id, x11_output.output(), origin.x(), origin.y()); | 
|  | } | 
|  |  | 
|  | bool NativeDisplayDelegateX11::ConfigureCrtc(RRCrtc crtc, | 
|  | RRMode mode, | 
|  | RROutput output, | 
|  | int x, | 
|  | int y) { | 
|  | CHECK(screen_) << "Server not grabbed"; | 
|  | VLOG(1) << "ConfigureCrtc: crtc=" << crtc << " mode=" << mode | 
|  | << " output=" << output << " x=" << x << " y=" << y; | 
|  | // Xrandr.h is full of lies. XRRSetCrtcConfig() is defined as returning a | 
|  | // Status, which is typically 0 for failure and 1 for success. In | 
|  | // actuality it returns a RRCONFIGSTATUS, which uses 0 for success. | 
|  | if (XRRSetCrtcConfig(display_, | 
|  | screen_, | 
|  | crtc, | 
|  | CurrentTime, | 
|  | x, | 
|  | y, | 
|  | mode, | 
|  | RR_Rotate_0, | 
|  | (output && mode) ? &output : NULL, | 
|  | (output && mode) ? 1 : 0) != RRSetConfigSuccess) { | 
|  | LOG(WARNING) << "Unable to configure CRTC " << crtc << ":" | 
|  | << " mode=" << mode << " output=" << output << " x=" << x | 
|  | << " y=" << y; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::CreateFrameBuffer(const gfx::Size& size) { | 
|  | CHECK(screen_) << "Server not grabbed"; | 
|  | gfx::Size current_screen_size( | 
|  | DisplayWidth(display_, DefaultScreen(display_)), | 
|  | DisplayHeight(display_, DefaultScreen(display_))); | 
|  |  | 
|  | VLOG(1) << "CreateFrameBuffer: new=" << size.ToString() | 
|  | << " current=" << current_screen_size.ToString(); | 
|  |  | 
|  | DestroyUnusedCrtcs(); | 
|  |  | 
|  | if (size == current_screen_size) | 
|  | return; | 
|  |  | 
|  | gfx::Size min_screen_size(current_screen_size); | 
|  | min_screen_size.SetToMin(size); | 
|  | UpdateCrtcsForNewFramebuffer(min_screen_size); | 
|  |  | 
|  | int mm_width = size.width() * kPixelsToMmScale; | 
|  | int mm_height = size.height() * kPixelsToMmScale; | 
|  | XRRSetScreenSize( | 
|  | display_, window_, size.width(), size.height(), mm_width, mm_height); | 
|  | // We don't wait for root window resize, therefore this end up with drawing | 
|  | // in the old window size, which we care during the boot. | 
|  | DrawBackground(); | 
|  |  | 
|  | // Don't redraw the background upon framebuffer change again. This should | 
|  | // happen only once after boot. | 
|  | background_color_argb_ = 0; | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::AddObserver(NativeDisplayObserver* observer) { | 
|  | observers_.AddObserver(observer); | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::RemoveObserver(NativeDisplayObserver* observer) { | 
|  | observers_.RemoveObserver(observer); | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::InitModes() { | 
|  | CHECK(screen_) << "Server not grabbed"; | 
|  |  | 
|  | STLDeleteContainerPairSecondPointers(modes_.begin(), modes_.end()); | 
|  | modes_.clear(); | 
|  |  | 
|  | for (int i = 0; i < screen_->nmode; ++i) { | 
|  | const XRRModeInfo& info = screen_->modes[i]; | 
|  | float refresh_rate = 0.0f; | 
|  | if (info.hTotal && info.vTotal) { | 
|  | refresh_rate = | 
|  | static_cast<float>(info.dotClock) / | 
|  | (static_cast<float>(info.hTotal) * static_cast<float>(info.vTotal)); | 
|  | } | 
|  |  | 
|  | modes_.insert( | 
|  | std::make_pair(info.id, | 
|  | new DisplayModeX11(gfx::Size(info.width, info.height), | 
|  | info.modeFlags & RR_Interlace, | 
|  | refresh_rate, | 
|  | info.id))); | 
|  | } | 
|  | } | 
|  |  | 
|  | DisplaySnapshotX11* NativeDisplayDelegateX11::InitDisplaySnapshot( | 
|  | RROutput output, | 
|  | XRROutputInfo* info, | 
|  | RRCrtc* last_used_crtc, | 
|  | int index) { | 
|  | int64_t display_id = 0; | 
|  | bool has_display_id = GetDisplayId( | 
|  | output, static_cast<uint8_t>(index), &display_id); | 
|  |  | 
|  | bool has_overscan = false; | 
|  | GetOutputOverscanFlag(output, &has_overscan); | 
|  |  | 
|  | DisplayConnectionType type = GetDisplayConnectionTypeFromName(info->name); | 
|  | if (type == DISPLAY_CONNECTION_TYPE_UNKNOWN) | 
|  | LOG(ERROR) << "Unknown link type: " << info->name; | 
|  |  | 
|  | // Use the index as a valid display ID even if the internal | 
|  | // display doesn't have valid EDID because the index | 
|  | // will never change. | 
|  | if (!has_display_id) { | 
|  | if (type == DISPLAY_CONNECTION_TYPE_INTERNAL) | 
|  | has_display_id = true; | 
|  |  | 
|  | // Fallback to output index. | 
|  | display_id = index; | 
|  | } | 
|  |  | 
|  | RRMode native_mode_id = GetOutputNativeMode(info); | 
|  | RRMode current_mode_id = None; | 
|  | gfx::Point origin; | 
|  | if (info->crtc) { | 
|  | XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display_, screen_, info->crtc); | 
|  | current_mode_id = crtc_info->mode; | 
|  | origin.SetPoint(crtc_info->x, crtc_info->y); | 
|  | XRRFreeCrtcInfo(crtc_info); | 
|  | } | 
|  |  | 
|  | RRCrtc crtc = None; | 
|  | // Assign a CRTC that isn't already in use. | 
|  | for (int i = 0; i < info->ncrtc; ++i) { | 
|  | if (info->crtcs[i] != *last_used_crtc) { | 
|  | crtc = info->crtcs[i]; | 
|  | *last_used_crtc = crtc; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | const DisplayMode* current_mode = NULL; | 
|  | const DisplayMode* native_mode = NULL; | 
|  | std::vector<const DisplayMode*> display_modes; | 
|  |  | 
|  | for (int i = 0; i < info->nmode; ++i) { | 
|  | const RRMode mode = info->modes[i]; | 
|  | if (modes_.find(mode) != modes_.end()) { | 
|  | display_modes.push_back(modes_.at(mode)); | 
|  |  | 
|  | if (mode == current_mode_id) | 
|  | current_mode = display_modes.back(); | 
|  | if (mode == native_mode_id) | 
|  | native_mode = display_modes.back(); | 
|  | } else { | 
|  | LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; | 
|  | } | 
|  | } | 
|  |  | 
|  | DisplaySnapshotX11* display_snapshot = | 
|  | new DisplaySnapshotX11(display_id, | 
|  | has_display_id, | 
|  | origin, | 
|  | gfx::Size(info->mm_width, info->mm_height), | 
|  | type, | 
|  | IsOutputAspectPreservingScaling(output), | 
|  | has_overscan, | 
|  | GetDisplayName(output), | 
|  | display_modes, | 
|  | current_mode, | 
|  | native_mode, | 
|  | output, | 
|  | crtc, | 
|  | index); | 
|  |  | 
|  | VLOG(1) << "Found display " << cached_outputs_.size() << ":" | 
|  | << " output=" << output << " crtc=" << crtc | 
|  | << " current_mode=" << current_mode_id; | 
|  |  | 
|  | return display_snapshot; | 
|  | } | 
|  |  | 
|  | bool NativeDisplayDelegateX11::GetHDCPState(const DisplaySnapshot& output, | 
|  | HDCPState* state) { | 
|  | unsigned char* values = NULL; | 
|  | int actual_format = 0; | 
|  | unsigned long nitems = 0; | 
|  | unsigned long bytes_after = 0; | 
|  | Atom actual_type = None; | 
|  | int success = 0; | 
|  | RROutput output_id = static_cast<const DisplaySnapshotX11&>(output).output(); | 
|  | // TODO(kcwu): Use X11AtomCache to save round trip time of XInternAtom. | 
|  | Atom prop = XInternAtom(display_, kContentProtectionAtomName, False); | 
|  |  | 
|  | bool ok = true; | 
|  | // TODO(kcwu): Move this to x11_util (similar method calls in this file and | 
|  | // output_util.cc) | 
|  | success = XRRGetOutputProperty(display_, | 
|  | output_id, | 
|  | prop, | 
|  | 0, | 
|  | 100, | 
|  | False, | 
|  | False, | 
|  | AnyPropertyType, | 
|  | &actual_type, | 
|  | &actual_format, | 
|  | &nitems, | 
|  | &bytes_after, | 
|  | &values); | 
|  | if (actual_type == None) { | 
|  | LOG(ERROR) << "Property '" << kContentProtectionAtomName | 
|  | << "' does not exist"; | 
|  | ok = false; | 
|  | } else if (success == Success && actual_type == XA_ATOM && | 
|  | actual_format == 32 && nitems == 1) { | 
|  | Atom value = reinterpret_cast<Atom*>(values)[0]; | 
|  | if (value == XInternAtom(display_, kProtectionUndesiredAtomName, False)) { | 
|  | *state = HDCP_STATE_UNDESIRED; | 
|  | } else if (value == | 
|  | XInternAtom(display_, kProtectionDesiredAtomName, False)) { | 
|  | *state = HDCP_STATE_DESIRED; | 
|  | } else if (value == | 
|  | XInternAtom(display_, kProtectionEnabledAtomName, False)) { | 
|  | *state = HDCP_STATE_ENABLED; | 
|  | } else { | 
|  | LOG(ERROR) << "Unknown " << kContentProtectionAtomName | 
|  | << " value: " << value; | 
|  | ok = false; | 
|  | } | 
|  | } else { | 
|  | LOG(ERROR) << "XRRGetOutputProperty failed"; | 
|  | ok = false; | 
|  | } | 
|  | if (values) | 
|  | XFree(values); | 
|  |  | 
|  | VLOG(3) << "HDCP state: " << ok << "," << *state; | 
|  | return ok; | 
|  | } | 
|  |  | 
|  | bool NativeDisplayDelegateX11::SetHDCPState(const DisplaySnapshot& output, | 
|  | HDCPState state) { | 
|  | Atom name = XInternAtom(display_, kContentProtectionAtomName, False); | 
|  | Atom value = None; | 
|  | switch (state) { | 
|  | case HDCP_STATE_UNDESIRED: | 
|  | value = XInternAtom(display_, kProtectionUndesiredAtomName, False); | 
|  | break; | 
|  | case HDCP_STATE_DESIRED: | 
|  | value = XInternAtom(display_, kProtectionDesiredAtomName, False); | 
|  | break; | 
|  | default: | 
|  | NOTREACHED() << "Invalid HDCP state: " << state; | 
|  | return false; | 
|  | } | 
|  | gfx::X11ErrorTracker err_tracker; | 
|  | unsigned char* data = reinterpret_cast<unsigned char*>(&value); | 
|  | RROutput output_id = static_cast<const DisplaySnapshotX11&>(output).output(); | 
|  | XRRChangeOutputProperty( | 
|  | display_, output_id, name, XA_ATOM, 32, PropModeReplace, data, 1); | 
|  | if (err_tracker.FoundNewError()) { | 
|  | LOG(ERROR) << "XRRChangeOutputProperty failed"; | 
|  | return false; | 
|  | } else { | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::DestroyUnusedCrtcs() { | 
|  | CHECK(screen_) << "Server not grabbed"; | 
|  |  | 
|  | for (int i = 0; i < screen_->ncrtc; ++i) { | 
|  | bool in_use = false; | 
|  | for (ScopedVector<DisplaySnapshot>::const_iterator it = | 
|  | cached_outputs_.begin(); | 
|  | it != cached_outputs_.end(); | 
|  | ++it) { | 
|  | DisplaySnapshotX11* x11_output = static_cast<DisplaySnapshotX11*>(*it); | 
|  | if (screen_->crtcs[i] == x11_output->crtc()) { | 
|  | in_use = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!in_use) | 
|  | ConfigureCrtc(screen_->crtcs[i], None, None, 0, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::UpdateCrtcsForNewFramebuffer( | 
|  | const gfx::Size& min_screen_size) { | 
|  | CHECK(screen_) << "Server not grabbed"; | 
|  | // 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 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. | 
|  | gfx::Rect fb_rect(min_screen_size); | 
|  | for (ScopedVector<DisplaySnapshot>::const_iterator it = | 
|  | cached_outputs_.begin(); | 
|  | it != cached_outputs_.end(); | 
|  | ++it) { | 
|  | DisplaySnapshotX11* x11_output = static_cast<DisplaySnapshotX11*>(*it); | 
|  | const DisplayMode* mode_info = x11_output->current_mode(); | 
|  | RROutput output = x11_output->output(); | 
|  | RRMode mode = None; | 
|  |  | 
|  | if (mode_info) { | 
|  | mode = static_cast<const DisplayModeX11*>(mode_info)->mode_id(); | 
|  |  | 
|  | if (!fb_rect.Contains(gfx::Rect(mode_info->size()))) { | 
|  | // In case our CRTC doesn't fit in common area of our current and about | 
|  | // to be resized framebuffer, disable it. | 
|  | // It'll get reenabled after we resize the framebuffer. | 
|  | mode = None; | 
|  | output = None; | 
|  | mode_info = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | ConfigureCrtc(x11_output->crtc(), mode, output, 0, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool NativeDisplayDelegateX11::IsOutputAspectPreservingScaling(RROutput id) { | 
|  | bool ret = false; | 
|  |  | 
|  | 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; | 
|  |  | 
|  | int nprop = 0; | 
|  | Atom* props = XRRListOutputProperties(display_, id, &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_, | 
|  | id, | 
|  | 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); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | std::vector<ColorCalibrationProfile> | 
|  | NativeDisplayDelegateX11::GetAvailableColorCalibrationProfiles( | 
|  | const DisplaySnapshot& output) { | 
|  | // TODO(mukai|marcheu): Checks the system data and fills the result. | 
|  | // Note that the order would be Dynamic -> Standard -> Movie -> Reading. | 
|  | return std::vector<ColorCalibrationProfile>(); | 
|  | } | 
|  |  | 
|  | bool NativeDisplayDelegateX11::SetColorCalibrationProfile( | 
|  | const DisplaySnapshot& output, | 
|  | ColorCalibrationProfile new_profile) { | 
|  | const DisplaySnapshotX11& x11_output = | 
|  | static_cast<const DisplaySnapshotX11&>(output); | 
|  |  | 
|  | XRRCrtcGamma* gamma_ramp = CreateGammaRampForProfile(x11_output, new_profile); | 
|  |  | 
|  | if (!gamma_ramp) | 
|  | return false; | 
|  |  | 
|  | int gamma_ramp_size = XRRGetCrtcGammaSize(display_, x11_output.crtc()); | 
|  | XRRSetCrtcGamma(display_, | 
|  | x11_output.crtc(), | 
|  | ResampleGammaRamp(gamma_ramp, gamma_ramp_size)); | 
|  | XRRFreeGamma(gamma_ramp); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | XRRCrtcGamma* NativeDisplayDelegateX11::CreateGammaRampForProfile( | 
|  | const DisplaySnapshotX11& x11_output, | 
|  | ColorCalibrationProfile new_profile) { | 
|  | // TODO(mukai|marcheu): Creates the appropriate gamma ramp data from the | 
|  | // profile enum. It would be served by the vendor. | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | void NativeDisplayDelegateX11::DrawBackground() { | 
|  | if (!background_color_argb_) | 
|  | return; | 
|  | // Configuring CRTCs/Framebuffer clears the boot screen image.  Paint the | 
|  | // same background color after updating framebuffer to minimize the | 
|  | // duration of black screen at boot time. | 
|  | 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); | 
|  |  | 
|  | GC gc = XCreateGC(display_, window_, 0, 0); | 
|  | XSetForeground(display_, gc, color.pixel); | 
|  | XSetFillStyle(display_, gc, FillSolid); | 
|  | int width = DisplayWidth(display_, DefaultScreen(display_)); | 
|  | int height = DisplayHeight(display_, DefaultScreen(display_)); | 
|  | XFillRectangle(display_, window_, gc, 0, 0, width, height); | 
|  | XFreeGC(display_, gc); | 
|  | XFreeColors(display_, colormap, &color.pixel, 1, 0); | 
|  | } | 
|  |  | 
|  | }  // namespace ui |