| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/output_configurator.h" | 5 #include "chromeos/display/output_configurator.h" |
| 6 | 6 |
| 7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
| 8 #include <X11/extensions/Xrandr.h> | 8 #include <X11/extensions/Xrandr.h> |
| 9 #include <X11/extensions/XInput2.h> | 9 #include <X11/extensions/XInput2.h> |
| 10 | 10 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 for (size_t i = 0; i < outputs.size(); ++i) | 91 for (size_t i = 0; i < outputs.size(); ++i) |
| 92 has_internal_output |= outputs[i].is_internal; | 92 has_internal_output |= outputs[i].is_internal; |
| 93 | 93 |
| 94 // "Projecting" is defined as having more than 1 output connected while at | 94 // "Projecting" is defined as having more than 1 output connected while at |
| 95 // least one of them is an internal output. | 95 // least one of them is an internal output. |
| 96 return has_internal_output && (connected_output_count > 1); | 96 return has_internal_output && (connected_output_count > 1); |
| 97 } | 97 } |
| 98 | 98 |
| 99 } // namespace | 99 } // namespace |
| 100 | 100 |
| 101 OutputConfigurator::ModeInfo::ModeInfo() |
| 102 : width(0), |
| 103 height(0), |
| 104 interlaced(false) {} |
| 105 |
| 101 OutputConfigurator::CoordinateTransformation::CoordinateTransformation() | 106 OutputConfigurator::CoordinateTransformation::CoordinateTransformation() |
| 102 : x_scale(1.0), | 107 : x_scale(1.0), |
| 103 x_offset(0.0), | 108 x_offset(0.0), |
| 104 y_scale(1.0), | 109 y_scale(1.0), |
| 105 y_offset(0.0) {} | 110 y_offset(0.0) {} |
| 106 | 111 |
| 107 OutputConfigurator::OutputSnapshot::OutputSnapshot() | 112 OutputConfigurator::OutputSnapshot::OutputSnapshot() |
| 108 : output(None), | 113 : output(None), |
| 109 crtc(None), | 114 crtc(None), |
| 110 current_mode(None), | 115 current_mode(None), |
| 111 native_mode(None), | 116 native_mode(None), |
| 112 mirror_mode(None), | 117 mirror_mode(None), |
| 113 selected_mode(None), | 118 selected_mode(None), |
| 114 x(0), | 119 x(0), |
| 115 y(0), | 120 y(0), |
| 121 width_mm(0), |
| 122 height_mm(0), |
| 116 is_internal(false), | 123 is_internal(false), |
| 117 is_aspect_preserving_scaling(false), | 124 is_aspect_preserving_scaling(false), |
| 118 touch_device_id(0), | 125 touch_device_id(0), |
| 119 display_id(0), | 126 display_id(0), |
| 120 has_display_id(false) {} | 127 has_display_id(false) {} |
| 121 | 128 |
| 122 void OutputConfigurator::TestApi::SendScreenChangeEvent() { | 129 void OutputConfigurator::TestApi::SendScreenChangeEvent() { |
| 123 XRRScreenChangeNotifyEvent event = {0}; | 130 XRRScreenChangeNotifyEvent event = {0}; |
| 124 event.type = xrandr_event_base_ + RRScreenChangeNotify; | 131 event.type = xrandr_event_base_ + RRScreenChangeNotify; |
| 125 configurator_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event)); | 132 configurator_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 143 if (configurator_->configure_timer_.get() && | 150 if (configurator_->configure_timer_.get() && |
| 144 configurator_->configure_timer_->IsRunning()) { | 151 configurator_->configure_timer_->IsRunning()) { |
| 145 configurator_->configure_timer_.reset(); | 152 configurator_->configure_timer_.reset(); |
| 146 configurator_->ConfigureOutputs(); | 153 configurator_->ConfigureOutputs(); |
| 147 return true; | 154 return true; |
| 148 } else { | 155 } else { |
| 149 return false; | 156 return false; |
| 150 } | 157 } |
| 151 } | 158 } |
| 152 | 159 |
| 160 // static |
| 161 const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo( |
| 162 const OutputSnapshot& output, |
| 163 RRMode mode) { |
| 164 std::map<RRMode, ModeInfo>::const_iterator it = output.mode_infos.find(mode); |
| 165 if (it == output.mode_infos.end()) { |
| 166 LOG(WARNING) << "Unable to find info about mode " << mode |
| 167 << " for output " << output.output; |
| 168 return NULL; |
| 169 } |
| 170 return &it->second; |
| 171 } |
| 172 |
| 153 OutputConfigurator::OutputConfigurator() | 173 OutputConfigurator::OutputConfigurator() |
| 154 : state_controller_(NULL), | 174 : state_controller_(NULL), |
| 155 mirroring_controller_(NULL), | 175 mirroring_controller_(NULL), |
| 156 configure_display_(base::chromeos::IsRunningOnChromeOS()), | 176 configure_display_(base::chromeos::IsRunningOnChromeOS()), |
| 157 xrandr_event_base_(0), | 177 xrandr_event_base_(0), |
| 158 output_state_(STATE_INVALID), | 178 output_state_(STATE_INVALID), |
| 159 power_state_(DISPLAY_POWER_ALL_ON) { | 179 power_state_(DISPLAY_POWER_ALL_ON) { |
| 160 } | 180 } |
| 161 | 181 |
| 162 OutputConfigurator::~OutputConfigurator() {} | 182 OutputConfigurator::~OutputConfigurator() {} |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 if (success) { | 418 if (success) { |
| 399 NotifyOnDisplayChanged(); | 419 NotifyOnDisplayChanged(); |
| 400 } else { | 420 } else { |
| 401 FOR_EACH_OBSERVER( | 421 FOR_EACH_OBSERVER( |
| 402 Observer, observers_, OnDisplayModeChangeFailed(new_state)); | 422 Observer, observers_, OnDisplayModeChangeFailed(new_state)); |
| 403 } | 423 } |
| 404 delegate_->SendProjectingStateToPowerManager(IsProjecting(outputs)); | 424 delegate_->SendProjectingStateToPowerManager(IsProjecting(outputs)); |
| 405 } | 425 } |
| 406 | 426 |
| 407 void OutputConfigurator::NotifyOnDisplayChanged() { | 427 void OutputConfigurator::NotifyOnDisplayChanged() { |
| 408 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); | 428 FOR_EACH_OBSERVER(Observer, observers_, |
| 429 OnDisplayModeChanged(cached_outputs_)); |
| 409 } | 430 } |
| 410 | 431 |
| 411 bool OutputConfigurator::EnterStateOrFallBackToSoftwareMirroring( | 432 bool OutputConfigurator::EnterStateOrFallBackToSoftwareMirroring( |
| 412 OutputState output_state, | 433 OutputState output_state, |
| 413 DisplayPowerState power_state, | 434 DisplayPowerState power_state, |
| 414 const std::vector<OutputSnapshot>& outputs) { | 435 const std::vector<OutputSnapshot>& outputs) { |
| 415 bool success = EnterState(output_state, power_state, outputs); | 436 bool success = EnterState(output_state, power_state, outputs); |
| 416 if (mirroring_controller_) { | 437 if (mirroring_controller_) { |
| 417 bool enable_software_mirroring = false; | 438 bool enable_software_mirroring = false; |
| 418 if (!success && output_state == STATE_DUAL_MIRROR) { | 439 if (!success && output_state == STATE_DUAL_MIRROR) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 return false; | 481 return false; |
| 461 } | 482 } |
| 462 | 483 |
| 463 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 484 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
| 464 OutputSnapshot* output = &updated_outputs[i]; | 485 OutputSnapshot* output = &updated_outputs[i]; |
| 465 output->x = 0; | 486 output->x = 0; |
| 466 output->y = 0; | 487 output->y = 0; |
| 467 output->current_mode = output_power[i] ? output->selected_mode : None; | 488 output->current_mode = output_power[i] ? output->selected_mode : None; |
| 468 | 489 |
| 469 if (output_power[i] || outputs.size() == 1) { | 490 if (output_power[i] || outputs.size() == 1) { |
| 470 if (!delegate_->GetModeDetails( | 491 const ModeInfo* mode_info = |
| 471 output->selected_mode, &width, &height, NULL)) | 492 GetModeInfo(*output, output->selected_mode); |
| 493 if (!mode_info) |
| 472 return false; | 494 return false; |
| 495 width = mode_info->width; |
| 496 height = mode_info->height; |
| 473 } | 497 } |
| 474 } | 498 } |
| 475 break; | 499 break; |
| 476 } | 500 } |
| 477 case STATE_DUAL_MIRROR: { | 501 case STATE_DUAL_MIRROR: { |
| 478 if (outputs.size() != 2 || (num_on_outputs != 0 && num_on_outputs != 2)) { | 502 if (outputs.size() != 2 || (num_on_outputs != 0 && num_on_outputs != 2)) { |
| 479 LOG(WARNING) << "Ignoring request to enter mirrored mode with " | 503 LOG(WARNING) << "Ignoring request to enter mirrored mode with " |
| 480 << outputs.size() << " connected output(s) and " | 504 << outputs.size() << " connected output(s) and " |
| 481 << num_on_outputs << " turned on"; | 505 << num_on_outputs << " turned on"; |
| 482 return false; | 506 return false; |
| 483 } | 507 } |
| 484 | 508 |
| 485 if (!delegate_->GetModeDetails( | 509 if (!outputs[0].mirror_mode) |
| 486 outputs[0].mirror_mode, &width, &height, NULL)) | |
| 487 return false; | 510 return false; |
| 511 const ModeInfo* mode_info = |
| 512 GetModeInfo(outputs[0], outputs[0].mirror_mode); |
| 513 if (!mode_info) |
| 514 return false; |
| 515 width = mode_info->width; |
| 516 height = mode_info->height; |
| 488 | 517 |
| 489 for (size_t i = 0; i < outputs.size(); ++i) { | 518 for (size_t i = 0; i < outputs.size(); ++i) { |
| 490 OutputSnapshot* output = &updated_outputs[i]; | 519 OutputSnapshot* output = &updated_outputs[i]; |
| 491 output->x = 0; | 520 output->x = 0; |
| 492 output->y = 0; | 521 output->y = 0; |
| 493 output->current_mode = output_power[i] ? output->mirror_mode : None; | 522 output->current_mode = output_power[i] ? output->mirror_mode : None; |
| 494 if (output->touch_device_id) { | 523 if (output->touch_device_id) { |
| 495 // CTM needs to be calculated if aspect preserving scaling is used. | 524 // CTM needs to be calculated if aspect preserving scaling is used. |
| 496 // Otherwise, assume it is full screen, and use identity CTM. | 525 // Otherwise, assume it is full screen, and use identity CTM. |
| 497 if (output->mirror_mode != output->native_mode && | 526 if (output->mirror_mode != output->native_mode && |
| 498 output->is_aspect_preserving_scaling) { | 527 output->is_aspect_preserving_scaling) { |
| 499 output->transform = GetMirrorModeCTM(output); | 528 output->transform = GetMirrorModeCTM(*output); |
| 500 mirrored_display_area_ratio_map_[output->touch_device_id] = | 529 mirrored_display_area_ratio_map_[output->touch_device_id] = |
| 501 GetMirroredDisplayAreaRatio(output); | 530 GetMirroredDisplayAreaRatio(*output); |
| 502 } | 531 } |
| 503 } | 532 } |
| 504 } | 533 } |
| 505 break; | 534 break; |
| 506 } | 535 } |
| 507 case STATE_DUAL_EXTENDED: { | 536 case STATE_DUAL_EXTENDED: { |
| 508 if (outputs.size() != 2 || (num_on_outputs != 0 && num_on_outputs != 2)) { | 537 if (outputs.size() != 2 || (num_on_outputs != 0 && num_on_outputs != 2)) { |
| 509 LOG(WARNING) << "Ignoring request to enter extended mode with " | 538 LOG(WARNING) << "Ignoring request to enter extended mode with " |
| 510 << outputs.size() << " connected output(s) and " | 539 << outputs.size() << " connected output(s) and " |
| 511 << num_on_outputs << " turned on"; | 540 << num_on_outputs << " turned on"; |
| 512 return false; | 541 return false; |
| 513 } | 542 } |
| 514 | 543 |
| 515 // Pairs are [width, height] corresponding to the given output's mode. | |
| 516 std::vector<std::pair<int, int> > mode_sizes(outputs.size()); | |
| 517 | |
| 518 for (size_t i = 0; i < outputs.size(); ++i) { | 544 for (size_t i = 0; i < outputs.size(); ++i) { |
| 519 if (!delegate_->GetModeDetails(outputs[i].selected_mode, | |
| 520 &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) { | |
| 521 return false; | |
| 522 } | |
| 523 | |
| 524 OutputSnapshot* output = &updated_outputs[i]; | 545 OutputSnapshot* output = &updated_outputs[i]; |
| 525 output->x = 0; | 546 output->x = 0; |
| 526 output->y = height ? height + kVerticalGap : 0; | 547 output->y = height ? height + kVerticalGap : 0; |
| 527 output->current_mode = output_power[i] ? output->selected_mode : None; | 548 output->current_mode = output_power[i] ? output->selected_mode : None; |
| 528 | 549 |
| 529 // Retain the full screen size even if all outputs are off so the | 550 // Retain the full screen size even if all outputs are off so the |
| 530 // same desktop configuration can be restored when the outputs are | 551 // same desktop configuration can be restored when the outputs are |
| 531 // turned back on. | 552 // turned back on. |
| 532 width = std::max<int>(width, mode_sizes[i].first); | 553 const ModeInfo* mode_info = |
| 533 height += (height ? kVerticalGap : 0) + mode_sizes[i].second; | 554 GetModeInfo(outputs[i], outputs[i].selected_mode); |
| 555 if (!mode_info) |
| 556 return false; |
| 557 width = std::max<int>(width, mode_info->width); |
| 558 height += (height ? kVerticalGap : 0) + mode_info->height; |
| 534 } | 559 } |
| 535 | 560 |
| 536 for (size_t i = 0; i < outputs.size(); ++i) { | 561 for (size_t i = 0; i < outputs.size(); ++i) { |
| 537 OutputSnapshot* output = &updated_outputs[i]; | 562 OutputSnapshot* output = &updated_outputs[i]; |
| 538 if (output->touch_device_id) { | 563 if (output->touch_device_id) { |
| 564 const ModeInfo* mode_info = |
| 565 GetModeInfo(*output, output->selected_mode); |
| 566 DCHECK(mode_info); |
| 539 CoordinateTransformation* ctm = &(output->transform); | 567 CoordinateTransformation* ctm = &(output->transform); |
| 540 ctm->x_scale = static_cast<float>(mode_sizes[i].first) / width; | 568 ctm->x_scale = static_cast<float>(mode_info->width) / width; |
| 541 ctm->x_offset = static_cast<float>(output->x) / width; | 569 ctm->x_offset = static_cast<float>(output->x) / width; |
| 542 ctm->y_scale = static_cast<float>(mode_sizes[i].second) / height; | 570 ctm->y_scale = static_cast<float>(mode_info->height) / height; |
| 543 ctm->y_offset = static_cast<float>(output->y) / height; | 571 ctm->y_offset = static_cast<float>(output->y) / height; |
| 544 } | 572 } |
| 545 } | 573 } |
| 546 break; | 574 break; |
| 547 } | 575 } |
| 548 } | 576 } |
| 549 | 577 |
| 550 // Finally, apply the desired changes. | 578 // Finally, apply the desired changes. |
| 551 DCHECK_EQ(outputs.size(), updated_outputs.size()); | 579 DCHECK_EQ(outputs.size(), updated_outputs.size()); |
| 552 if (!outputs.empty()) { | 580 if (!outputs.empty()) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 } | 630 } |
| 603 } | 631 } |
| 604 default: | 632 default: |
| 605 NOTREACHED(); | 633 NOTREACHED(); |
| 606 } | 634 } |
| 607 return STATE_INVALID; | 635 return STATE_INVALID; |
| 608 } | 636 } |
| 609 | 637 |
| 610 OutputConfigurator::CoordinateTransformation | 638 OutputConfigurator::CoordinateTransformation |
| 611 OutputConfigurator::GetMirrorModeCTM( | 639 OutputConfigurator::GetMirrorModeCTM( |
| 612 const OutputConfigurator::OutputSnapshot* output) { | 640 const OutputConfigurator::OutputSnapshot& output) { |
| 613 CoordinateTransformation ctm; // Default to identity | 641 CoordinateTransformation ctm; // Default to identity |
| 614 int native_mode_width = 0, native_mode_height = 0; | 642 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); |
| 615 int mirror_mode_width = 0, mirror_mode_height = 0; | 643 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); |
| 616 if (!delegate_->GetModeDetails(output->native_mode, | 644 |
| 617 &native_mode_width, &native_mode_height, NULL) || | 645 if (!native_mode_info || !mirror_mode_info || |
| 618 !delegate_->GetModeDetails(output->mirror_mode, | 646 native_mode_info->height == 0 || mirror_mode_info->height == 0 || |
| 619 &mirror_mode_width, &mirror_mode_height, NULL)) | 647 native_mode_info->width == 0 || mirror_mode_info->width == 0) |
| 620 return ctm; | 648 return ctm; |
| 621 | 649 |
| 622 if (native_mode_height == 0 || mirror_mode_height == 0 || | 650 float native_mode_ar = static_cast<float>(native_mode_info->width) / |
| 623 native_mode_width == 0 || mirror_mode_width == 0) | 651 static_cast<float>(native_mode_info->height); |
| 624 return ctm; | 652 float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) / |
| 625 | 653 static_cast<float>(mirror_mode_info->height); |
| 626 float native_mode_ar = static_cast<float>(native_mode_width) / | |
| 627 static_cast<float>(native_mode_height); | |
| 628 float mirror_mode_ar = static_cast<float>(mirror_mode_width) / | |
| 629 static_cast<float>(mirror_mode_height); | |
| 630 | 654 |
| 631 if (mirror_mode_ar > native_mode_ar) { // Letterboxing | 655 if (mirror_mode_ar > native_mode_ar) { // Letterboxing |
| 632 ctm.x_scale = 1.0; | 656 ctm.x_scale = 1.0; |
| 633 ctm.x_offset = 0.0; | 657 ctm.x_offset = 0.0; |
| 634 ctm.y_scale = mirror_mode_ar / native_mode_ar; | 658 ctm.y_scale = mirror_mode_ar / native_mode_ar; |
| 635 ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5; | 659 ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5; |
| 636 return ctm; | 660 return ctm; |
| 637 } | 661 } |
| 638 if (native_mode_ar > mirror_mode_ar) { // Pillarboxing | 662 if (native_mode_ar > mirror_mode_ar) { // Pillarboxing |
| 639 ctm.y_scale = 1.0; | 663 ctm.y_scale = 1.0; |
| 640 ctm.y_offset = 0.0; | 664 ctm.y_offset = 0.0; |
| 641 ctm.x_scale = native_mode_ar / mirror_mode_ar; | 665 ctm.x_scale = native_mode_ar / mirror_mode_ar; |
| 642 ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5; | 666 ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5; |
| 643 return ctm; | 667 return ctm; |
| 644 } | 668 } |
| 645 | 669 |
| 646 return ctm; // Same aspect ratio - return identity | 670 return ctm; // Same aspect ratio - return identity |
| 647 } | 671 } |
| 648 | 672 |
| 649 float OutputConfigurator::GetMirroredDisplayAreaRatio( | 673 float OutputConfigurator::GetMirroredDisplayAreaRatio( |
| 650 const OutputConfigurator::OutputSnapshot* output) { | 674 const OutputConfigurator::OutputSnapshot& output) { |
| 651 float area_ratio = 1.0f; | 675 float area_ratio = 1.0f; |
| 652 int native_mode_width = 0, native_mode_height = 0; | 676 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); |
| 653 int mirror_mode_width = 0, mirror_mode_height = 0; | 677 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); |
| 654 if (!delegate_->GetModeDetails(output->native_mode, | 678 |
| 655 &native_mode_width, &native_mode_height, NULL) || | 679 if (!native_mode_info || !mirror_mode_info || |
| 656 !delegate_->GetModeDetails(output->mirror_mode, | 680 native_mode_info->height == 0 || mirror_mode_info->height == 0 || |
| 657 &mirror_mode_width, &mirror_mode_height, NULL)) | 681 native_mode_info->width == 0 || mirror_mode_info->width == 0) |
| 658 return area_ratio; | 682 return area_ratio; |
| 659 | 683 |
| 660 if (native_mode_height == 0 || mirror_mode_height == 0 || | 684 float width_ratio = static_cast<float>(mirror_mode_info->width) / |
| 661 native_mode_width == 0 || mirror_mode_width == 0) | 685 static_cast<float>(native_mode_info->width); |
| 662 return area_ratio; | 686 float height_ratio = static_cast<float>(mirror_mode_info->height) / |
| 663 | 687 static_cast<float>(native_mode_info->height); |
| 664 float width_ratio = static_cast<float>(mirror_mode_width) / | |
| 665 static_cast<float>(native_mode_width); | |
| 666 float height_ratio = static_cast<float>(mirror_mode_height) / | |
| 667 static_cast<float>(native_mode_height); | |
| 668 | 688 |
| 669 area_ratio = width_ratio * height_ratio; | 689 area_ratio = width_ratio * height_ratio; |
| 670 return area_ratio; | 690 return area_ratio; |
| 671 } | 691 } |
| 672 | 692 |
| 673 } // namespace chromeos | 693 } // namespace chromeos |
| OLD | NEW |