| 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 "ash/display/display_manager.h" | 5 #include "ash/display/display_manager.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "ash/ash_switches.h" | 12 #include "ash/ash_switches.h" |
| 13 #include "ash/display/display_layout_store.h" | 13 #include "ash/display/display_layout_store.h" |
| 14 #include "ash/display/screen_ash.h" | 14 #include "ash/display/screen_ash.h" |
| 15 #include "ash/screen_util.h" | 15 #include "ash/screen_util.h" |
| 16 #include "ash/shell.h" | 16 #include "ash/shell.h" |
| 17 #include "base/auto_reset.h" | 17 #include "base/auto_reset.h" |
| 18 #include "base/command_line.h" | 18 #include "base/command_line.h" |
| 19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/metrics/histogram.h" | 20 #include "base/metrics/histogram.h" |
| 21 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
| 22 #include "base/strings/string_split.h" | 22 #include "base/strings/string_split.h" |
| 23 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
| 24 #include "base/strings/utf_string_conversions.h" | 24 #include "base/strings/utf_string_conversions.h" |
| 25 #include "grit/ash_strings.h" | 25 #include "grit/ash_strings.h" |
| 26 #include "ui/base/l10n/l10n_util.h" | 26 #include "ui/base/l10n/l10n_util.h" |
| 27 #include "ui/base/layout.h" | 27 #include "ui/base/layout.h" |
| 28 #include "ui/base/resource/resource_bundle.h" | 28 #include "ui/base/resource/resource_bundle.h" |
| 29 #include "ui/gfx/display.h" | 29 #include "ui/gfx/display.h" |
| 30 #include "ui/gfx/display_observer.h" |
| 30 #include "ui/gfx/rect.h" | 31 #include "ui/gfx/rect.h" |
| 31 #include "ui/gfx/screen.h" | 32 #include "ui/gfx/screen.h" |
| 32 #include "ui/gfx/size_conversions.h" | 33 #include "ui/gfx/size_conversions.h" |
| 33 | 34 |
| 34 #if defined(USE_X11) | 35 #if defined(USE_X11) |
| 35 #include "ui/base/x/x11_util.h" | 36 #include "ui/base/x/x11_util.h" |
| 36 #endif | 37 #endif |
| 37 | 38 |
| 38 #if defined(OS_CHROMEOS) | 39 #if defined(OS_CHROMEOS) |
| 39 #include "ash/display/display_configurator_animation.h" | 40 #include "ash/display/display_configurator_animation.h" |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 delegate_->PreDisplayConfigurationChange(false); | 341 delegate_->PreDisplayConfigurationChange(false); |
| 341 // PreDisplayConfigurationChange(false); | 342 // PreDisplayConfigurationChange(false); |
| 342 // TODO(oshima): Call UpdateDisplays instead. | 343 // TODO(oshima): Call UpdateDisplays instead. |
| 343 const DisplayLayout layout = GetCurrentDisplayLayout(); | 344 const DisplayLayout layout = GetCurrentDisplayLayout(); |
| 344 UpdateDisplayBoundsForLayoutById( | 345 UpdateDisplayBoundsForLayoutById( |
| 345 layout, primary, | 346 layout, primary, |
| 346 ScreenUtil::GetSecondaryDisplay().id()); | 347 ScreenUtil::GetSecondaryDisplay().id()); |
| 347 | 348 |
| 348 // Primary's bounds stay the same. Just notify bounds change | 349 // Primary's bounds stay the same. Just notify bounds change |
| 349 // on the secondary. | 350 // on the secondary. |
| 350 screen_ash_->NotifyBoundsChanged( | 351 int metrics = gfx::DisplayObserver::DISPLAY_METRICS_BOUNDS | |
| 351 ScreenUtil::GetSecondaryDisplay()); | 352 gfx::DisplayObserver::DISPLAY_METRICS_WORK_AREA; |
| 353 screen_ash_->NotifyMetricsChanged(ScreenUtil::GetSecondaryDisplay(), |
| 354 static_cast<gfx::DisplayObserver::DisplayMetrics>(metrics)); |
| 352 if (delegate_) | 355 if (delegate_) |
| 353 delegate_->PostDisplayConfigurationChange(); | 356 delegate_->PostDisplayConfigurationChange(); |
| 354 } | 357 } |
| 355 } | 358 } |
| 356 | 359 |
| 357 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const { | 360 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const { |
| 358 gfx::Display* display = | 361 gfx::Display* display = |
| 359 const_cast<DisplayManager*>(this)->FindDisplayForId(id); | 362 const_cast<DisplayManager*>(this)->FindDisplayForId(id); |
| 360 return display ? *display : GetInvalidDisplay(); | 363 return display ? *display : GetInvalidDisplay(); |
| 361 } | 364 } |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 636 ": Multiple display test does not work on Windows bots. Please " | 639 ": Multiple display test does not work on Windows bots. Please " |
| 637 "skip (don't disable) the test using SupportsMultipleDisplays()"; | 640 "skip (don't disable) the test using SupportsMultipleDisplays()"; |
| 638 #endif | 641 #endif |
| 639 | 642 |
| 640 DisplayInfoList new_display_info_list = updated_display_info_list; | 643 DisplayInfoList new_display_info_list = updated_display_info_list; |
| 641 std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor()); | 644 std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor()); |
| 642 std::sort(new_display_info_list.begin(), | 645 std::sort(new_display_info_list.begin(), |
| 643 new_display_info_list.end(), | 646 new_display_info_list.end(), |
| 644 DisplayInfoSortFunctor()); | 647 DisplayInfoSortFunctor()); |
| 645 DisplayList removed_displays; | 648 DisplayList removed_displays; |
| 646 std::vector<size_t> changed_display_indices; | 649 std::map<size_t, gfx::DisplayObserver::DisplayMetrics> display_changes; |
| 647 std::vector<size_t> added_display_indices; | 650 std::vector<size_t> added_display_indices; |
| 648 | 651 |
| 649 DisplayList::iterator curr_iter = displays_.begin(); | 652 DisplayList::iterator curr_iter = displays_.begin(); |
| 650 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin(); | 653 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin(); |
| 651 | 654 |
| 652 DisplayList new_displays; | 655 DisplayList new_displays; |
| 653 | 656 |
| 654 // Use the internal display or 1st as the mirror source, then scale | 657 // Use the internal display or 1st as the mirror source, then scale |
| 655 // the root window so that it matches the external display's | 658 // the root window so that it matches the external display's |
| 656 // resolution. This is necessary in order for scaling to work while | 659 // resolution. This is necessary in order for scaling to work while |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 706 } else if (curr_iter->id() == new_info_iter->id()) { | 709 } else if (curr_iter->id() == new_info_iter->id()) { |
| 707 const gfx::Display& current_display = *curr_iter; | 710 const gfx::Display& current_display = *curr_iter; |
| 708 // Copy the info because |CreateDisplayFromInfo| updates the instance. | 711 // Copy the info because |CreateDisplayFromInfo| updates the instance. |
| 709 const DisplayInfo current_display_info = | 712 const DisplayInfo current_display_info = |
| 710 GetDisplayInfo(current_display.id()); | 713 GetDisplayInfo(current_display.id()); |
| 711 InsertAndUpdateDisplayInfo(*new_info_iter); | 714 InsertAndUpdateDisplayInfo(*new_info_iter); |
| 712 gfx::Display new_display = | 715 gfx::Display new_display = |
| 713 CreateDisplayFromDisplayInfoById(new_info_iter->id()); | 716 CreateDisplayFromDisplayInfoById(new_info_iter->id()); |
| 714 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id()); | 717 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id()); |
| 715 | 718 |
| 716 bool host_window_bounds_changed = | 719 int metrics = gfx::DisplayObserver::DISPLAY_METRICS_NONE; |
| 717 current_display_info.bounds_in_native() != | |
| 718 new_display_info.bounds_in_native(); | |
| 719 | 720 |
| 721 // At that point the new Display objects we have are not entirely updated, |
| 722 // they are missing the translation related to the Display disposition in |
| 723 // the layout. |
| 724 // Using display.bounds() and display.work_area() would fail most of the |
| 725 // time. |
| 720 if (force_bounds_changed_ || | 726 if (force_bounds_changed_ || |
| 721 host_window_bounds_changed || | 727 (current_display_info.bounds_in_native() != |
| 722 (current_display.device_scale_factor() != | 728 new_display_info.bounds_in_native()) || |
| 723 new_display.device_scale_factor()) || | |
| 724 (current_display_info.size_in_pixel() != | 729 (current_display_info.size_in_pixel() != |
| 725 new_display.GetSizeInPixel()) || | 730 new_display.GetSizeInPixel())) { |
| 726 (current_display.rotation() != new_display.rotation())) { | 731 metrics |= gfx::DisplayObserver::DISPLAY_METRICS_BOUNDS | |
| 727 changed_display_indices.push_back(new_displays.size()); | 732 gfx::DisplayObserver::DISPLAY_METRICS_WORK_AREA; |
| 733 } |
| 734 |
| 735 if (current_display.device_scale_factor() != |
| 736 new_display.device_scale_factor()) { |
| 737 metrics |= gfx::DisplayObserver::DISPLAY_METRICS_DEVICE_SCALE_FACTOR; |
| 738 } |
| 739 |
| 740 if (current_display.rotation() != new_display.rotation()) |
| 741 metrics |= gfx::DisplayObserver::DISPLAY_METRICS_ROTATION; |
| 742 |
| 743 if (metrics != gfx::DisplayObserver::DISPLAY_METRICS_NONE) { |
| 744 display_changes.insert( |
| 745 std::pair<size_t, gfx::DisplayObserver::DisplayMetrics>( |
| 746 new_displays.size(), |
| 747 static_cast<gfx::DisplayObserver::DisplayMetrics>(metrics))); |
| 728 } | 748 } |
| 729 | 749 |
| 730 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets()); | 750 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets()); |
| 731 new_displays.push_back(new_display); | 751 new_displays.push_back(new_display); |
| 732 ++curr_iter; | 752 ++curr_iter; |
| 733 ++new_info_iter; | 753 ++new_info_iter; |
| 734 } else if (curr_iter->id() < new_info_iter->id()) { | 754 } else if (curr_iter->id() < new_info_iter->id()) { |
| 735 // more displays in current list between ids, which means it is deleted. | 755 // more displays in current list between ids, which means it is deleted. |
| 736 removed_displays.push_back(*curr_iter); | 756 removed_displays.push_back(*curr_iter); |
| 737 ++curr_iter; | 757 ++curr_iter; |
| 738 } else { | 758 } else { |
| 739 // more displays in new list between ids, which means it is added. | 759 // more displays in new list between ids, which means it is added. |
| 740 added_display_indices.push_back(new_displays.size()); | 760 added_display_indices.push_back(new_displays.size()); |
| 741 InsertAndUpdateDisplayInfo(*new_info_iter); | 761 InsertAndUpdateDisplayInfo(*new_info_iter); |
| 742 new_displays.push_back( | 762 new_displays.push_back( |
| 743 CreateDisplayFromDisplayInfoById(new_info_iter->id())); | 763 CreateDisplayFromDisplayInfoById(new_info_iter->id())); |
| 744 ++new_info_iter; | 764 ++new_info_iter; |
| 745 } | 765 } |
| 746 } | 766 } |
| 747 | 767 |
| 748 scoped_ptr<NonDesktopDisplayUpdater> non_desktop_display_updater( | 768 scoped_ptr<NonDesktopDisplayUpdater> non_desktop_display_updater( |
| 749 new NonDesktopDisplayUpdater(this, delegate_)); | 769 new NonDesktopDisplayUpdater(this, delegate_)); |
| 750 | 770 |
| 751 // Do not update |displays_| if there's nothing to be updated. Without this, | 771 // Do not update |displays_| if there's nothing to be updated. Without this, |
| 752 // it will not update the display layout, which causes the bug | 772 // it will not update the display layout, which causes the bug |
| 753 // http://crbug.com/155948. | 773 // http://crbug.com/155948. |
| 754 if (changed_display_indices.empty() && added_display_indices.empty() && | 774 if (display_changes.empty() && added_display_indices.empty() && |
| 755 removed_displays.empty()) { | 775 removed_displays.empty()) { |
| 756 return; | 776 return; |
| 757 } | 777 } |
| 758 // Clear focus if the display has been removed, but don't clear focus if | 778 // Clear focus if the display has been removed, but don't clear focus if |
| 759 // the destkop has been moved from one display to another | 779 // the destkop has been moved from one display to another |
| 760 // (mirror -> docked, docked -> single internal). | 780 // (mirror -> docked, docked -> single internal). |
| 761 bool clear_focus = | 781 bool clear_focus = |
| 762 !removed_displays.empty() && | 782 !removed_displays.empty() && |
| 763 !(removed_displays.size() == 1 && added_display_indices.size() == 1); | 783 !(removed_displays.size() == 1 && added_display_indices.size() == 1); |
| 764 if (delegate_) | 784 if (delegate_) |
| 765 delegate_->PreDisplayConfigurationChange(clear_focus); | 785 delegate_->PreDisplayConfigurationChange(clear_focus); |
| 766 | 786 |
| 767 size_t updated_index; | 787 size_t updated_index; |
| 768 if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) && | 788 if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) && |
| 769 std::find(added_display_indices.begin(), | 789 std::find(added_display_indices.begin(), |
| 770 added_display_indices.end(), | 790 added_display_indices.end(), |
| 771 updated_index) == added_display_indices.end() && | 791 updated_index) == added_display_indices.end()) { |
| 772 std::find(changed_display_indices.begin(), | 792 int metrics = gfx::DisplayObserver::DISPLAY_METRICS_BOUNDS | |
| 773 changed_display_indices.end(), | 793 gfx::DisplayObserver::DISPLAY_METRICS_WORK_AREA; |
| 774 updated_index) == changed_display_indices.end()) { | 794 if (display_changes.find(updated_index) != display_changes.end()) |
| 775 changed_display_indices.push_back(updated_index); | 795 metrics |= display_changes[updated_index]; |
| 796 |
| 797 display_changes[updated_index] = |
| 798 static_cast<gfx::DisplayObserver::DisplayMetrics>(metrics); |
| 776 } | 799 } |
| 777 | 800 |
| 778 displays_ = new_displays; | 801 displays_ = new_displays; |
| 779 | 802 |
| 780 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false); | 803 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false); |
| 781 | 804 |
| 782 // Temporarily add displays to be removed because display object | 805 // Temporarily add displays to be removed because display object |
| 783 // being removed are accessed during shutting down the root. | 806 // being removed are accessed during shutting down the root. |
| 784 displays_.insert(displays_.end(), removed_displays.begin(), | 807 displays_.insert(displays_.end(), removed_displays.begin(), |
| 785 removed_displays.end()); | 808 removed_displays.end()); |
| 786 | 809 |
| 787 for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin(); | 810 for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin(); |
| 788 iter != removed_displays.rend(); ++iter) { | 811 iter != removed_displays.rend(); ++iter) { |
| 789 screen_ash_->NotifyDisplayRemoved(displays_.back()); | 812 screen_ash_->NotifyDisplayRemoved(displays_.back()); |
| 790 displays_.pop_back(); | 813 displays_.pop_back(); |
| 791 } | 814 } |
| 792 // Close the non desktop window here to avoid creating two compositor on | 815 // Close the non desktop window here to avoid creating two compositor on |
| 793 // one display. | 816 // one display. |
| 794 if (!non_desktop_display_updater->enabled()) | 817 if (!non_desktop_display_updater->enabled()) |
| 795 non_desktop_display_updater.reset(); | 818 non_desktop_display_updater.reset(); |
| 796 for (std::vector<size_t>::iterator iter = added_display_indices.begin(); | 819 for (std::vector<size_t>::iterator iter = added_display_indices.begin(); |
| 797 iter != added_display_indices.end(); ++iter) { | 820 iter != added_display_indices.end(); ++iter) { |
| 798 screen_ash_->NotifyDisplayAdded(displays_[*iter]); | 821 screen_ash_->NotifyDisplayAdded(displays_[*iter]); |
| 799 } | 822 } |
| 800 // Create the non destkop window after all displays are added so that | 823 // Create the non destkop window after all displays are added so that |
| 801 // it can mirror the display newly added. This can happen when switching | 824 // it can mirror the display newly added. This can happen when switching |
| 802 // from dock mode to software mirror mode. | 825 // from dock mode to software mirror mode. |
| 803 non_desktop_display_updater.reset(); | 826 non_desktop_display_updater.reset(); |
| 804 for (std::vector<size_t>::iterator iter = changed_display_indices.begin(); | 827 for (std::map<size_t, gfx::DisplayObserver::DisplayMetrics>::iterator iter = |
| 805 iter != changed_display_indices.end(); ++iter) { | 828 display_changes.begin(); |
| 806 screen_ash_->NotifyBoundsChanged(displays_[*iter]); | 829 iter != display_changes.end(); ++iter) { |
| 830 screen_ash_->NotifyMetricsChanged(displays_[iter->first], iter->second); |
| 807 } | 831 } |
| 808 if (delegate_) | 832 if (delegate_) |
| 809 delegate_->PostDisplayConfigurationChange(); | 833 delegate_->PostDisplayConfigurationChange(); |
| 810 | 834 |
| 811 #if defined(USE_X11) && defined(OS_CHROMEOS) | 835 #if defined(USE_X11) && defined(OS_CHROMEOS) |
| 812 if (!changed_display_indices.empty() && base::SysInfo::IsRunningOnChromeOS()) | 836 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS()) |
| 813 ui::ClearX11DefaultRootWindow(); | 837 ui::ClearX11DefaultRootWindow(); |
| 814 #endif | 838 #endif |
| 815 } | 839 } |
| 816 | 840 |
| 817 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const { | 841 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const { |
| 818 DCHECK_LT(index, displays_.size()); | 842 DCHECK_LT(index, displays_.size()); |
| 819 return displays_[index]; | 843 return displays_[index]; |
| 820 } | 844 } |
| 821 | 845 |
| 822 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const { | 846 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const { |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 | 970 |
| 947 bool DisplayManager::UpdateDisplayBounds(int64 display_id, | 971 bool DisplayManager::UpdateDisplayBounds(int64 display_id, |
| 948 const gfx::Rect& new_bounds) { | 972 const gfx::Rect& new_bounds) { |
| 949 if (change_display_upon_host_resize_) { | 973 if (change_display_upon_host_resize_) { |
| 950 display_info_[display_id].SetBounds(new_bounds); | 974 display_info_[display_id].SetBounds(new_bounds); |
| 951 // Don't notify observers if the mirrored window has changed. | 975 // Don't notify observers if the mirrored window has changed. |
| 952 if (software_mirroring_enabled() && mirrored_display_id_ == display_id) | 976 if (software_mirroring_enabled() && mirrored_display_id_ == display_id) |
| 953 return false; | 977 return false; |
| 954 gfx::Display* display = FindDisplayForId(display_id); | 978 gfx::Display* display = FindDisplayForId(display_id); |
| 955 display->SetSize(display_info_[display_id].size_in_pixel()); | 979 display->SetSize(display_info_[display_id].size_in_pixel()); |
| 956 screen_ash_->NotifyBoundsChanged(*display); | 980 screen_ash_->NotifyMetricsChanged(*display, |
| 981 gfx::DisplayObserver::DISPLAY_METRICS_BOUNDS); |
| 957 return true; | 982 return true; |
| 958 } | 983 } |
| 959 return false; | 984 return false; |
| 960 } | 985 } |
| 961 | 986 |
| 962 void DisplayManager::CreateMirrorWindowIfAny() { | 987 void DisplayManager::CreateMirrorWindowIfAny() { |
| 963 NonDesktopDisplayUpdater updater(this, delegate_); | 988 NonDesktopDisplayUpdater updater(this, delegate_); |
| 964 } | 989 } |
| 965 | 990 |
| 966 void DisplayManager::CreateScreenForShutdown() const { | 991 void DisplayManager::CreateScreenForShutdown() const { |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1115 new_secondary_origin.Offset(-secondary_bounds.width(), offset); | 1140 new_secondary_origin.Offset(-secondary_bounds.width(), offset); |
| 1116 break; | 1141 break; |
| 1117 } | 1142 } |
| 1118 gfx::Insets insets = secondary_display->GetWorkAreaInsets(); | 1143 gfx::Insets insets = secondary_display->GetWorkAreaInsets(); |
| 1119 secondary_display->set_bounds( | 1144 secondary_display->set_bounds( |
| 1120 gfx::Rect(new_secondary_origin, secondary_bounds.size())); | 1145 gfx::Rect(new_secondary_origin, secondary_bounds.size())); |
| 1121 secondary_display->UpdateWorkAreaFromInsets(insets); | 1146 secondary_display->UpdateWorkAreaFromInsets(insets); |
| 1122 } | 1147 } |
| 1123 | 1148 |
| 1124 } // namespace ash | 1149 } // namespace ash |
| OLD | NEW |