display_change_observer_chromeos.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
1// Copyright 2013 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 "ash/display/display_change_observer_chromeos.h" 6 7#include <algorithm> 8#include <map> 9#include <set> 10#include <vector> 11 12#include "ash/ash_switches.h" 13#include "ash/display/display_info.h" 14#include "ash/display/display_layout_store.h" 15#include "ash/display/display_manager.h" 16#include "ash/shell.h" 17#include "base/command_line.h" 18#include "base/logging.h" 19#include "grit/ash_strings.h" 20#include "ui/base/l10n/l10n_util.h" 21#include "ui/base/x/x11_util.h" 22#include "ui/compositor/dip_util.h" 23#include "ui/display/chromeos/display_mode.h" 24#include "ui/display/chromeos/display_snapshot.h" 25#include "ui/gfx/display.h" 26 27namespace ash { 28namespace internal { 29 30using ui::OutputConfigurator; 31 32namespace { 33 34// The DPI threshold to detect high density screen. 35// Higher DPI than this will use device_scale_factor=2. 36const unsigned int kHighDensityDPIThreshold = 170; 37 38// 1 inch in mm. 39const float kInchInMm = 25.4f; 40 41// Display mode list is sorted by (in descending priority): 42// * the area in pixels. 43// * refresh rate. 44struct DisplayModeSorter { 45 bool operator()(const DisplayMode& a, const DisplayMode& b) { 46 if (a.size.GetArea() == b.size.GetArea()) 47 return (a.refresh_rate > b.refresh_rate); 48 return (a.size.GetArea() > b.size.GetArea()); 49 } 50}; 51 52} // namespace 53 54// static 55std::vector<DisplayMode> DisplayChangeObserver::GetDisplayModeList( 56 const OutputConfigurator::DisplayState& output) { 57 typedef std::map<std::pair<int, int>, DisplayMode> DisplayModeMap; 58 DisplayModeMap display_mode_map; 59 60 for (std::vector<const ui::DisplayMode*>::const_iterator it = 61 output.display->modes().begin(); 62 it != output.display->modes().end(); 63 ++it) { 64 const ui::DisplayMode& mode_info = **it; 65 const std::pair<int, int> size(mode_info.size().width(), 66 mode_info.size().height()); 67 const DisplayMode display_mode(mode_info.size(), 68 mode_info.refresh_rate(), 69 mode_info.is_interlaced(), 70 output.display->native_mode() == *it); 71 72 // Add the display mode if it isn't already present and override interlaced 73 // display modes with non-interlaced ones. 74 DisplayModeMap::iterator display_mode_it = display_mode_map.find(size); 75 if (display_mode_it == display_mode_map.end()) 76 display_mode_map.insert(std::make_pair(size, display_mode)); 77 else if (display_mode_it->second.interlaced && !display_mode.interlaced) 78 display_mode_it->second = display_mode; 79 } 80 81 std::vector<DisplayMode> display_mode_list; 82 for (DisplayModeMap::const_iterator iter = display_mode_map.begin(); 83 iter != display_mode_map.end(); 84 ++iter) { 85 display_mode_list.push_back(iter->second); 86 } 87 std::sort( 88 display_mode_list.begin(), display_mode_list.end(), DisplayModeSorter()); 89 return display_mode_list; 90} 91 92DisplayChangeObserver::DisplayChangeObserver() { 93 Shell::GetInstance()->AddShellObserver(this); 94} 95 96DisplayChangeObserver::~DisplayChangeObserver() { 97 Shell::GetInstance()->RemoveShellObserver(this); 98} 99 100ui::OutputState DisplayChangeObserver::GetStateForDisplayIds( 101 const std::vector<int64>& display_ids) const { 102 CHECK_EQ(2U, display_ids.size()); 103 DisplayIdPair pair = std::make_pair(display_ids[0], display_ids[1]); 104 DisplayLayout layout = Shell::GetInstance()->display_manager()-> 105 layout_store()->GetRegisteredDisplayLayout(pair); 106 return layout.mirrored ? ui::OUTPUT_STATE_DUAL_MIRROR : 107 ui::OUTPUT_STATE_DUAL_EXTENDED; 108} 109 110bool DisplayChangeObserver::GetResolutionForDisplayId(int64 display_id, 111 gfx::Size* size) const { 112 DisplayMode mode; 113 if (!Shell::GetInstance()->display_manager()->GetSelectedModeForDisplayId( 114 display_id, &mode)) 115 return false; 116 117 *size = mode.size; 118 return true; 119} 120 121void DisplayChangeObserver::OnDisplayModeChanged( 122 const std::vector<OutputConfigurator::DisplayState>& outputs) { 123 std::vector<DisplayInfo> displays; 124 std::set<int64> ids; 125 for (size_t i = 0; i < outputs.size(); ++i) { 126 const OutputConfigurator::DisplayState& output = outputs[i]; 127 128 if (output.display->type() == ui::OUTPUT_TYPE_INTERNAL && 129 gfx::Display::InternalDisplayId() == gfx::Display::kInvalidDisplayID) { 130 gfx::Display::SetInternalDisplayId(output.display->display_id()); 131 } 132 133 const ui::DisplayMode* mode_info = output.display->current_mode(); 134 if (!mode_info) 135 continue; 136 137 float device_scale_factor = 1.0f; 138 if (!ui::IsXDisplaySizeBlackListed( 139 output.display->physical_size().width(), 140 output.display->physical_size().height()) && 141 (kInchInMm * mode_info->size().width() / 142 output.display->physical_size().width()) > kHighDensityDPIThreshold) { 143 device_scale_factor = 2.0f; 144 } 145 gfx::Rect display_bounds(output.display->origin(), mode_info->size()); 146 147 std::vector<DisplayMode> display_modes = GetDisplayModeList(output); 148 149 std::string name = 150 output.display->type() == ui::OUTPUT_TYPE_INTERNAL 151 ? l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) : 152 output.display->GetDisplayName(); 153 if (name.empty()) 154 name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME); 155 156 bool has_overscan = output.display->GetOverscanFlag(); 157 int64 id = output.display->display_id(); 158 ids.insert(id); 159 160 displays.push_back(DisplayInfo(id, name, has_overscan)); 161 displays.back().set_device_scale_factor(device_scale_factor); 162 displays.back().SetBounds(display_bounds); 163 displays.back().set_native(true); 164 displays.back().set_display_modes(display_modes); 165 displays.back().set_touch_support( 166 output.touch_device_id == 0 ? gfx::Display::TOUCH_SUPPORT_UNAVAILABLE : 167 gfx::Display::TOUCH_SUPPORT_AVAILABLE); 168 } 169 170 // DisplayManager can be null during the boot. 171 Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays); 172} 173 174void DisplayChangeObserver::OnAppTerminating() { 175#if defined(USE_ASH) 176 // Stop handling display configuration events once the shutdown 177 // process starts. crbug.com/177014. 178 Shell::GetInstance()->output_configurator()->PrepareForExit(); 179#endif 180} 181 182} // namespace internal 183} // namespace ash 184