1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/display/chromeos/x11/native_display_delegate_x11.h" 6 7 #include <X11/Xatom.h> 8 #include <X11/Xlib.h> 9 #include <X11/extensions/dpms.h> 10 #include <X11/extensions/Xrandr.h> 11 #include <X11/extensions/XInput2.h> 12 13 #include <utility> 14 15 #include "base/logging.h" 16 #include "base/stl_util.h" 17 #include "ui/display/chromeos/x11/display_mode_x11.h" 18 #include "ui/display/chromeos/x11/display_snapshot_x11.h" 19 #include "ui/display/chromeos/x11/display_util_x11.h" 20 #include "ui/display/chromeos/x11/native_display_event_dispatcher_x11.h" 21 #include "ui/display/types/chromeos/native_display_observer.h" 22 #include "ui/display/util/x11/edid_parser_x11.h" 23 #include "ui/events/platform/platform_event_observer.h" 24 #include "ui/events/platform/platform_event_source.h" 25 #include "ui/gfx/geometry/rect.h" 26 #include "ui/gfx/x/x11_error_tracker.h" 27 #include "ui/gfx/x/x11_types.h" 28 29 namespace ui { 30 31 namespace { 32 33 // DPI measurements. 34 const float kMmInInch = 25.4; 35 const float kDpi96 = 96.0; 36 const float kPixelsToMmScale = kMmInInch / kDpi96; 37 38 const char kContentProtectionAtomName[] = "Content Protection"; 39 const char kProtectionUndesiredAtomName[] = "Undesired"; 40 const char kProtectionDesiredAtomName[] = "Desired"; 41 const char kProtectionEnabledAtomName[] = "Enabled"; 42 43 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { 44 return output_info->nmode > 0 ? output_info->modes[0] : None; 45 } 46 47 XRRCrtcGamma* ResampleGammaRamp(XRRCrtcGamma* gamma_ramp, int gamma_ramp_size) { 48 if (gamma_ramp->size == gamma_ramp_size) 49 return gamma_ramp; 50 51 #define RESAMPLE(array, i, r) \ 52 array[i] + (array[i + 1] - array[i]) * r / gamma_ramp_size 53 54 XRRCrtcGamma* resampled = XRRAllocGamma(gamma_ramp_size); 55 for (int i = 0; i < gamma_ramp_size; ++i) { 56 int base_index = gamma_ramp->size * i / gamma_ramp_size; 57 int remaining = gamma_ramp->size * i % gamma_ramp_size; 58 if (base_index < gamma_ramp->size - 1) { 59 resampled->red[i] = RESAMPLE(gamma_ramp->red, base_index, remaining); 60 resampled->green[i] = RESAMPLE(gamma_ramp->green, base_index, remaining); 61 resampled->blue[i] = RESAMPLE(gamma_ramp->blue, base_index, remaining); 62 } else { 63 resampled->red[i] = gamma_ramp->red[gamma_ramp->size - 1]; 64 resampled->green[i] = gamma_ramp->green[gamma_ramp->size - 1]; 65 resampled->blue[i] = gamma_ramp->blue[gamma_ramp->size - 1]; 66 } 67 } 68 69 #undef RESAMPLE 70 XRRFreeGamma(gamma_ramp); 71 return resampled; 72 } 73 74 } // namespace 75 76 //////////////////////////////////////////////////////////////////////////////// 77 // NativeDisplayDelegateX11::HelperDelegateX11 78 79 class NativeDisplayDelegateX11::HelperDelegateX11 80 : public NativeDisplayDelegateX11::HelperDelegate { 81 public: 82 HelperDelegateX11(NativeDisplayDelegateX11* delegate) : delegate_(delegate) {} 83 virtual ~HelperDelegateX11() {} 84 85 // NativeDisplayDelegateX11::HelperDelegate overrides: 86 virtual void UpdateXRandRConfiguration(const base::NativeEvent& event) 87 OVERRIDE { 88 XRRUpdateConfiguration(event); 89 } 90 virtual const std::vector<DisplaySnapshot*>& GetCachedDisplays() const 91 OVERRIDE { 92 return delegate_->cached_outputs_.get(); 93 } 94 virtual void NotifyDisplayObservers() OVERRIDE { 95 FOR_EACH_OBSERVER( 96 NativeDisplayObserver, delegate_->observers_, OnConfigurationChanged()); 97 } 98 99 private: 100 NativeDisplayDelegateX11* delegate_; 101 102 DISALLOW_COPY_AND_ASSIGN(HelperDelegateX11); 103 }; 104 105 //////////////////////////////////////////////////////////////////////////////// 106 // NativeDisplayDelegateX11::PlatformEventObserverX11 107 108 class NativeDisplayDelegateX11::PlatformEventObserverX11 109 : public PlatformEventObserver { 110 public: 111 PlatformEventObserverX11(HelperDelegate* delegate); 112 virtual ~PlatformEventObserverX11(); 113 114 // PlatformEventObserverX11: 115 virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE; 116 virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE; 117 118 private: 119 HelperDelegate* delegate_; // Not owned. 120 121 DISALLOW_COPY_AND_ASSIGN(PlatformEventObserverX11); 122 }; 123 124 NativeDisplayDelegateX11::PlatformEventObserverX11::PlatformEventObserverX11( 125 HelperDelegate* delegate) 126 : delegate_(delegate) {} 127 128 NativeDisplayDelegateX11::PlatformEventObserverX11:: 129 ~PlatformEventObserverX11() {} 130 131 void NativeDisplayDelegateX11::PlatformEventObserverX11::WillProcessEvent( 132 const ui::PlatformEvent& event) { 133 // XI_HierarchyChanged events are special. There is no window associated with 134 // these events. So process them directly from here. 135 if (event->type == GenericEvent && 136 event->xgeneric.evtype == XI_HierarchyChanged) { 137 VLOG(1) << "Received XI_HierarchyChanged event"; 138 // Defer configuring outputs to not stall event processing. 139 // This also takes care of same event being received twice. 140 delegate_->NotifyDisplayObservers(); 141 } 142 } 143 144 void NativeDisplayDelegateX11::PlatformEventObserverX11::DidProcessEvent( 145 const ui::PlatformEvent& event) {} 146 147 //////////////////////////////////////////////////////////////////////////////// 148 // NativeDisplayDelegateX11 implementation: 149 150 NativeDisplayDelegateX11::NativeDisplayDelegateX11() 151 : display_(gfx::GetXDisplay()), 152 window_(DefaultRootWindow(display_)), 153 screen_(NULL), 154 background_color_argb_(0) {} 155 156 NativeDisplayDelegateX11::~NativeDisplayDelegateX11() { 157 if (ui::PlatformEventSource::GetInstance()) { 158 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher( 159 platform_event_dispatcher_.get()); 160 ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver( 161 platform_event_observer_.get()); 162 } 163 164 STLDeleteContainerPairSecondPointers(modes_.begin(), modes_.end()); 165 } 166 167 void NativeDisplayDelegateX11::Initialize() { 168 int error_base_ignored = 0; 169 int xrandr_event_base = 0; 170 XRRQueryExtension(display_, &xrandr_event_base, &error_base_ignored); 171 172 helper_delegate_.reset(new HelperDelegateX11(this)); 173 platform_event_dispatcher_.reset(new NativeDisplayEventDispatcherX11( 174 helper_delegate_.get(), xrandr_event_base)); 175 platform_event_observer_.reset( 176 new PlatformEventObserverX11(helper_delegate_.get())); 177 178 if (ui::PlatformEventSource::GetInstance()) { 179 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher( 180 platform_event_dispatcher_.get()); 181 182 // We can't do this with a root window listener because XI_HierarchyChanged 183 // messages don't have a target window. 184 ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver( 185 platform_event_observer_.get()); 186 } 187 } 188 189 void NativeDisplayDelegateX11::GrabServer() { 190 CHECK(!screen_) << "Server already grabbed"; 191 XGrabServer(display_); 192 screen_ = XRRGetScreenResources(display_, window_); 193 CHECK(screen_); 194 } 195 196 void NativeDisplayDelegateX11::UngrabServer() { 197 CHECK(screen_) << "Server not grabbed"; 198 XRRFreeScreenResources(screen_); 199 screen_ = NULL; 200 XUngrabServer(display_); 201 // crbug.com/366125 202 XFlush(display_); 203 } 204 205 void NativeDisplayDelegateX11::SyncWithServer() { XSync(display_, 0); } 206 207 void NativeDisplayDelegateX11::SetBackgroundColor(uint32_t color_argb) { 208 background_color_argb_ = color_argb; 209 } 210 211 void NativeDisplayDelegateX11::ForceDPMSOn() { 212 CHECK(DPMSEnable(display_)); 213 CHECK(DPMSForceLevel(display_, DPMSModeOn)); 214 } 215 216 std::vector<DisplaySnapshot*> NativeDisplayDelegateX11::GetDisplays() { 217 CHECK(screen_) << "Server not grabbed"; 218 219 cached_outputs_.clear(); 220 RRCrtc last_used_crtc = None; 221 222 InitModes(); 223 for (int i = 0; i < screen_->noutput && cached_outputs_.size() < 2; ++i) { 224 RROutput output_id = screen_->outputs[i]; 225 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id); 226 if (output_info->connection == RR_Connected) { 227 DisplaySnapshotX11* output = 228 InitDisplaySnapshot(output_id, output_info, &last_used_crtc, i); 229 cached_outputs_.push_back(output); 230 } 231 XRRFreeOutputInfo(output_info); 232 } 233 234 return cached_outputs_.get(); 235 } 236 237 void NativeDisplayDelegateX11::AddMode(const DisplaySnapshot& output, 238 const DisplayMode* mode) { 239 CHECK(screen_) << "Server not grabbed"; 240 CHECK(mode) << "Must add valid mode"; 241 242 const DisplaySnapshotX11& x11_output = 243 static_cast<const DisplaySnapshotX11&>(output); 244 RRMode mode_id = static_cast<const DisplayModeX11*>(mode)->mode_id(); 245 246 VLOG(1) << "AddDisplayMode: output=" << x11_output.output() 247 << " mode=" << mode_id; 248 XRRAddOutputMode(display_, x11_output.output(), mode_id); 249 } 250 251 bool NativeDisplayDelegateX11::Configure(const DisplaySnapshot& output, 252 const DisplayMode* mode, 253 const gfx::Point& origin) { 254 const DisplaySnapshotX11& x11_output = 255 static_cast<const DisplaySnapshotX11&>(output); 256 RRMode mode_id = None; 257 if (mode) 258 mode_id = static_cast<const DisplayModeX11*>(mode)->mode_id(); 259 260 return ConfigureCrtc( 261 x11_output.crtc(), mode_id, x11_output.output(), origin.x(), origin.y()); 262 } 263 264 bool NativeDisplayDelegateX11::ConfigureCrtc(RRCrtc crtc, 265 RRMode mode, 266 RROutput output, 267 int x, 268 int y) { 269 CHECK(screen_) << "Server not grabbed"; 270 VLOG(1) << "ConfigureCrtc: crtc=" << crtc << " mode=" << mode 271 << " output=" << output << " x=" << x << " y=" << y; 272 // Xrandr.h is full of lies. XRRSetCrtcConfig() is defined as returning a 273 // Status, which is typically 0 for failure and 1 for success. In 274 // actuality it returns a RRCONFIGSTATUS, which uses 0 for success. 275 if (XRRSetCrtcConfig(display_, 276 screen_, 277 crtc, 278 CurrentTime, 279 x, 280 y, 281 mode, 282 RR_Rotate_0, 283 (output && mode) ? &output : NULL, 284 (output && mode) ? 1 : 0) != RRSetConfigSuccess) { 285 LOG(WARNING) << "Unable to configure CRTC " << crtc << ":" 286 << " mode=" << mode << " output=" << output << " x=" << x 287 << " y=" << y; 288 return false; 289 } 290 291 return true; 292 } 293 294 void NativeDisplayDelegateX11::CreateFrameBuffer(const gfx::Size& size) { 295 CHECK(screen_) << "Server not grabbed"; 296 gfx::Size current_screen_size( 297 DisplayWidth(display_, DefaultScreen(display_)), 298 DisplayHeight(display_, DefaultScreen(display_))); 299 300 VLOG(1) << "CreateFrameBuffer: new=" << size.ToString() 301 << " current=" << current_screen_size.ToString(); 302 303 DestroyUnusedCrtcs(); 304 305 if (size == current_screen_size) 306 return; 307 308 gfx::Size min_screen_size(current_screen_size); 309 min_screen_size.SetToMin(size); 310 UpdateCrtcsForNewFramebuffer(min_screen_size); 311 312 int mm_width = size.width() * kPixelsToMmScale; 313 int mm_height = size.height() * kPixelsToMmScale; 314 XRRSetScreenSize( 315 display_, window_, size.width(), size.height(), mm_width, mm_height); 316 // We don't wait for root window resize, therefore this end up with drawing 317 // in the old window size, which we care during the boot. 318 DrawBackground(); 319 320 // Don't redraw the background upon framebuffer change again. This should 321 // happen only once after boot. 322 background_color_argb_ = 0; 323 } 324 325 void NativeDisplayDelegateX11::AddObserver(NativeDisplayObserver* observer) { 326 observers_.AddObserver(observer); 327 } 328 329 void NativeDisplayDelegateX11::RemoveObserver(NativeDisplayObserver* observer) { 330 observers_.RemoveObserver(observer); 331 } 332 333 void NativeDisplayDelegateX11::InitModes() { 334 CHECK(screen_) << "Server not grabbed"; 335 336 STLDeleteContainerPairSecondPointers(modes_.begin(), modes_.end()); 337 modes_.clear(); 338 339 for (int i = 0; i < screen_->nmode; ++i) { 340 const XRRModeInfo& info = screen_->modes[i]; 341 float refresh_rate = 0.0f; 342 if (info.hTotal && info.vTotal) { 343 refresh_rate = 344 static_cast<float>(info.dotClock) / 345 (static_cast<float>(info.hTotal) * static_cast<float>(info.vTotal)); 346 } 347 348 modes_.insert( 349 std::make_pair(info.id, 350 new DisplayModeX11(gfx::Size(info.width, info.height), 351 info.modeFlags & RR_Interlace, 352 refresh_rate, 353 info.id))); 354 } 355 } 356 357 DisplaySnapshotX11* NativeDisplayDelegateX11::InitDisplaySnapshot( 358 RROutput id, 359 XRROutputInfo* info, 360 RRCrtc* last_used_crtc, 361 int index) { 362 int64_t display_id = 0; 363 bool has_display_id = GetDisplayId( 364 id, static_cast<uint8_t>(index), &display_id); 365 366 bool has_overscan = false; 367 GetOutputOverscanFlag(id, &has_overscan); 368 369 DisplayConnectionType type = GetDisplayConnectionTypeFromName(info->name); 370 if (type == DISPLAY_CONNECTION_TYPE_UNKNOWN) 371 LOG(ERROR) << "Unknown link type: " << info->name; 372 373 // Use the index as a valid display ID even if the internal 374 // display doesn't have valid EDID because the index 375 // will never change. 376 if (!has_display_id) { 377 if (type == DISPLAY_CONNECTION_TYPE_INTERNAL) 378 has_display_id = true; 379 380 // Fallback to output index. 381 display_id = index; 382 } 383 384 RRMode native_mode_id = GetOutputNativeMode(info); 385 RRMode current_mode_id = None; 386 gfx::Point origin; 387 if (info->crtc) { 388 XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display_, screen_, info->crtc); 389 current_mode_id = crtc_info->mode; 390 origin.SetPoint(crtc_info->x, crtc_info->y); 391 XRRFreeCrtcInfo(crtc_info); 392 } 393 394 RRCrtc crtc = None; 395 // Assign a CRTC that isn't already in use. 396 for (int i = 0; i < info->ncrtc; ++i) { 397 if (info->crtcs[i] != *last_used_crtc) { 398 crtc = info->crtcs[i]; 399 *last_used_crtc = crtc; 400 break; 401 } 402 } 403 404 const DisplayMode* current_mode = NULL; 405 const DisplayMode* native_mode = NULL; 406 std::vector<const DisplayMode*> display_modes; 407 408 for (int i = 0; i < info->nmode; ++i) { 409 const RRMode mode = info->modes[i]; 410 if (modes_.find(mode) != modes_.end()) { 411 display_modes.push_back(modes_.at(mode)); 412 413 if (mode == current_mode_id) 414 current_mode = display_modes.back(); 415 if (mode == native_mode_id) 416 native_mode = display_modes.back(); 417 } else { 418 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; 419 } 420 } 421 422 DisplaySnapshotX11* output = 423 new DisplaySnapshotX11(display_id, 424 has_display_id, 425 origin, 426 gfx::Size(info->mm_width, info->mm_height), 427 type, 428 IsOutputAspectPreservingScaling(id), 429 has_overscan, 430 GetDisplayName(id), 431 display_modes, 432 current_mode, 433 native_mode, 434 id, 435 crtc, 436 index); 437 438 VLOG(2) << "Found display " << cached_outputs_.size() << ":" 439 << " output=" << output << " crtc=" << crtc 440 << " current_mode=" << current_mode_id; 441 442 return output; 443 } 444 445 bool NativeDisplayDelegateX11::GetHDCPState(const DisplaySnapshot& output, 446 HDCPState* state) { 447 unsigned char* values = NULL; 448 int actual_format = 0; 449 unsigned long nitems = 0; 450 unsigned long bytes_after = 0; 451 Atom actual_type = None; 452 int success = 0; 453 RROutput output_id = static_cast<const DisplaySnapshotX11&>(output).output(); 454 // TODO(kcwu): Use X11AtomCache to save round trip time of XInternAtom. 455 Atom prop = XInternAtom(display_, kContentProtectionAtomName, False); 456 457 bool ok = true; 458 // TODO(kcwu): Move this to x11_util (similar method calls in this file and 459 // output_util.cc) 460 success = XRRGetOutputProperty(display_, 461 output_id, 462 prop, 463 0, 464 100, 465 False, 466 False, 467 AnyPropertyType, 468 &actual_type, 469 &actual_format, 470 &nitems, 471 &bytes_after, 472 &values); 473 if (actual_type == None) { 474 LOG(ERROR) << "Property '" << kContentProtectionAtomName 475 << "' does not exist"; 476 ok = false; 477 } else if (success == Success && actual_type == XA_ATOM && 478 actual_format == 32 && nitems == 1) { 479 Atom value = reinterpret_cast<Atom*>(values)[0]; 480 if (value == XInternAtom(display_, kProtectionUndesiredAtomName, False)) { 481 *state = HDCP_STATE_UNDESIRED; 482 } else if (value == 483 XInternAtom(display_, kProtectionDesiredAtomName, False)) { 484 *state = HDCP_STATE_DESIRED; 485 } else if (value == 486 XInternAtom(display_, kProtectionEnabledAtomName, False)) { 487 *state = HDCP_STATE_ENABLED; 488 } else { 489 LOG(ERROR) << "Unknown " << kContentProtectionAtomName 490 << " value: " << value; 491 ok = false; 492 } 493 } else { 494 LOG(ERROR) << "XRRGetOutputProperty failed"; 495 ok = false; 496 } 497 if (values) 498 XFree(values); 499 500 VLOG(3) << "HDCP state: " << ok << "," << *state; 501 return ok; 502 } 503 504 bool NativeDisplayDelegateX11::SetHDCPState(const DisplaySnapshot& output, 505 HDCPState state) { 506 Atom name = XInternAtom(display_, kContentProtectionAtomName, False); 507 Atom value = None; 508 switch (state) { 509 case HDCP_STATE_UNDESIRED: 510 value = XInternAtom(display_, kProtectionUndesiredAtomName, False); 511 break; 512 case HDCP_STATE_DESIRED: 513 value = XInternAtom(display_, kProtectionDesiredAtomName, False); 514 break; 515 default: 516 NOTREACHED() << "Invalid HDCP state: " << state; 517 return false; 518 } 519 gfx::X11ErrorTracker err_tracker; 520 unsigned char* data = reinterpret_cast<unsigned char*>(&value); 521 RROutput output_id = static_cast<const DisplaySnapshotX11&>(output).output(); 522 XRRChangeOutputProperty( 523 display_, output_id, name, XA_ATOM, 32, PropModeReplace, data, 1); 524 if (err_tracker.FoundNewError()) { 525 LOG(ERROR) << "XRRChangeOutputProperty failed"; 526 return false; 527 } else { 528 return true; 529 } 530 } 531 532 void NativeDisplayDelegateX11::DestroyUnusedCrtcs() { 533 CHECK(screen_) << "Server not grabbed"; 534 535 for (int i = 0; i < screen_->ncrtc; ++i) { 536 bool in_use = false; 537 for (ScopedVector<DisplaySnapshot>::const_iterator it = 538 cached_outputs_.begin(); 539 it != cached_outputs_.end(); 540 ++it) { 541 DisplaySnapshotX11* x11_output = static_cast<DisplaySnapshotX11*>(*it); 542 if (screen_->crtcs[i] == x11_output->crtc()) { 543 in_use = true; 544 break; 545 } 546 } 547 548 if (!in_use) 549 ConfigureCrtc(screen_->crtcs[i], None, None, 0, 0); 550 } 551 } 552 553 void NativeDisplayDelegateX11::UpdateCrtcsForNewFramebuffer( 554 const gfx::Size& min_screen_size) { 555 CHECK(screen_) << "Server not grabbed"; 556 // Setting the screen size will fail if any CRTC doesn't fit afterwards. 557 // At the same time, turning CRTCs off and back on uses up a lot of time. 558 // This function tries to be smart to avoid too many off/on cycles: 559 // - We set the new modes on CRTCs, if they fit in both the old and new 560 // FBs, and park them at (0,0) 561 // - We disable the CRTCs we will need but don't fit in the old FB. Those 562 // will be reenabled after the resize. 563 // We don't worry about the cached state of the outputs here since we are 564 // not interested in the state we are setting - we just try to get the CRTCs 565 // out of the way so we can rebuild the frame buffer. 566 gfx::Rect fb_rect(min_screen_size); 567 for (ScopedVector<DisplaySnapshot>::const_iterator it = 568 cached_outputs_.begin(); 569 it != cached_outputs_.end(); 570 ++it) { 571 DisplaySnapshotX11* x11_output = static_cast<DisplaySnapshotX11*>(*it); 572 const DisplayMode* mode_info = x11_output->current_mode(); 573 RROutput output = x11_output->output(); 574 RRMode mode = None; 575 576 if (mode_info) { 577 mode = static_cast<const DisplayModeX11*>(mode_info)->mode_id(); 578 579 if (!fb_rect.Contains(gfx::Rect(mode_info->size()))) { 580 // In case our CRTC doesn't fit in common area of our current and about 581 // to be resized framebuffer, disable it. 582 // It'll get reenabled after we resize the framebuffer. 583 mode = None; 584 output = None; 585 mode_info = NULL; 586 } 587 } 588 589 ConfigureCrtc(x11_output->crtc(), mode, output, 0, 0); 590 } 591 } 592 593 bool NativeDisplayDelegateX11::IsOutputAspectPreservingScaling(RROutput id) { 594 bool ret = false; 595 596 Atom scaling_prop = XInternAtom(display_, "scaling mode", False); 597 Atom full_aspect_atom = XInternAtom(display_, "Full aspect", False); 598 if (scaling_prop == None || full_aspect_atom == None) 599 return false; 600 601 int nprop = 0; 602 Atom* props = XRRListOutputProperties(display_, id, &nprop); 603 for (int j = 0; j < nprop && !ret; j++) { 604 Atom prop = props[j]; 605 if (scaling_prop == prop) { 606 unsigned char* values = NULL; 607 int actual_format; 608 unsigned long nitems; 609 unsigned long bytes_after; 610 Atom actual_type; 611 int success; 612 613 success = XRRGetOutputProperty(display_, 614 id, 615 prop, 616 0, 617 100, 618 False, 619 False, 620 AnyPropertyType, 621 &actual_type, 622 &actual_format, 623 &nitems, 624 &bytes_after, 625 &values); 626 if (success == Success && actual_type == XA_ATOM && actual_format == 32 && 627 nitems == 1) { 628 Atom value = reinterpret_cast<Atom*>(values)[0]; 629 if (full_aspect_atom == value) 630 ret = true; 631 } 632 if (values) 633 XFree(values); 634 } 635 } 636 if (props) 637 XFree(props); 638 639 return ret; 640 } 641 642 643 std::vector<ColorCalibrationProfile> 644 NativeDisplayDelegateX11::GetAvailableColorCalibrationProfiles( 645 const DisplaySnapshot& output) { 646 // TODO(mukai|marcheu): Checks the system data and fills the result. 647 // Note that the order would be Dynamic -> Standard -> Movie -> Reading. 648 return std::vector<ColorCalibrationProfile>(); 649 } 650 651 bool NativeDisplayDelegateX11::SetColorCalibrationProfile( 652 const DisplaySnapshot& output, 653 ColorCalibrationProfile new_profile) { 654 const DisplaySnapshotX11& x11_output = 655 static_cast<const DisplaySnapshotX11&>(output); 656 657 XRRCrtcGamma* gamma_ramp = CreateGammaRampForProfile(x11_output, new_profile); 658 659 if (!gamma_ramp) 660 return false; 661 662 int gamma_ramp_size = XRRGetCrtcGammaSize(display_, x11_output.crtc()); 663 XRRSetCrtcGamma(display_, 664 x11_output.crtc(), 665 ResampleGammaRamp(gamma_ramp, gamma_ramp_size)); 666 XRRFreeGamma(gamma_ramp); 667 return true; 668 } 669 670 XRRCrtcGamma* NativeDisplayDelegateX11::CreateGammaRampForProfile( 671 const DisplaySnapshotX11& x11_output, 672 ColorCalibrationProfile new_profile) { 673 // TODO(mukai|marcheu): Creates the appropriate gamma ramp data from the 674 // profile enum. It would be served by the vendor. 675 return NULL; 676 } 677 678 void NativeDisplayDelegateX11::DrawBackground() { 679 if (!background_color_argb_) 680 return; 681 // Configuring CRTCs/Framebuffer clears the boot screen image. Paint the 682 // same background color after updating framebuffer to minimize the 683 // duration of black screen at boot time. 684 XColor color; 685 Colormap colormap = DefaultColormap(display_, 0); 686 // XColor uses 16 bits per color. 687 color.red = (background_color_argb_ & 0x00FF0000) >> 8; 688 color.green = (background_color_argb_ & 0x0000FF00); 689 color.blue = (background_color_argb_ & 0x000000FF) << 8; 690 color.flags = DoRed | DoGreen | DoBlue; 691 XAllocColor(display_, colormap, &color); 692 693 GC gc = XCreateGC(display_, window_, 0, 0); 694 XSetForeground(display_, gc, color.pixel); 695 XSetFillStyle(display_, gc, FillSolid); 696 int width = DisplayWidth(display_, DefaultScreen(display_)); 697 int height = DisplayHeight(display_, DefaultScreen(display_)); 698 XFillRectangle(display_, window_, gc, 0, 0, width, height); 699 XFreeGC(display_, gc); 700 XFreeColors(display_, colormap, &color.pixel, 1, 0); 701 } 702 703 } // namespace ui 704