background_view.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2011 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 "chrome/browser/chromeos/login/background_view.h" 6 7#include <string> 8#include <vector> 9 10#include "base/string16.h" 11#include "base/string_util.h" 12#include "base/stringprintf.h" 13#include "base/utf_string_conversions.h" 14#include "chrome/browser/chromeos/login/helper.h" 15#include "chrome/browser/chromeos/login/login_utils.h" 16#include "chrome/browser/chromeos/login/oobe_progress_bar.h" 17#include "chrome/browser/chromeos/login/proxy_settings_dialog.h" 18#include "chrome/browser/chromeos/login/rounded_rect_painter.h" 19#include "chrome/browser/chromeos/login/shutdown_button.h" 20#include "chrome/browser/chromeos/login/wizard_controller.h" 21#include "chrome/browser/chromeos/status/clock_menu_button.h" 22#include "chrome/browser/chromeos/status/input_method_menu_button.h" 23#include "chrome/browser/chromeos/status/network_menu_button.h" 24#include "chrome/browser/chromeos/status/status_area_view.h" 25#include "chrome/browser/chromeos/wm_ipc.h" 26#include "chrome/browser/profiles/profile_manager.h" 27#include "chrome/browser/ui/views/dom_view.h" 28#include "chrome/browser/ui/views/window.h" 29#include "googleurl/src/gurl.h" 30#include "grit/chromium_strings.h" 31#include "grit/generated_resources.h" 32#include "grit/theme_resources.h" 33#include "third_party/cros/chromeos_wm_ipc_enums.h" 34#include "ui/base/l10n/l10n_util.h" 35#include "ui/base/resource/resource_bundle.h" 36#include "ui/base/x/x11_util.h" 37#include "ui/gfx/gtk_util.h" 38#include "views/controls/button/text_button.h" 39#include "views/controls/label.h" 40#include "views/screen.h" 41#include "views/widget/widget_gtk.h" 42#include "views/window/window.h" 43 44// X Windows headers have "#define Status int". That interferes with 45// NetworkLibrary header which defines enum "Status". 46#include <X11/cursorfont.h> // NOLINT 47#include <X11/Xcursor/Xcursor.h> // NOLINT 48 49using views::WidgetGtk; 50 51namespace { 52 53const SkColor kVersionColor = 0xff5c739f; 54 55// Returns the corresponding step id for step constant. 56int GetStepId(size_t step) { 57 switch (step) { 58 case chromeos::BackgroundView::SELECT_NETWORK: 59 return IDS_OOBE_SELECT_NETWORK; 60 case chromeos::BackgroundView::EULA: 61 return IDS_OOBE_EULA; 62 case chromeos::BackgroundView::SIGNIN: 63 return IDS_OOBE_SIGNIN; 64 case chromeos::BackgroundView::REGISTRATION: 65 return IDS_OOBE_REGISTRATION; 66 case chromeos::BackgroundView::PICTURE: 67 return IDS_OOBE_PICTURE; 68 default: 69 NOTREACHED(); 70 return 0; 71 } 72} 73 74// The same as TextButton but switches cursor to hand cursor when mouse 75// is over the button. 76class TextButtonWithHandCursorOver : public views::TextButton { 77 public: 78 TextButtonWithHandCursorOver(views::ButtonListener* listener, 79 const std::wstring& text) 80 : views::TextButton(listener, text) { 81 } 82 83 virtual ~TextButtonWithHandCursorOver() {} 84 85 virtual gfx::NativeCursor GetCursorForPoint( 86 ui::EventType event_type, 87 const gfx::Point& p) { 88 if (!IsEnabled()) { 89 return NULL; 90 } 91 return gfx::GetCursor(GDK_HAND2); 92 } 93 94 private: 95 DISALLOW_COPY_AND_ASSIGN(TextButtonWithHandCursorOver); 96}; 97 98// This gets rid of the ugly X default cursor. 99static void ResetXCursor() { 100 // TODO(sky): nuke this once new window manager is in place. 101 Display* display = ui::GetXDisplay(); 102 Cursor cursor = XCreateFontCursor(display, XC_left_ptr); 103 XID root_window = ui::GetX11RootWindow(); 104 XSetWindowAttributes attr; 105 attr.cursor = cursor; 106 XChangeWindowAttributes(display, root_window, CWCursor, &attr); 107} 108 109} // namespace 110 111namespace chromeos { 112 113/////////////////////////////////////////////////////////////////////////////// 114// BackgroundView public: 115 116BackgroundView::BackgroundView() 117 : status_area_(NULL), 118 os_version_label_(NULL), 119 boot_times_label_(NULL), 120 progress_bar_(NULL), 121 shutdown_button_(NULL), 122 did_paint_(false), 123#if defined(OFFICIAL_BUILD) 124 is_official_build_(true), 125#else 126 is_official_build_(false), 127#endif 128 background_area_(NULL) { 129} 130 131void BackgroundView::Init(const GURL& background_url) { 132 views::Painter* painter = CreateBackgroundPainter(); 133 set_background(views::Background::CreateBackgroundPainter(true, painter)); 134 InitStatusArea(); 135 InitInfoLabels(); 136 if (!background_url.is_empty()) { 137 Profile* profile = ProfileManager::GetDefaultProfile(); 138 background_area_ = new DOMView(); 139 AddChildView(background_area_); 140 background_area_->Init(profile, NULL); 141 background_area_->SetVisible(false); 142 background_area_->LoadURL(background_url); 143 } 144} 145 146void BackgroundView::EnableShutdownButton(bool enable) { 147 if (enable) { 148 if (shutdown_button_) 149 return; 150 shutdown_button_ = new ShutdownButton(); 151 shutdown_button_->Init(); 152 AddChildView(shutdown_button_); 153 } else { 154 if (!shutdown_button_) 155 return; 156 delete shutdown_button_; 157 shutdown_button_ = NULL; 158 SchedulePaint(); 159 } 160} 161 162// static 163views::Widget* BackgroundView::CreateWindowContainingView( 164 const gfx::Rect& bounds, 165 const GURL& background_url, 166 BackgroundView** view) { 167 ResetXCursor(); 168 169 WidgetGtk* window = new WidgetGtk(WidgetGtk::TYPE_WINDOW); 170 window->Init(NULL, bounds); 171 *view = new BackgroundView(); 172 (*view)->Init(background_url); 173 174 if ((*view)->ScreenSaverEnabled()) 175 (*view)->ShowScreenSaver(); 176 177 window->SetContentsView(*view); 178 179 (*view)->UpdateWindowType(); 180 181 // This keeps the window from flashing at startup. 182 GdkWindow* gdk_window = window->GetNativeView()->window; 183 gdk_window_set_back_pixmap(gdk_window, NULL, false); 184 185 LoginUtils::Get()->SetBackgroundView(*view); 186 187 return window; 188} 189 190void BackgroundView::CreateModalPopup(views::WindowDelegate* view) { 191 views::Window* window = browser::CreateViewsWindow( 192 GetNativeWindow(), gfx::Rect(), view); 193 window->SetIsAlwaysOnTop(true); 194 window->Show(); 195} 196 197gfx::NativeWindow BackgroundView::GetNativeWindow() const { 198 return 199 GTK_WINDOW(static_cast<const WidgetGtk*>(GetWidget())->GetNativeView()); 200} 201 202void BackgroundView::SetStatusAreaVisible(bool visible) { 203 status_area_->SetVisible(visible); 204} 205 206void BackgroundView::SetStatusAreaEnabled(bool enable) { 207 status_area_->MakeButtonsActive(enable); 208} 209 210void BackgroundView::SetOobeProgressBarVisible(bool visible) { 211 if (!progress_bar_ && visible) 212 InitProgressBar(); 213 214 if (progress_bar_) 215 progress_bar_->SetVisible(visible); 216} 217 218bool BackgroundView::IsOobeProgressBarVisible() { 219 return progress_bar_ && progress_bar_->IsVisible(); 220} 221 222void BackgroundView::SetOobeProgress(LoginStep step) { 223 DCHECK(step < STEPS_COUNT); 224 if (progress_bar_) 225 progress_bar_->SetStep(GetStepId(step)); 226} 227 228void BackgroundView::ShowScreenSaver() { 229 SetStatusAreaVisible(false); 230 background_area_->SetVisible(true); 231} 232 233void BackgroundView::HideScreenSaver() { 234 SetStatusAreaVisible(true); 235 // TODO(oshima): we need a way to suspend screen saver 236 // to save power when it's not visible. 237 background_area_->SetVisible(false); 238} 239 240bool BackgroundView::IsScreenSaverVisible() { 241 return ScreenSaverEnabled() && background_area_->IsVisible(); 242} 243 244bool BackgroundView::ScreenSaverEnabled() { 245 return background_area_ != NULL; 246} 247 248/////////////////////////////////////////////////////////////////////////////// 249// BackgroundView protected: 250 251void BackgroundView::Paint(gfx::Canvas* canvas) { 252 views::View::Paint(canvas); 253 if (!did_paint_) { 254 did_paint_ = true; 255 UpdateWindowType(); 256 } 257} 258 259void BackgroundView::Layout() { 260 const int kCornerPadding = 5; 261 const int kInfoLeftPadding = 10; 262 const int kInfoBottomPadding = 10; 263 const int kInfoBetweenLinesPadding = 1; 264 const int kProgressBarBottomPadding = 20; 265 const int kProgressBarWidth = 750; 266 const int kProgressBarHeight = 70; 267 gfx::Size status_area_size = status_area_->GetPreferredSize(); 268 status_area_->SetBounds( 269 width() - status_area_size.width() - kCornerPadding, 270 kCornerPadding, 271 status_area_size.width(), 272 status_area_size.height()); 273 gfx::Size version_size = os_version_label_->GetPreferredSize(); 274 int os_version_y = height() - version_size.height() - kInfoBottomPadding; 275 if (!is_official_build_) 276 os_version_y -= (version_size.height() + kInfoBetweenLinesPadding); 277 os_version_label_->SetBounds( 278 kInfoLeftPadding, 279 os_version_y, 280 width() - 2 * kInfoLeftPadding, 281 version_size.height()); 282 if (!is_official_build_) { 283 boot_times_label_->SetBounds( 284 kInfoLeftPadding, 285 height() - (version_size.height() + kInfoBottomPadding), 286 width() - 2 * kInfoLeftPadding, 287 version_size.height()); 288 } 289 if (progress_bar_) { 290 progress_bar_->SetBounds( 291 (width() - kProgressBarWidth) / 2, 292 (height() - kProgressBarBottomPadding - kProgressBarHeight), 293 kProgressBarWidth, 294 kProgressBarHeight); 295 } 296 if (shutdown_button_) { 297 shutdown_button_->LayoutIn(this); 298 } 299 if (background_area_) 300 background_area_->SetBoundsRect(this->bounds()); 301} 302 303void BackgroundView::ChildPreferredSizeChanged(View* child) { 304 Layout(); 305 SchedulePaint(); 306} 307 308bool BackgroundView::ShouldOpenButtonOptions( 309 const views::View* button_view) const { 310 if (button_view == status_area_->network_view()) { 311 return true; 312 } 313 if (button_view == status_area_->clock_view() || 314 button_view == status_area_->input_method_view()) { 315 return false; 316 } 317 return true; 318} 319 320void BackgroundView::OpenButtonOptions(const views::View* button_view) { 321 if (button_view == status_area_->network_view()) { 322 if (proxy_settings_dialog_.get() == NULL) { 323 proxy_settings_dialog_.reset(new ProxySettingsDialog( 324 this, GetNativeWindow())); 325 } 326 proxy_settings_dialog_->Show(); 327 } 328} 329 330StatusAreaHost::ScreenMode BackgroundView::GetScreenMode() const { 331 return kLoginMode; 332} 333 334// Overridden from LoginHtmlDialog::Delegate: 335void BackgroundView::OnLocaleChanged() { 336 // Proxy settings dialog contains localized strings. 337 proxy_settings_dialog_.reset(); 338} 339 340/////////////////////////////////////////////////////////////////////////////// 341// BackgroundView private: 342 343void BackgroundView::InitStatusArea() { 344 DCHECK(status_area_ == NULL); 345 status_area_ = new StatusAreaView(this); 346 status_area_->Init(); 347 AddChildView(status_area_); 348} 349 350void BackgroundView::InitInfoLabels() { 351 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 352 353 os_version_label_ = new views::Label(); 354 os_version_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 355 os_version_label_->SetColor(kVersionColor); 356 os_version_label_->SetFont(rb.GetFont(ResourceBundle::SmallFont)); 357 AddChildView(os_version_label_); 358 if (!is_official_build_) { 359 boot_times_label_ = new views::Label(); 360 boot_times_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 361 boot_times_label_->SetColor(kVersionColor); 362 boot_times_label_->SetFont(rb.GetFont(ResourceBundle::SmallFont)); 363 AddChildView(boot_times_label_); 364 } 365 366 if (CrosLibrary::Get()->EnsureLoaded()) { 367 version_loader_.GetVersion( 368 &version_consumer_, 369 NewCallback(this, &BackgroundView::OnVersion), 370 is_official_build_? 371 VersionLoader::VERSION_SHORT_WITH_DATE : 372 VersionLoader::VERSION_FULL); 373 if (!is_official_build_) { 374 boot_times_loader_.GetBootTimes( 375 &boot_times_consumer_, 376 NewCallback(this, &BackgroundView::OnBootTimes)); 377 } 378 } else { 379 os_version_label_->SetText( 380 ASCIIToWide(CrosLibrary::Get()->load_error_string())); 381 } 382} 383 384void BackgroundView::InitProgressBar() { 385 std::vector<int> steps; 386 steps.push_back(GetStepId(SELECT_NETWORK)); 387#if defined(OFFICIAL_BUILD) 388 steps.push_back(GetStepId(EULA)); 389#endif 390 steps.push_back(GetStepId(SIGNIN)); 391#if defined(OFFICIAL_BUILD) 392 if (WizardController::IsRegisterScreenDefined()) 393 steps.push_back(GetStepId(REGISTRATION)); 394#endif 395 steps.push_back(GetStepId(PICTURE)); 396 progress_bar_ = new OobeProgressBar(steps); 397 AddChildView(progress_bar_); 398} 399 400void BackgroundView::UpdateWindowType() { 401 std::vector<int> params; 402 params.push_back(did_paint_ ? 1 : 0); 403 WmIpc::instance()->SetWindowType( 404 GTK_WIDGET(GetNativeWindow()), 405 WM_IPC_WINDOW_LOGIN_BACKGROUND, 406 ¶ms); 407} 408 409void BackgroundView::OnVersion( 410 VersionLoader::Handle handle, std::string version) { 411 // TODO(jungshik): Is string concatenation OK here? 412 std::string version_text = l10n_util::GetStringUTF8(IDS_PRODUCT_OS_NAME); 413 version_text += ' '; 414 version_text += l10n_util::GetStringUTF8(IDS_VERSION_FIELD_PREFIX); 415 version_text += ' '; 416 version_text += version; 417 418 // Workaround over incorrect width calculation in old fonts. 419 // TODO(glotov): remove the following line when new fonts are used. 420 version_text += ' '; 421 os_version_label_->SetText(UTF8ToWide(version_text)); 422} 423 424void BackgroundView::OnBootTimes( 425 BootTimesLoader::Handle handle, BootTimesLoader::BootTimes boot_times) { 426 const char* kBootTimesNoChromeExec = 427 "Non-firmware boot took %.2f seconds (kernel %.2fs, system %.2fs)"; 428 const char* kBootTimesChromeExec = 429 "Non-firmware boot took %.2f seconds " 430 "(kernel %.2fs, system %.2fs, chrome %.2fs)"; 431 std::string boot_times_text; 432 433 if (boot_times.chrome > 0) { 434 boot_times_text = 435 base::StringPrintf( 436 kBootTimesChromeExec, 437 boot_times.total, 438 boot_times.pre_startup, 439 boot_times.system, 440 boot_times.chrome); 441 } else { 442 boot_times_text = 443 base::StringPrintf( 444 kBootTimesNoChromeExec, 445 boot_times.total, 446 boot_times.pre_startup, 447 boot_times.system); 448 } 449 // Use UTF8ToWide once this string is localized. 450 boot_times_label_->SetText(ASCIIToWide(boot_times_text)); 451} 452 453} // namespace chromeos 454