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