display_change_observer_chromeos.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// Copyright 2013 The Chromium Authors. All rights reserved. 29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// Use of this source code is governed by a BSD-style license that can be 39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// found in the LICENSE file. 49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ash/display/display_change_observer_chromeos.h" 69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include <algorithm> 89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include <map> 99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include <set> 109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include <vector> 119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ash/ash_switches.h" 139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ash/display/display_info.h" 149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ash/display/display_layout_store.h" 159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ash/display/display_manager.h" 169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ash/shell.h" 179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "base/command_line.h" 189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "base/logging.h" 199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "grit/ash_strings.h" 209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ui/base/l10n/l10n_util.h" 219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ui/base/x/x11_util.h" 229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ui/compositor/dip_util.h" 239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ui/display/chromeos/x11/display_util.h" 249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson#include "ui/gfx/display.h" 259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonnamespace ash { 279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonnamespace internal { 289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonusing ui::OutputConfigurator; 309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonnamespace { 329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// The DPI threshold to detect high density screen. 349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// Higher DPI than this will use device_scale_factor=2. 359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonconst unsigned int kHighDensityDPIThreshold = 170; 369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// 1 inch in mm. 389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonconst float kInchInMm = 25.4f; 399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// Display mode list is sorted by (in descending priority): 419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// * the area in pixels. 429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// * refresh rate. 439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstruct DisplayModeSorter { 449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson bool operator()(const DisplayMode& a, const DisplayMode& b) { 459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (a.size.GetArea() == b.size.GetArea()) 469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return (a.refresh_rate > b.refresh_rate); 479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return (a.size.GetArea() > b.size.GetArea()); 489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}; 509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson} // namespace 529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson// static 549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonstd::vector<DisplayMode> DisplayChangeObserver::GetDisplayModeList( 559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson const OutputConfigurator::OutputSnapshot& output) { 569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson typedef std::map<std::pair<int, int>, DisplayMode> DisplayModeMap; 579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson DisplayModeMap display_mode_map; 589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (std::map<RRMode, OutputConfigurator::ModeInfo>::const_iterator it = 609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson output.mode_infos.begin(); it != output.mode_infos.end(); ++it) { 619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson const OutputConfigurator::ModeInfo& mode_info = it->second; 629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson const std::pair<int, int> size(mode_info.width, mode_info.height); 639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson const DisplayMode display_mode(gfx::Size(mode_info.width, mode_info.height), 649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson mode_info.refresh_rate, 659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson mode_info.interlaced, 669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson output.native_mode == it->first); 679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Add the display mode if it isn't already present and override interlaced 699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // display modes with non-interlaced ones. 709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson DisplayModeMap::iterator display_mode_it = display_mode_map.find(size); 719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (display_mode_it == display_mode_map.end()) 729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson display_mode_map.insert(std::make_pair(size, display_mode)); 739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else if (display_mode_it->second.interlaced && !display_mode.interlaced) 749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson display_mode_it->second = display_mode; 759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson std::vector<DisplayMode> display_mode_list; 789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (DisplayModeMap::const_iterator iter = display_mode_map.begin(); 799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson iter != display_mode_map.end(); 809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ++iter) { 819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson display_mode_list.push_back(iter->second); 829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson std::sort( 849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson display_mode_list.begin(), display_mode_list.end(), DisplayModeSorter()); 859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return display_mode_list; 869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson} 879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse WilsonDisplayChangeObserver::DisplayChangeObserver() { 899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Shell::GetInstance()->AddShellObserver(this); 909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson} 919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse WilsonDisplayChangeObserver::~DisplayChangeObserver() { 939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Shell::GetInstance()->RemoveShellObserver(this); 949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson} 959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonui::OutputState DisplayChangeObserver::GetStateForDisplayIds( 979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson const std::vector<int64>& display_ids) const { 989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson CHECK_EQ(2U, display_ids.size()); 999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson DisplayIdPair pair = std::make_pair(display_ids[0], display_ids[1]); 1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson DisplayLayout layout = Shell::GetInstance()->display_manager()-> 1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson layout_store()->GetRegisteredDisplayLayout(pair); 102 return layout.mirrored ? ui::OUTPUT_STATE_DUAL_MIRROR : 103 ui::OUTPUT_STATE_DUAL_EXTENDED; 104} 105 106bool DisplayChangeObserver::GetResolutionForDisplayId(int64 display_id, 107 int* width, 108 int* height) const { 109 DisplayMode mode; 110 if (!Shell::GetInstance()->display_manager()->GetSelectedModeForDisplayId( 111 display_id, &mode)) 112 return false; 113 114 *width = mode.size.width(); 115 *height = mode.size.height(); 116 return true; 117} 118 119void DisplayChangeObserver::OnDisplayModeChanged( 120 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { 121 std::vector<DisplayInfo> displays; 122 std::set<int64> ids; 123 for (size_t i = 0; i < outputs.size(); ++i) { 124 const OutputConfigurator::OutputSnapshot& output = outputs[i]; 125 126 if (output.type == ui::OUTPUT_TYPE_INTERNAL && 127 gfx::Display::InternalDisplayId() == gfx::Display::kInvalidDisplayID) { 128 // Fall back to output index. crbug.com/180100 129 gfx::Display::SetInternalDisplayId( 130 output.display_id == gfx::Display::kInvalidDisplayID ? output.index : 131 output.display_id); 132 } 133 134 const OutputConfigurator::ModeInfo* mode_info = 135 OutputConfigurator::GetModeInfo(output, output.current_mode); 136 if (!mode_info) 137 continue; 138 139 float device_scale_factor = 1.0f; 140 if (!ui::IsXDisplaySizeBlackListed(output.width_mm, output.height_mm) && 141 (kInchInMm * mode_info->width / output.width_mm) > 142 kHighDensityDPIThreshold) { 143 device_scale_factor = 2.0f; 144 } 145 gfx::Rect display_bounds( 146 output.x, output.y, mode_info->width, mode_info->height); 147 148 std::vector<DisplayMode> display_modes = GetDisplayModeList(output); 149 150 std::string name = 151 output.type == ui::OUTPUT_TYPE_INTERNAL 152 ? l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) : 153 ui::GetDisplayName(output); 154 if (name.empty()) 155 name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME); 156 157 bool has_overscan = false; 158 ui::GetOutputOverscanFlag(output, &has_overscan); 159 160 int64 id = output.display_id; 161 if (id == gfx::Display::kInvalidDisplayID || ids.find(id) != ids.end()) 162 id = output.index; 163 ids.insert(id); 164 165 displays.push_back(DisplayInfo(id, name, has_overscan)); 166 displays.back().set_device_scale_factor(device_scale_factor); 167 displays.back().SetBounds(display_bounds); 168 displays.back().set_native(true); 169 displays.back().set_display_modes(display_modes); 170 displays.back().set_touch_support( 171 output.touch_device_id == 0 ? gfx::Display::TOUCH_SUPPORT_UNAVAILABLE : 172 gfx::Display::TOUCH_SUPPORT_AVAILABLE); 173 } 174 175 // DisplayManager can be null during the boot. 176 Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays); 177} 178 179void DisplayChangeObserver::OnAppTerminating() { 180#if defined(USE_ASH) 181 // Stop handling display configuration events once the shutdown 182 // process starts. crbug.com/177014. 183 Shell::GetInstance()->output_configurator()->PrepareForExit(); 184#endif 185} 186 187} // namespace internal 188} // namespace ash 189