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> |
(...skipping 12 matching lines...) Expand all Loading... | |
23 | 23 |
24 namespace chromeos { | 24 namespace chromeos { |
25 | 25 |
26 namespace { | 26 namespace { |
27 | 27 |
28 // DPI measurements. | 28 // DPI measurements. |
29 const float kMmInInch = 25.4; | 29 const float kMmInInch = 25.4; |
30 const float kDpi96 = 96.0; | 30 const float kDpi96 = 96.0; |
31 const float kPixelsToMmScale = kMmInInch / kDpi96; | 31 const float kPixelsToMmScale = kMmInInch / kDpi96; |
32 | 32 |
33 // Prefixes of output name | |
34 const char kOutputPortName_VGA[] = "VGA"; | |
Daniel Erat
2013/09/18 22:39:16
nit: remove underscores from constant identifiers
kcwu
2013/09/20 03:03:47
This naming style follows kInternal_* as marcheu m
| |
35 const char kOutputPortName_HDMI[] = "HDMI"; | |
36 const char kOutputPortName_DVI[] = "DVI"; | |
37 const char kOutputPortName_DisplayPort[] = "DP"; | |
marcheu
2013/09/18 23:21:35
I think just "OutputName_*" is fine, the "OutputPo
kcwu
2013/09/20 03:03:47
Done. I changed they as kOutputName_*.
These names
| |
38 | |
33 bool IsInternalOutput(const XRROutputInfo* output_info) { | 39 bool IsInternalOutput(const XRROutputInfo* output_info) { |
34 return IsInternalOutputName(std::string(output_info->name)); | 40 return IsInternalOutputName(std::string(output_info->name)); |
35 } | 41 } |
36 | 42 |
37 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { | 43 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { |
38 return output_info->nmode > 0 ? output_info->modes[0] : None; | 44 return output_info->nmode > 0 ? output_info->modes[0] : None; |
39 } | 45 } |
40 | 46 |
41 } // namespace | 47 } // namespace |
42 | 48 |
43 RealOutputConfiguratorDelegate::RealOutputConfiguratorDelegate() | 49 RealOutputConfiguratorDelegate::RealOutputConfiguratorDelegate() |
44 : display_(base::MessagePumpAuraX11::GetDefaultXDisplay()), | 50 : display_(base::MessagePumpAuraX11::GetDefaultXDisplay()), |
45 window_(DefaultRootWindow(display_)), | 51 window_(DefaultRootWindow(display_)), |
46 screen_(NULL), | 52 screen_(NULL), |
47 is_panel_fitting_enabled_(false) { | 53 is_panel_fitting_enabled_(false), |
54 next_client_id_(1) { | |
48 } | 55 } |
49 | 56 |
50 RealOutputConfiguratorDelegate::~RealOutputConfiguratorDelegate() { | 57 RealOutputConfiguratorDelegate::~RealOutputConfiguratorDelegate() { |
51 } | 58 } |
52 | 59 |
53 void RealOutputConfiguratorDelegate::SetPanelFittingEnabled(bool enabled) { | 60 void RealOutputConfiguratorDelegate::SetPanelFittingEnabled(bool enabled) { |
54 is_panel_fitting_enabled_ = enabled; | 61 is_panel_fitting_enabled_ = enabled; |
55 } | 62 } |
56 | 63 |
57 void RealOutputConfiguratorDelegate::InitXRandRExtension(int* event_base) { | 64 void RealOutputConfiguratorDelegate::InitXRandRExtension(int* event_base) { |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
363 &mode_info.interlaced)) { | 370 &mode_info.interlaced)) { |
364 output.mode_infos.insert(std::make_pair(mode, mode_info)); | 371 output.mode_infos.insert(std::make_pair(mode, mode_info)); |
365 } else { | 372 } else { |
366 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; | 373 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; |
367 } | 374 } |
368 } | 375 } |
369 | 376 |
370 return output; | 377 return output; |
371 } | 378 } |
372 | 379 |
380 bool RealOutputConfiguratorDelegate::GetHDCPState(RROutput id, | |
381 HDCPState* state) { | |
382 CHECK(screen_) << "Server not grabbed"; | |
383 unsigned char* values = NULL; | |
384 int actual_format = 0; | |
385 unsigned long nitems = 0; | |
386 unsigned long bytes_after = 0; | |
387 Atom actual_type = None; | |
388 int success = 0; | |
389 Atom prop = XInternAtom(display_, "Content Protection", False); | |
390 | |
391 bool ok = true; | |
392 success = XRRGetOutputProperty(display_, id, prop, 0, 100, False, | |
Daniel Erat
2013/09/18 22:39:16
please add a TODO to move this to x11_util (simila
kcwu
2013/09/20 03:03:47
Done.
| |
393 False, AnyPropertyType, &actual_type, | |
394 &actual_format, &nitems, &bytes_after, | |
395 &values); | |
396 if (actual_type == None) { | |
397 LOG(ERROR) << "Property 'Content Protection' does not exist"; | |
398 ok = false; | |
399 } else if (success == Success && actual_type == XA_ATOM && | |
400 actual_format == 32 && nitems == 1) { | |
401 Atom value = reinterpret_cast<Atom*>(values)[0]; | |
402 if (value == XInternAtom(display_, "Undesired", False)) { | |
403 *state = HDCP_State_Undesired; | |
404 } else if (value == XInternAtom(display_, "Desired", False)) { | |
405 *state = HDCP_State_Desired; | |
406 } else if (value == XInternAtom(display_, "Enabled", False)) { | |
407 *state = HDCP_State_Enabled; | |
408 } else { | |
409 LOG(ERROR) << "Unknown property value: " << value; | |
410 ok = false; | |
411 } | |
412 } else { | |
413 LOG(ERROR) << "XRRGetOutputProperty failed"; | |
414 ok = false; | |
415 } | |
416 if (values) | |
417 XFree(values); | |
418 | |
419 VLOG(3) << "HDCP state: " << ok << "," << *state; | |
420 return ok; | |
421 } | |
422 | |
423 bool RealOutputConfiguratorDelegate::SetHDCPState(RROutput id, | |
424 HDCPState state) { | |
425 CHECK(screen_) << "Server not grabbed"; | |
426 Atom name = XInternAtom(display_, "Content Protection", False); | |
427 Atom value; | |
428 switch (state) { | |
429 case HDCP_State_Undesired: | |
430 value = XInternAtom(display_, "Undesired", False); | |
431 break; | |
432 case HDCP_State_Desired: | |
433 value = XInternAtom(display_, "Desired", False); | |
434 break; | |
435 default: | |
436 NOTREACHED() << "Invalid HDCP state: " << state; | |
437 return false; | |
438 } | |
439 unsigned char *data = reinterpret_cast<unsigned char*>(&value); | |
440 XRRChangeOutputProperty(display_, id, name, XA_ATOM, 32, | |
441 PropModeReplace, data, 1); | |
marcheu
2013/09/18 23:21:35
Hmm, we probably shouldn't return true here withou
kcwu
2013/09/20 03:03:47
Done.
| |
442 return true; | |
443 } | |
444 | |
445 uint64_t RealOutputConfiguratorDelegate::RegisterOutputProtectionClient() { | |
446 return next_client_id_++; | |
447 } | |
448 | |
449 void RealOutputConfiguratorDelegate::UnregisterOutputProtectionClient( | |
450 uint64_t client_id) { | |
451 EnableOutputProtection(client_id, OUTPUT_PROTECTION_METHOD_NONE); | |
452 } | |
453 | |
454 bool RealOutputConfiguratorDelegate::QueryOutputProtectionLinkType( | |
455 RROutput id, | |
456 OutputLinkType *link_type) { | |
457 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, id); | |
458 if (!output_info) { | |
459 return false; | |
460 } | |
461 | |
462 bool ok = true; | |
463 if (output_info->connection == RR_Connected) { | |
464 std::string name(output_info->name); | |
465 if (IsInternalOutput(output_info)) { | |
466 *link_type = OUTPUT_LINK_TYPE_INTERNAL; | |
467 } else if (name.find(kOutputPortName_VGA) == 0) { | |
468 *link_type = OUTPUT_LINK_TYPE_VGA; | |
469 } else if (name.find(kOutputPortName_HDMI) == 0) { | |
470 *link_type = OUTPUT_LINK_TYPE_HDMI; | |
471 } else if (name.find(kOutputPortName_DVI) == 0) { | |
472 *link_type = OUTPUT_LINK_TYPE_DVI; | |
473 } else if (name.find(kOutputPortName_DisplayPort) == 0) { | |
474 *link_type = OUTPUT_LINK_TYPE_DISPLAYPORT; | |
475 } else { | |
476 DCHECK(0) << "Unknown link type: " << name; | |
477 ok = false; | |
478 } | |
479 } else { | |
480 *link_type = OUTPUT_LINK_TYPE_NONE; | |
481 } | |
482 XRRFreeOutputInfo(output_info); | |
483 return ok; | |
484 } | |
485 | |
486 bool RealOutputConfiguratorDelegate::EnableOutputProtection( | |
487 uint64_t client_id, | |
488 uint32_t desired_method_mask) { | |
489 if (desired_method_mask == OUTPUT_PROTECTION_METHOD_NONE) | |
490 client_protection_requests_.erase(client_id); | |
491 else | |
492 client_protection_requests_[client_id] = desired_method_mask; | |
493 | |
494 uint32_t all_desires = 0; | |
495 for (ProtectionRequests::const_iterator it = | |
496 client_protection_requests_.begin(); | |
497 it != client_protection_requests_.end(); | |
498 ++it) { | |
499 all_desires |= it->second; | |
500 } | |
501 | |
502 for (int i = 0; i < screen_->noutput; ++i) { | |
503 RROutput this_id = screen_->outputs[i]; | |
504 OutputLinkType type; | |
505 if (!QueryOutputProtectionLinkType(this_id, &type)) | |
506 return false; | |
507 | |
508 if ((type & OUTPUT_LINK_TYPE_HDMI) || | |
509 (type & OUTPUT_LINK_TYPE_DISPLAYPORT)) { | |
510 HDCPState new_desired_state; | |
511 if (all_desires & OUTPUT_PROTECTION_METHOD_HDCP) { | |
512 new_desired_state = HDCP_State_Desired; | |
513 } else { | |
514 new_desired_state = HDCP_State_Undesired; | |
515 } | |
516 if (!SetHDCPState(this_id, new_desired_state)) | |
517 return false; | |
518 } | |
519 } | |
520 return true; | |
521 } | |
522 | |
523 bool RealOutputConfiguratorDelegate::QueryOutputProtectionStatus( | |
524 uint64_t client_id, | |
525 uint32_t* link_mask, | |
526 uint32_t* protection_mask) { | |
527 uint32_t enabled = 0; | |
528 uint32_t unfulfilled = 0; | |
529 | |
530 *link_mask = 0; | |
531 for (int i = 0; i < screen_->noutput; ++i) { | |
532 RROutput this_id = screen_->outputs[i]; | |
533 OutputLinkType type; | |
534 if (!QueryOutputProtectionLinkType(this_id, &type)) | |
535 return false; | |
536 *link_mask |= type; | |
537 | |
538 if ((type & OUTPUT_LINK_TYPE_HDMI) || | |
539 (type & OUTPUT_LINK_TYPE_DISPLAYPORT)) { | |
540 HDCPState state; | |
541 RROutput this_id = screen_->outputs[i]; | |
542 if (!GetHDCPState(this_id, &state)) | |
543 return false; | |
544 if (state == HDCP_State_Enabled) | |
545 enabled |= OUTPUT_PROTECTION_METHOD_HDCP; | |
546 else | |
547 unfulfilled |= OUTPUT_PROTECTION_METHOD_HDCP; | |
548 } | |
549 } | |
550 | |
551 // Don't reveal protections requested by other clients. | |
552 ProtectionRequests::iterator it = client_protection_requests_.find(client_id); | |
553 if (it != client_protection_requests_.end()) { | |
554 uint32_t requested_mask = it->second; | |
555 *protection_mask = enabled & ~unfulfilled & requested_mask; | |
556 } else { | |
557 *protection_mask = 0; | |
558 } | |
559 return true; | |
560 } | |
561 | |
373 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( | 562 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( |
374 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { | 563 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { |
375 CHECK(screen_) << "Server not grabbed"; | 564 CHECK(screen_) << "Server not grabbed"; |
376 // Setting the screen size will fail if any CRTC doesn't fit afterwards. | 565 // Setting the screen size will fail if any CRTC doesn't fit afterwards. |
377 // At the same time, turning CRTCs off and back on uses up a lot of time. | 566 // At the same time, turning CRTCs off and back on uses up a lot of time. |
378 // This function tries to be smart to avoid too many off/on cycles: | 567 // This function tries to be smart to avoid too many off/on cycles: |
379 // - We disable all the CRTCs we won't need after the FB resize. | 568 // - We disable all the CRTCs we won't need after the FB resize. |
380 // - We set the new modes on CRTCs, if they fit in both the old and new | 569 // - We set the new modes on CRTCs, if they fit in both the old and new |
381 // FBs, and park them at (0,0) | 570 // FBs, and park them at (0,0) |
382 // - We disable the CRTCs we will need but don't fit in the old FB. Those | 571 // - We disable the CRTCs we will need but don't fit in the old FB. Those |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
638 << (*outputs)[i].touch_device_id << " to output #" << i; | 827 << (*outputs)[i].touch_device_id << " to output #" << i; |
639 break; | 828 break; |
640 } | 829 } |
641 } | 830 } |
642 } | 831 } |
643 | 832 |
644 XIFreeDeviceInfo(info); | 833 XIFreeDeviceInfo(info); |
645 } | 834 } |
646 | 835 |
647 } // namespace chromeos | 836 } // namespace chromeos |
OLD | NEW |