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