summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authoryusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-15 09:15:39 +0000
committeryusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-15 09:15:39 +0000
commit34fd3763e84b2347ab89ec5be7c7f73dac9ccb6a (patch)
tree1d9c85956a61bcf6012239a89c9ff1a317e9536f /chrome/browser
parentfc12cfd609a24233288c6ab471929eb15cee3520 (diff)
downloadchromium_src-34fd3763e84b2347ab89ec5be7c7f73dac9ccb6a.zip
chromium_src-34fd3763e84b2347ab89ec5be7c7f73dac9ccb6a.tar.gz
chromium_src-34fd3763e84b2347ab89ec5be7c7f73dac9ccb6a.tar.bz2
Implement "Language Switcher" for Chromium OS. This change enables users to switch their IME (input method) by clicking a menu button on the status area. Basic structure of the code is almost the same as power_menu_button and power_library.
Demo: http://dev.chromium.org/chromium-os/chromiumos-design-docs/text-input/demos language_library.{cc,h}: UI-libcros glue. boilerplate code. language_menu_button.{cc,h}: A button on the status area and its drop-down menu. Implements app/menus/menu_model.h interface. status_area_view.{cc,h}: Put the language button on the status area. BUG=494 TEST=Start Chromium OS. Click the menu button on the status area. Then verify that all IMEs you configured (via ibus-setup command, for now) is listed in the drop down menu. Review URL: http://codereview.chromium.org/449050 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34540 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/chromeos/language_library.cc100
-rw-r--r--chrome/browser/chromeos/language_library.h86
-rw-r--r--chrome/browser/chromeos/language_menu_button.cc241
-rw-r--r--chrome/browser/chromeos/language_menu_button.h69
-rwxr-xr-xchrome/browser/chromeos/status_area_view.cc15
-rw-r--r--chrome/browser/chromeos/status_area_view.h2
6 files changed, 511 insertions, 2 deletions
diff --git a/chrome/browser/chromeos/language_library.cc b/chrome/browser/chromeos/language_library.cc
new file mode 100644
index 0000000..7db0a2b
--- /dev/null
+++ b/chrome/browser/chromeos/language_library.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/language_library.h"
+
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/cros_library.h"
+
+// Allows InvokeLater without adding refcounting. This class is a Singleton and
+// won't be deleted until it's last InvokeLater is run.
+template <>
+struct RunnableMethodTraits<chromeos::LanguageLibrary> {
+ void RetainCallee(chromeos::LanguageLibrary* obj) {}
+ void ReleaseCallee(chromeos::LanguageLibrary* obj) {}
+};
+
+namespace chromeos {
+
+LanguageLibrary::LanguageLibrary() : language_status_connection_(NULL) {
+ if (EnsureLoaded()) {
+ Init();
+ }
+}
+
+LanguageLibrary::~LanguageLibrary() {
+ if (EnsureLoaded()) {
+ chromeos::DisconnectLanguageStatus(language_status_connection_);
+ }
+}
+
+LanguageLibrary::Observer::~Observer() {
+}
+
+// static
+LanguageLibrary* LanguageLibrary::Get() {
+ return Singleton<LanguageLibrary>::get();
+}
+
+// static
+bool LanguageLibrary::EnsureLoaded() {
+ return CrosLibrary::EnsureLoaded();
+}
+
+void LanguageLibrary::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void LanguageLibrary::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+chromeos::InputLanguageList* LanguageLibrary::GetLanguages() {
+ chromeos::InputLanguageList* result = NULL;
+ if (EnsureLoaded()) {
+ result = chromeos::GetLanguages(language_status_connection_);
+ }
+ return result ? result : CreateFallbackInputLanguageList();
+}
+
+void LanguageLibrary::ChangeLanguage(
+ LanguageCategory category, const std::string& id) {
+ if (EnsureLoaded()) {
+ chromeos::ChangeLanguage(language_status_connection_, category, id.c_str());
+ }
+}
+
+// static
+void LanguageLibrary::LanguageChangedHandler(
+ void* object, const chromeos::InputLanguage& current_language) {
+ LanguageLibrary* language_library = static_cast<LanguageLibrary*>(object);
+ language_library->UpdateCurrentLanguage(current_language);
+}
+
+void LanguageLibrary::Init() {
+ language_status_connection_ = chromeos::MonitorLanguageStatus(
+ &LanguageChangedHandler, this);
+}
+
+void LanguageLibrary::UpdateCurrentLanguage(
+ const chromeos::InputLanguage& current_language) {
+ // Make sure we run on UI thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ DLOG(INFO) << "UpdateCurrentLanguage (Background thread)";
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ // NewRunnableMethod() copies |current_language| by value.
+ NewRunnableMethod(
+ this, &LanguageLibrary::UpdateCurrentLanguage, current_language));
+ return;
+ }
+
+ DLOG(INFO) << "UpdateCurrentLanguage (UI thread)";
+ current_language_ = current_language;
+ FOR_EACH_OBSERVER(Observer, observers_, LanguageChanged(this));
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/language_library.h b/chrome/browser/chromeos/language_library.h
new file mode 100644
index 0000000..e79d159
--- /dev/null
+++ b/chrome/browser/chromeos/language_library.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LANGUAGE_LIBRARY_H_
+#define CHROME_BROWSER_CHROMEOS_LANGUAGE_LIBRARY_H_
+
+#include <string>
+
+#include "base/observer_list.h"
+#include "base/singleton.h"
+#include "base/time.h"
+#include "third_party/cros/chromeos_language.h"
+
+namespace chromeos {
+
+// This class handles the interaction with the ChromeOS language library APIs.
+// Classes can add themselves as observers. Users can get an instance of this
+// library class like this: LanguageLibrary::Get()
+class LanguageLibrary {
+ public:
+ class Observer {
+ public:
+ virtual ~Observer() = 0;
+ virtual void LanguageChanged(LanguageLibrary* obj) = 0;
+ };
+
+ // This gets the singleton LanguageLibrary
+ static LanguageLibrary* Get();
+
+ // Makes sure the library is loaded, loading it if necessary. Returns true if
+ // the library has been successfully loaded.
+ static bool EnsureLoaded();
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Returns the list of IMEs and keyboard layouts we can select. If the cros
+ // library is not found or IBus/DBus daemon is not alive, this function
+ // returns a fallback language list (and never returns NULL).
+ InputLanguageList* GetLanguages();
+
+ // Changes the current IME engine to |id| and enable IME (when |category|
+ // is LANGUAGE_CATEGORY_IME). Changes the current XKB layout to |id| and
+ // disable IME (when |category| is LANGUAGE_CATEGORY_XKB). |id| is a unique
+ // identifier of a IME engine or XKB layout. Please check chromeos_language.h
+ // in src third_party/cros/ for details.
+ void ChangeLanguage(LanguageCategory category, const std::string& id);
+
+ const InputLanguage& current_language() const {
+ return current_language_;
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<LanguageLibrary>;
+
+ LanguageLibrary();
+ ~LanguageLibrary();
+
+ // This method is called when there's a change in language status.
+ // This method is called on a background thread.
+ static void LanguageChangedHandler(
+ void* object, const InputLanguage& current_language);
+
+ // This methods starts the monitoring of language changes.
+ void Init();
+
+ // Called by the handler to update the language status.
+ // This will notify all the Observers.
+ void UpdateCurrentLanguage(const InputLanguage& current_language);
+
+ // A reference to the language api, to allow callbacks when the language
+ // status changes.
+ LanguageStatusConnection* language_status_connection_;
+ ObserverList<Observer> observers_;
+
+ // The language (IME or XKB layout) which currently selected.
+ InputLanguage current_language_;
+
+ DISALLOW_COPY_AND_ASSIGN(LanguageLibrary);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LANGUAGE_LIBRARY_H_
+
diff --git a/chrome/browser/chromeos/language_menu_button.cc b/chrome/browser/chromeos/language_menu_button.cc
new file mode 100644
index 0000000..87092cc
--- /dev/null
+++ b/chrome/browser/chromeos/language_menu_button.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/language_menu_button.h"
+
+#include <string>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/time.h"
+#include "chrome/browser/browser.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+const int kRadioGroupNone = 0;
+const int kRadioGroupLanguage = 1;
+const size_t kMaxLanguageNameLen = 7;
+const wchar_t kSpacer[] = L"MMMMMMM";
+
+// Returns true if the |index| points to the "Configure IME" menu item.
+bool IsIndexShowControlPanel(
+ int index, chromeos::InputLanguageList* language_list) {
+ DCHECK_GE(index, 0);
+ if (language_list->empty()) {
+ // If language_list is empty, then there's no separator. So "Configure IME"
+ // should be at index 0.
+ DCHECK_EQ(index, 0);
+ return index == 0;
+ }
+ return static_cast<size_t>(index) == (language_list->size() + 1);
+}
+
+// Converts chromeos::InputLanguage object into human readable string. Returns
+// a string for the drop-down menu if |for_menu| is true. Otherwise, returns a
+// string for the status area.
+std::string FormatInputLanguage(
+ const chromeos::InputLanguage& language, bool for_menu) {
+ std::string formatted = language.display_name;
+ if (formatted.empty()) {
+ formatted = language.id;
+ }
+ if (for_menu) {
+ switch (language.category) {
+ case chromeos::LANGUAGE_CATEGORY_XKB:
+ // TODO(yusukes): Use message catalog.
+ formatted += " (Layout)";
+ break;
+ case chromeos::LANGUAGE_CATEGORY_IME:
+ // TODO(yusukes): Use message catalog.
+ formatted += " (IME)";
+ break;
+ }
+ } else {
+ // For status area. Trim the string.
+ formatted = formatted.substr(0, kMaxLanguageNameLen);
+ // TODO(yusukes): Simple substr() does not work for non-ASCII string.
+ // TODO(yusukes): How can we ensure that the trimmed string does not
+ // overflow the area?
+ }
+ return formatted;
+}
+
+} // namespace
+
+namespace chromeos {
+
+////////////////////////////////////////////////////////////////////////////////
+// LanguageMenuButton
+
+LanguageMenuButton::LanguageMenuButton(Browser* browser)
+ : MenuButton(NULL, std::wstring(), this, false),
+ language_list_(LanguageLibrary::Get()->GetLanguages()),
+ // Since the constructor of |language_menu_| calls this->GetItemCount(),
+ // we have to initialize |language_list_| before hand.
+ ALLOW_THIS_IN_INITIALIZER_LIST(language_menu_(this)),
+ browser_(browser) {
+ DCHECK(language_list_.get() && !language_list_->empty());
+ // Grab the real estate.
+ UpdateIcon(kSpacer);
+ // Display the default XKB name (usually "US").
+ const std::string name = FormatInputLanguage(language_list_->at(0), false);
+ UpdateIcon(UTF8ToWide(name));
+ LanguageLibrary::Get()->AddObserver(this);
+}
+
+LanguageMenuButton::~LanguageMenuButton() {
+ LanguageLibrary::Get()->RemoveObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// LanguageMenuButton, menus::MenuModel implementation:
+
+int LanguageMenuButton::GetCommandIdAt(int index) const {
+ return index; // dummy
+}
+
+bool LanguageMenuButton::IsLabelDynamicAt(int index) const {
+ // Menu content for the language button could change time by time.
+ return true;
+}
+
+bool LanguageMenuButton::GetAcceleratorAt(
+ int index, menus::Accelerator* accelerator) const {
+ // Views for Chromium OS does not support accelerators yet.
+ return false;
+}
+
+bool LanguageMenuButton::IsItemCheckedAt(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(language_list_.get());
+ if (static_cast<size_t>(index) < language_list_->size()) {
+ const InputLanguage& language = language_list_->at(index);
+ return language == LanguageLibrary::Get()->current_language();
+ }
+ return false;
+}
+
+int LanguageMenuButton::GetGroupIdAt(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(language_list_.get());
+ if (static_cast<size_t>(index) < language_list_->size()) {
+ return kRadioGroupLanguage;
+ }
+ return kRadioGroupNone;
+}
+
+bool LanguageMenuButton::HasIcons() const {
+ // TODO(yusukes): Display IME icons.
+ return false;
+}
+
+bool LanguageMenuButton::GetIconAt(int index, SkBitmap* icon) const {
+ return false;
+}
+
+bool LanguageMenuButton::IsEnabledAt(int index) const {
+ // Just return true so all IMEs and XLB layouts listed could be clicked.
+ return true;
+}
+
+menus::MenuModel* LanguageMenuButton::GetSubmenuModelAt(int index) const {
+ return NULL;
+}
+
+void LanguageMenuButton::HighlightChangedTo(int index) {
+ // Views for Chromium OS does not support this interface yet.
+}
+
+void LanguageMenuButton::MenuWillShow() {
+ // Views for Chromium OS does not support this interface yet.
+}
+
+int LanguageMenuButton::GetItemCount() const {
+ DCHECK(language_list_.get());
+ if (language_list_->empty()) {
+ return 1; // no separator; "Configure IME" only
+ }
+ return language_list_->size() + 2; // separator + "Configure IME"
+}
+
+menus::MenuModel::ItemType LanguageMenuButton::GetTypeAt(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(language_list_.get());
+ if (IsIndexShowControlPanel(index, language_list_.get())) {
+ return menus::MenuModel::TYPE_COMMAND; // "Configure IME"
+ }
+ if (static_cast<size_t>(index) < language_list_->size()) {
+ return menus::MenuModel::TYPE_RADIO;
+ }
+
+ DCHECK_EQ(static_cast<size_t>(index), language_list_->size());
+ return menus::MenuModel::TYPE_SEPARATOR;
+}
+
+string16 LanguageMenuButton::GetLabelAt(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK(language_list_.get());
+ if (IsIndexShowControlPanel(index, language_list_.get())) {
+ // TODO(yusukes): Use message catalog.
+ return WideToUTF16(L"Configure IME...");
+ }
+ if (static_cast<size_t>(index) < language_list_->size()) {
+ std::string name = FormatInputLanguage(language_list_->at(index), true);
+ return UTF8ToUTF16(name);
+ }
+ NOTREACHED();
+ return WideToUTF16(L"");
+}
+
+void LanguageMenuButton::ActivatedAt(int index) {
+ DCHECK_GE(index, 0);
+ DCHECK(language_list_.get());
+ if (IsIndexShowControlPanel(index, language_list_.get())) {
+ browser_->ShowControlPanel();
+ return;
+ }
+ if (static_cast<size_t>(index) < language_list_->size()) {
+ const InputLanguage& language = language_list_->at(index);
+ LanguageLibrary::Get()->ChangeLanguage(language.category, language.id);
+ return;
+ }
+ NOTREACHED();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// LanguageMenuButton, views::ViewMenuDelegate implementation:
+
+void LanguageMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
+ language_list_.reset(LanguageLibrary::Get()->GetLanguages());
+ language_menu_.Rebuild();
+ language_menu_.UpdateStates();
+ language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// LanguageMenuButton, PowerLibrary::Observer implementation:
+
+void LanguageMenuButton::LanguageChanged(LanguageLibrary* obj) {
+ const std::string name = FormatInputLanguage(obj->current_language(), false);
+ UpdateIcon(UTF8ToWide(name));
+}
+
+void LanguageMenuButton::UpdateIcon(const std::wstring& name) {
+ set_border(NULL);
+ SetFont(ResourceBundle::GetSharedInstance().GetFont(
+ ResourceBundle::BaseFont).DeriveFont(0, gfx::Font::BOLD));
+ SetEnabledColor(SK_ColorWHITE);
+ SetShowHighlighted(false);
+ SetText(name);
+ // TODO(yusukes): Show icon on the status area?
+ set_alignment(TextButton::ALIGN_RIGHT);
+ SchedulePaint();
+}
+
+// TODO(yusukes): Register and handle hotkeys for IME and XKB switching?
+
+} // namespace chromeos
+
diff --git a/chrome/browser/chromeos/language_menu_button.h b/chrome/browser/chromeos/language_menu_button.h
new file mode 100644
index 0000000..f1ebfbc
--- /dev/null
+++ b/chrome/browser/chromeos/language_menu_button.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LANGUAGE_MENU_BUTTON_H_
+#define CHROME_BROWSER_CHROMEOS_LANGUAGE_MENU_BUTTON_H_
+
+#include "chrome/browser/chromeos/language_library.h"
+#include "chrome/browser/chromeos/status_area_button.h"
+#include "views/controls/menu/menu_2.h"
+#include "views/controls/menu/view_menu_delegate.h"
+
+class Browser;
+class SkBitmap;
+
+namespace chromeos {
+
+// The language menu button in the status area.
+// This class will handle getting the IME/XKB status and populating the menu.
+class LanguageMenuButton : public views::MenuButton,
+ public views::ViewMenuDelegate,
+ public menus::MenuModel,
+ public LanguageLibrary::Observer {
+ public:
+ explicit LanguageMenuButton(Browser* browser);
+ virtual ~LanguageMenuButton();
+
+ // views::Menu2Model implementation.
+ virtual bool HasIcons() const;
+ virtual int GetItemCount() const;
+ virtual menus::MenuModel::ItemType GetTypeAt(int index) const;
+ virtual int GetCommandIdAt(int index) const;
+ virtual string16 GetLabelAt(int index) const;
+ virtual bool IsLabelDynamicAt(int index) const;
+ virtual bool GetAcceleratorAt(int index,
+ menus::Accelerator* accelerator) const;
+ virtual bool IsItemCheckedAt(int index) const;
+ virtual int GetGroupIdAt(int index) const;
+ virtual bool GetIconAt(int index, SkBitmap* icon) const;
+ virtual bool IsEnabledAt(int index) const;
+ virtual menus::MenuModel* GetSubmenuModelAt(int index) const;
+ virtual void HighlightChangedTo(int index);
+ virtual void ActivatedAt(int index);
+ virtual void MenuWillShow();
+
+ // LanguageLibrary::Observer implementation.
+ virtual void LanguageChanged(LanguageLibrary* obj);
+
+ private:
+ // views::ViewMenuDelegate implementation.
+ virtual void RunMenu(views::View* source, const gfx::Point& pt);
+
+ // Update the status area with |name|.
+ void UpdateIcon(const std::wstring& name);
+
+ // The current language list.
+ scoped_ptr<InputLanguageList> language_list_;
+
+ // The language menu.
+ views::Menu2 language_menu_;
+ // The browser window that owns us.
+ Browser* browser_;
+
+ DISALLOW_COPY_AND_ASSIGN(LanguageMenuButton);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LANGUAGE_MENU_BUTTON_H_
diff --git a/chrome/browser/chromeos/status_area_view.cc b/chrome/browser/chromeos/status_area_view.cc
index f3ba39d..bb58e11 100755
--- a/chrome/browser/chromeos/status_area_view.cc
+++ b/chrome/browser/chromeos/status_area_view.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chromeos/clock_menu_button.h"
+#include "chrome/browser/chromeos/language_menu_button.h"
#include "chrome/browser/chromeos/network_menu_button.h"
#include "chrome/browser/chromeos/power_menu_button.h"
#include "chrome/browser/chromeos/status_area_button.h"
@@ -37,6 +38,9 @@ namespace chromeos {
const int kLeftBorder = 1;
// Number of pixels to separate the clock from the next item on the right.
const int kClockSeparation = 4;
+// Number of pixels to separate the language selector from the next item
+// on the right.
+const int kLanguageSeparation = 4;
// BrowserWindowGtk tiles its image with this offset
const int kCustomFrameBackgroundVerticalOffset = 15;
@@ -126,6 +130,7 @@ StatusAreaView::StatusAreaView(Browser* browser,
: browser_(browser),
window_(window),
clock_view_(NULL),
+ language_view_(NULL),
network_view_(NULL),
battery_view_(NULL),
menu_view_(NULL) {
@@ -134,6 +139,10 @@ StatusAreaView::StatusAreaView(Browser* browser,
void StatusAreaView::Init() {
ThemeProvider* theme = browser_->profile()->GetThemeProvider();
+ // Language.
+ language_view_ = new LanguageMenuButton(browser_);
+ AddChildView(language_view_);
+
// Clock.
clock_view_ = new ClockMenuButton(browser_);
AddChildView(clock_view_);
@@ -164,7 +173,7 @@ void StatusAreaView::Update() {
gfx::Size StatusAreaView::GetPreferredSize() {
// Start with padding.
- int result_w = kLeftBorder + kClockSeparation;
+ int result_w = kLeftBorder + kClockSeparation + kLanguageSeparation;
int result_h = 0;
for (int i = 0; i < GetChildViewCount(); i++) {
views::View* cur = GetChildViewAt(i);
@@ -195,9 +204,11 @@ void StatusAreaView::Layout() {
cur_x += cur_size.width();
- // Buttons have built in padding, but clock doesn't.
+ // Buttons have built in padding, but clock and language status don't.
if (cur == clock_view_)
cur_x += kClockSeparation;
+ else if (cur == language_view_)
+ cur_x += kLanguageSeparation;
}
}
}
diff --git a/chrome/browser/chromeos/status_area_view.h b/chrome/browser/chromeos/status_area_view.h
index 95cfdf6..ee3a172 100644
--- a/chrome/browser/chromeos/status_area_view.h
+++ b/chrome/browser/chromeos/status_area_view.h
@@ -17,6 +17,7 @@ class Browser;
namespace chromeos {
class ClockMenuButton;
+class LanguageMenuButton;
class NetworkMenuButton;
class PowerMenuButton;
class StatusAreaButton;
@@ -73,6 +74,7 @@ class StatusAreaView : public views::View,
gfx::NativeWindow window_;
ClockMenuButton* clock_view_;
+ LanguageMenuButton* language_view_;
NetworkMenuButton* network_view_;
PowerMenuButton* battery_view_;
StatusAreaButton* menu_view_;