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