tray_display.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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
3// found in the LICENSE file.
4
5#include "ash/system/chromeos/tray_display.h"
6
7#include "ash/display/display_controller.h"
8#include "ash/display/display_manager.h"
9#include "ash/screen_ash.h"
10#include "ash/shell.h"
11#include "ash/system/tray/fixed_sized_image_view.h"
12#include "ash/system/tray/system_tray.h"
13#include "ash/system/tray/system_tray_delegate.h"
14#include "ash/system/tray/tray_constants.h"
15#include "base/chromeos/chromeos_version.h"
16#include "base/utf_string_conversions.h"
17#include "grit/ash_resources.h"
18#include "grit/ash_strings.h"
19#include "ui/aura/env.h"
20#include "ui/base/l10n/l10n_util.h"
21#include "ui/base/resource/resource_bundle.h"
22#include "ui/gfx/image/image.h"
23#include "ui/views/controls/image_view.h"
24#include "ui/views/controls/label.h"
25#include "ui/views/layout/box_layout.h"
26
27#if defined(USE_X11)
28#include "chromeos/display/output_configurator.h"
29#include "ui/base/x/x11_util.h"
30#endif
31
32namespace ash {
33namespace internal {
34
35class DisplayView : public ash::internal::ActionableView {
36 public:
37  explicit DisplayView(user::LoginStatus login_status)
38      : login_status_(login_status) {
39    SetLayoutManager(new
40        views::BoxLayout(views::BoxLayout::kHorizontal,
41        ash::kTrayPopupPaddingHorizontal, 0,
42        ash::kTrayPopupPaddingBetweenItems));
43
44    ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
45    image_ =
46        new ash::internal::FixedSizedImageView(0, ash::kTrayPopupItemHeight);
47    image_->SetImage(
48        bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY).ToImageSkia());
49    AddChildView(image_);
50    label_ = new views::Label();
51    label_->SetMultiLine(true);
52    label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
53    AddChildView(label_);
54    Update();
55  }
56
57  virtual ~DisplayView() {}
58
59  void Update() {
60#if !defined(USE_X11)
61     SetVisible(false);
62#else
63    chromeos::OutputState state =
64        base::chromeos::IsRunningOnChromeOS() ?
65        Shell::GetInstance()->output_configurator()->output_state() :
66        InferOutputState();
67    switch (state) {
68      case chromeos::STATE_INVALID:
69      case chromeos::STATE_HEADLESS:
70      case chromeos::STATE_SINGLE:
71        SetVisible(false);
72        return;
73      case chromeos::STATE_DUAL_MIRROR:
74        label_->SetText(l10n_util::GetStringFUTF16(
75            IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetExternalDisplayName()));
76        SetVisible(true);
77        return;
78      case chromeos::STATE_DUAL_EXTENDED:
79        label_->SetText(l10n_util::GetStringFUTF16(
80            IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetExternalDisplayName()));
81        SetVisible(true);
82        return;
83    }
84    NOTREACHED() << "Unhandled state " << state;
85#endif
86  }
87
88  chromeos::OutputState InferOutputState() const {
89    return Shell::GetScreen()->GetNumDisplays() == 1 ?
90        chromeos::STATE_SINGLE : chromeos::STATE_DUAL_EXTENDED;
91  }
92
93 private:
94  // Returns the name of the currently connected external display.
95  base::string16 GetExternalDisplayName() const {
96    DisplayManager* display_manager = Shell::GetInstance()->display_manager();
97    int64 external_id = display_manager->mirrored_display_id();
98
99    if (external_id == gfx::Display::kInvalidDisplayID) {
100      int64 internal_display_id = gfx::Display::InternalDisplayId();
101      int64 first_display_id = display_manager->first_display_id();
102      for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
103        int64 id = display_manager->GetDisplayAt(i)->id();
104        if (id != internal_display_id && id != first_display_id) {
105          external_id = id;
106          break;
107        }
108      }
109    }
110    if (external_id != gfx::Display::kInvalidDisplayID)
111      return UTF8ToUTF16(display_manager->GetDisplayNameForId(external_id));
112    return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
113  }
114
115  // Overridden from ActionableView.
116  virtual bool PerformAction(const ui::Event& event) OVERRIDE {
117    if (login_status_ == ash::user::LOGGED_IN_USER ||
118        login_status_ == ash::user::LOGGED_IN_OWNER ||
119        login_status_ == ash::user::LOGGED_IN_GUEST) {
120      ash::Shell::GetInstance()->system_tray_delegate()->ShowDisplaySettings();
121    }
122
123    return true;
124  }
125
126  virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE {
127    int label_max_width = bounds().width() - kTrayPopupPaddingHorizontal * 2 -
128        kTrayPopupPaddingBetweenItems - image_->GetPreferredSize().width();
129    label_->SizeToFit(label_max_width);
130    PreferredSizeChanged();
131  }
132
133  user::LoginStatus login_status_;
134  views::ImageView* image_;
135  views::Label* label_;
136
137  DISALLOW_COPY_AND_ASSIGN(DisplayView);
138};
139
140TrayDisplay::TrayDisplay(SystemTray* system_tray)
141    : SystemTrayItem(system_tray),
142      default_(NULL) {
143  Shell::GetScreen()->AddObserver(this);
144#if defined(USE_X11)
145  Shell::GetInstance()->output_configurator()->AddObserver(this);
146#endif
147}
148
149TrayDisplay::~TrayDisplay() {
150  Shell::GetScreen()->RemoveObserver(this);
151#if defined(USE_X11)
152  Shell::GetInstance()->output_configurator()->RemoveObserver(this);
153#endif
154}
155
156views::View* TrayDisplay::CreateDefaultView(user::LoginStatus status) {
157  default_ = new DisplayView(status);
158  return default_;
159}
160
161void TrayDisplay::DestroyDefaultView() {
162  default_ = NULL;
163}
164
165void TrayDisplay::OnDisplayBoundsChanged(const gfx::Display& display) {
166  if (default_)
167    default_->Update();
168}
169
170void TrayDisplay::OnDisplayAdded(const gfx::Display& new_display) {
171  if (default_)
172    default_->Update();
173}
174
175void TrayDisplay::OnDisplayRemoved(const gfx::Display& old_display) {
176  if (default_)
177    default_->Update();
178}
179
180#if defined(OS_CHROMEOS)
181void TrayDisplay::OnDisplayModeChanged() {
182  if (default_)
183    default_->Update();
184}
185#endif
186
187}  // namespace internal
188}  // namespace ash
189