Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/display/real_output_configurator_delegate.h" | 5 #include "chromeos/display/real_output_configurator_delegate.h" |
| 6 | 6 |
| 7 #include <X11/Xatom.h> | 7 #include <X11/Xatom.h> |
| 8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
| 9 #include <X11/extensions/dpms.h> | 9 #include <X11/extensions/dpms.h> |
| 10 #include <X11/extensions/XInput.h> | 10 #include <X11/extensions/XInput.h> |
| 11 #include <X11/extensions/XInput2.h> | 11 #include <X11/extensions/XInput2.h> |
| 12 #include <X11/extensions/Xrandr.h> | 12 #include <X11/extensions/Xrandr.h> |
| 13 | 13 |
| 14 #include <cmath> | 14 #include <cmath> |
| 15 #include <set> | 15 #include <set> |
| 16 #include <utility> | 16 #include <utility> |
| 17 | 17 |
| 18 #include "base/logging.h" | 18 #include "base/logging.h" |
| 19 #include "base/message_loop/message_pump_x11.h" | 19 #include "base/message_loop/message_pump_x11.h" |
| 20 #include "chromeos/dbus/dbus_thread_manager.h" | 20 #include "chromeos/dbus/dbus_thread_manager.h" |
| 21 #include "chromeos/dbus/power_manager_client.h" | 21 #include "chromeos/dbus/power_manager_client.h" |
| 22 #include "chromeos/display/output_util.h" | 22 #include "chromeos/display/output_util.h" |
| 23 #include "ui/base/x/x11_error_tracker.h" | |
| 23 | 24 |
| 24 namespace chromeos { | 25 namespace chromeos { |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 // DPI measurements. | 29 // DPI measurements. |
| 29 const float kMmInInch = 25.4; | 30 const float kMmInInch = 25.4; |
| 30 const float kDpi96 = 96.0; | 31 const float kDpi96 = 96.0; |
| 31 const float kPixelsToMmScale = kMmInInch / kDpi96; | 32 const float kPixelsToMmScale = kMmInInch / kDpi96; |
| 32 | 33 |
| 34 // Prefixes of output name | |
| 35 const char kOutputName_VGA[] = "VGA"; | |
| 36 const char kOutputName_HDMI[] = "HDMI"; | |
| 37 const char kOutputName_DVI[] = "DVI"; | |
| 38 const char kOutputName_DisplayPort[] = "DP"; | |
| 39 | |
| 33 bool IsInternalOutput(const XRROutputInfo* output_info) { | 40 bool IsInternalOutput(const XRROutputInfo* output_info) { |
| 34 return IsInternalOutputName(std::string(output_info->name)); | 41 return IsInternalOutputName(std::string(output_info->name)); |
| 35 } | 42 } |
| 36 | 43 |
| 37 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { | 44 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { |
| 38 return output_info->nmode > 0 ? output_info->modes[0] : None; | 45 return output_info->nmode > 0 ? output_info->modes[0] : None; |
| 39 } | 46 } |
| 40 | 47 |
| 41 } // namespace | 48 } // namespace |
| 42 | 49 |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 299 OutputConfigurator::ModeInfo mode_info; | 306 OutputConfigurator::ModeInfo mode_info; |
| 300 if (InitModeInfo(mode, &mode_info)) | 307 if (InitModeInfo(mode, &mode_info)) |
| 301 output.mode_infos.insert(std::make_pair(mode, mode_info)); | 308 output.mode_infos.insert(std::make_pair(mode, mode_info)); |
| 302 else | 309 else |
| 303 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; | 310 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; |
| 304 } | 311 } |
| 305 | 312 |
| 306 return output; | 313 return output; |
| 307 } | 314 } |
| 308 | 315 |
| 316 bool RealOutputConfiguratorDelegate::GetHDCPState(RROutput id, | |
| 317 HDCPState* state) { | |
| 318 CHECK(screen_) << "Server not grabbed"; | |
| 319 unsigned char* values = NULL; | |
| 320 int actual_format = 0; | |
| 321 unsigned long nitems = 0; | |
| 322 unsigned long bytes_after = 0; | |
| 323 Atom actual_type = None; | |
| 324 int success = 0; | |
| 325 Atom prop = XInternAtom(display_, "Content Protection", False); | |
|
Daniel Erat
2013/09/20 15:00:24
please move this to a constant at the top of the f
kcwu
2013/09/20 20:29:30
Done.
| |
| 326 | |
| 327 bool ok = true; | |
| 328 // TODO(kcwu): Move this to x11_util (similar method calls in this file and | |
| 329 // output_util.cc) | |
| 330 success = XRRGetOutputProperty(display_, id, prop, 0, 100, False, | |
| 331 False, AnyPropertyType, &actual_type, | |
| 332 &actual_format, &nitems, &bytes_after, | |
| 333 &values); | |
| 334 if (actual_type == None) { | |
| 335 LOG(ERROR) << "Property 'Content Protection' does not exist"; | |
| 336 ok = false; | |
| 337 } else if (success == Success && actual_type == XA_ATOM && | |
| 338 actual_format == 32 && nitems == 1) { | |
| 339 Atom value = reinterpret_cast<Atom*>(values)[0]; | |
| 340 if (value == XInternAtom(display_, "Undesired", False)) { | |
|
Daniel Erat
2013/09/20 15:00:24
please make constants for these too so they aren't
kcwu
2013/09/20 20:29:30
Done.
| |
| 341 *state = HDCP_STATE_UNDESIRED; | |
| 342 } else if (value == XInternAtom(display_, "Desired", False)) { | |
| 343 *state = HDCP_STATE_DESIRED; | |
| 344 } else if (value == XInternAtom(display_, "Enabled", False)) { | |
| 345 *state = HDCP_STATE_ENABLED; | |
| 346 } else { | |
| 347 LOG(ERROR) << "Unknown property value: " << value; | |
|
Daniel Erat
2013/09/20 15:00:24
nit: mind changing this to "Unknown " << kContentP
kcwu
2013/09/20 20:29:30
Done.
| |
| 348 ok = false; | |
| 349 } | |
| 350 } else { | |
| 351 LOG(ERROR) << "XRRGetOutputProperty failed"; | |
| 352 ok = false; | |
| 353 } | |
| 354 if (values) | |
| 355 XFree(values); | |
| 356 | |
| 357 VLOG(3) << "HDCP state: " << ok << "," << *state; | |
| 358 return ok; | |
| 359 } | |
| 360 | |
| 361 bool RealOutputConfiguratorDelegate::SetHDCPState(RROutput id, | |
| 362 HDCPState state) { | |
| 363 CHECK(screen_) << "Server not grabbed"; | |
| 364 Atom name = XInternAtom(display_, "Content Protection", False); | |
| 365 Atom value; | |
| 366 switch (state) { | |
| 367 case HDCP_STATE_UNDESIRED: | |
| 368 value = XInternAtom(display_, "Undesired", False); | |
| 369 break; | |
| 370 case HDCP_STATE_DESIRED: | |
| 371 value = XInternAtom(display_, "Desired", False); | |
| 372 break; | |
| 373 default: | |
| 374 NOTREACHED() << "Invalid HDCP state: " << state; | |
| 375 return false; | |
| 376 } | |
| 377 ui::X11ErrorTracker err_tracker; | |
| 378 unsigned char *data = reinterpret_cast<unsigned char*>(&value); | |
| 379 XRRChangeOutputProperty(display_, id, name, XA_ATOM, 32, | |
| 380 PropModeReplace, data, 1); | |
| 381 if (err_tracker.FoundNewError()) { | |
| 382 LOG(ERROR) << "XRRChangeOutputProperty failed"; | |
| 383 return false; | |
| 384 } else { | |
| 385 return true; | |
| 386 } | |
| 387 } | |
| 388 | |
| 389 bool RealOutputConfiguratorDelegate::QueryOutputProtectionLinkType( | |
| 390 RROutput id, | |
| 391 OutputType *link_type) { | |
| 392 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, id); | |
| 393 if (!output_info) { | |
| 394 return false; | |
| 395 } | |
| 396 | |
| 397 bool ok = true; | |
| 398 if (output_info->connection == RR_Connected) { | |
| 399 std::string name(output_info->name); | |
| 400 if (IsInternalOutput(output_info)) { | |
| 401 *link_type = OUTPUT_TYPE_INTERNAL; | |
| 402 } else if (name.find(kOutputName_VGA) == 0) { | |
| 403 *link_type = OUTPUT_TYPE_VGA; | |
| 404 } else if (name.find(kOutputName_HDMI) == 0) { | |
| 405 *link_type = OUTPUT_TYPE_HDMI; | |
| 406 } else if (name.find(kOutputName_DVI) == 0) { | |
| 407 *link_type = OUTPUT_TYPE_DVI; | |
| 408 } else if (name.find(kOutputName_DisplayPort) == 0) { | |
| 409 *link_type = OUTPUT_TYPE_DISPLAYPORT; | |
| 410 } else { | |
| 411 DCHECK(0) << "Unknown link type: " << name; | |
|
Daniel Erat
2013/09/20 15:00:24
use NOTREACHED() or maybe just LOG(ERROR) instead
kcwu
2013/09/20 20:29:30
Done.
| |
| 412 ok = false; | |
| 413 } | |
| 414 } else { | |
| 415 *link_type = OUTPUT_TYPE_NONE; | |
| 416 } | |
| 417 XRRFreeOutputInfo(output_info); | |
| 418 return ok; | |
| 419 } | |
| 420 | |
| 421 bool RealOutputConfiguratorDelegate::EnableOutputProtection( | |
| 422 chromeos::OutputConfigurator::OutputProtectionClientId client_id, | |
| 423 uint32_t desired_method_mask) { | |
| 424 if (desired_method_mask == OUTPUT_PROTECTION_METHOD_NONE) | |
| 425 client_protection_requests_.erase(client_id); | |
| 426 else | |
| 427 client_protection_requests_[client_id] = desired_method_mask; | |
|
Daniel Erat
2013/09/20 15:00:24
should you hold off on updating the request map un
kcwu
2013/09/20 20:29:30
Done.
| |
| 428 | |
| 429 uint32_t all_desires = 0; | |
| 430 for (ProtectionRequests::const_iterator it = | |
| 431 client_protection_requests_.begin(); | |
| 432 it != client_protection_requests_.end(); | |
| 433 ++it) { | |
| 434 all_desires |= it->second; | |
| 435 } | |
| 436 | |
| 437 for (int i = 0; i < screen_->noutput; ++i) { | |
| 438 RROutput this_id = screen_->outputs[i]; | |
| 439 OutputType type; | |
| 440 if (!QueryOutputProtectionLinkType(this_id, &type)) | |
| 441 return false; | |
| 442 | |
| 443 if ((type & OUTPUT_TYPE_HDMI) || | |
| 444 (type & OUTPUT_TYPE_DISPLAYPORT)) { | |
| 445 HDCPState new_desired_state; | |
|
Daniel Erat
2013/09/20 15:00:24
nit:
HDCPState new_desired_state =
(all_d
kcwu
2013/09/20 20:29:30
Done.
| |
| 446 if (all_desires & OUTPUT_PROTECTION_METHOD_HDCP) { | |
| 447 new_desired_state = HDCP_STATE_DESIRED; | |
| 448 } else { | |
| 449 new_desired_state = HDCP_STATE_UNDESIRED; | |
| 450 } | |
| 451 if (!SetHDCPState(this_id, new_desired_state)) | |
| 452 return false; | |
| 453 } | |
| 454 } | |
| 455 return true; | |
| 456 } | |
| 457 | |
| 458 bool RealOutputConfiguratorDelegate::QueryOutputProtectionStatus( | |
| 459 chromeos::OutputConfigurator::OutputProtectionClientId client_id, | |
| 460 uint32_t* link_mask, | |
| 461 uint32_t* protection_mask) { | |
|
Daniel Erat
2013/09/20 15:00:24
mind adding a CHECK(screen_) here too?
but this s
Daniel Erat
2013/09/20 15:08:26
moreover, is there any reason why you can't save t
kcwu
2013/09/20 20:29:30
I'm confused. marcheu said grabbing is not strictl
kcwu
2013/09/20 20:29:30
Ah, I didn't notice OutputSnapshot was added recen
Daniel Erat
2013/09/20 20:40:59
screen_ is only valid while the server is grabbed
kcwu
2013/09/23 18:00:02
Done.
| |
| 462 uint32_t enabled = 0; | |
| 463 uint32_t unfulfilled = 0; | |
| 464 | |
| 465 *link_mask = 0; | |
| 466 for (int i = 0; i < screen_->noutput; ++i) { | |
| 467 RROutput this_id = screen_->outputs[i]; | |
| 468 OutputType type; | |
| 469 if (!QueryOutputProtectionLinkType(this_id, &type)) | |
| 470 return false; | |
| 471 *link_mask |= type; | |
| 472 | |
| 473 if ((type & OUTPUT_TYPE_HDMI) || | |
| 474 (type & OUTPUT_TYPE_DISPLAYPORT)) { | |
| 475 HDCPState state; | |
| 476 RROutput this_id = screen_->outputs[i]; | |
|
Daniel Erat
2013/09/20 15:00:24
i think you're shadowing the earlier |this_id| var
kcwu
2013/09/20 20:29:30
Done.
| |
| 477 if (!GetHDCPState(this_id, &state)) | |
| 478 return false; | |
| 479 if (state == HDCP_STATE_ENABLED) | |
| 480 enabled |= OUTPUT_PROTECTION_METHOD_HDCP; | |
| 481 else | |
| 482 unfulfilled |= OUTPUT_PROTECTION_METHOD_HDCP; | |
| 483 } | |
| 484 } | |
| 485 | |
| 486 // Don't reveal protections requested by other clients. | |
| 487 ProtectionRequests::iterator it = client_protection_requests_.find(client_id); | |
| 488 if (it != client_protection_requests_.end()) { | |
| 489 uint32_t requested_mask = it->second; | |
| 490 *protection_mask = enabled & ~unfulfilled & requested_mask; | |
| 491 } else { | |
| 492 *protection_mask = 0; | |
| 493 } | |
| 494 return true; | |
| 495 } | |
| 496 | |
| 309 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( | 497 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( |
| 310 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { | 498 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { |
| 311 CHECK(screen_) << "Server not grabbed"; | 499 CHECK(screen_) << "Server not grabbed"; |
| 312 // Setting the screen size will fail if any CRTC doesn't fit afterwards. | 500 // Setting the screen size will fail if any CRTC doesn't fit afterwards. |
| 313 // At the same time, turning CRTCs off and back on uses up a lot of time. | 501 // At the same time, turning CRTCs off and back on uses up a lot of time. |
| 314 // This function tries to be smart to avoid too many off/on cycles: | 502 // This function tries to be smart to avoid too many off/on cycles: |
| 315 // - We disable all the CRTCs we won't need after the FB resize. | 503 // - We disable all the CRTCs we won't need after the FB resize. |
| 316 // - We set the new modes on CRTCs, if they fit in both the old and new | 504 // - We set the new modes on CRTCs, if they fit in both the old and new |
| 317 // FBs, and park them at (0,0) | 505 // FBs, and park them at (0,0) |
| 318 // - We disable the CRTCs we will need but don't fit in the old FB. Those | 506 // - We disable the CRTCs we will need but don't fit in the old FB. Those |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 500 << (*outputs)[i].touch_device_id << " to output #" << i; | 688 << (*outputs)[i].touch_device_id << " to output #" << i; |
| 501 break; | 689 break; |
| 502 } | 690 } |
| 503 } | 691 } |
| 504 } | 692 } |
| 505 | 693 |
| 506 XIFreeDeviceInfo(info); | 694 XIFreeDeviceInfo(info); |
| 507 } | 695 } |
| 508 | 696 |
| 509 } // namespace chromeos | 697 } // namespace chromeos |
| OLD | NEW |