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