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/screensaver/screensaver_view.h"
6
7#include "ash/shell.h"
8#include "ash/shell_delegate.h"
9#include "base/bind.h"
10#include "base/logging.h"
11#include "content/public/browser/browser_context.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/browser/web_contents.h"
14#include "ui/aura/window_event_dispatcher.h"
15#include "ui/gfx/screen.h"
16#include "ui/views/controls/webview/webview.h"
17#include "ui/views/layout/fill_layout.h"
18#include "ui/views/widget/widget.h"
19
20using content::BrowserThread;
21
22namespace {
23
24ash::ScreensaverView* g_instance = NULL;
25
26// Do not restart the screensaver again if it has
27// terminated kMaxTerminations times already.
28const int kMaxTerminations = 3;
29
30}  // namespace
31
32namespace ash {
33
34void ShowScreensaver(const GURL& url) { ScreensaverView::ShowScreensaver(url); }
35
36void CloseScreensaver() { ScreensaverView::CloseScreensaver(); }
37
38bool IsScreensaverShown() { return ScreensaverView::IsScreensaverShown(); }
39
40// static
41void ScreensaverView::ShowScreensaver(const GURL& url) {
42  if (!g_instance) {
43    g_instance = new ScreensaverView(url);
44    g_instance->Show();
45  }
46}
47
48// static
49void ScreensaverView::CloseScreensaver() {
50  if (g_instance) {
51    g_instance->Close();
52    g_instance = NULL;
53  }
54}
55
56// static
57bool ScreensaverView::IsScreensaverShown() {
58  return g_instance && g_instance->IsScreensaverShowingURL(g_instance->url_);
59}
60
61bool ScreensaverView::IsScreensaverShowingURL(const GURL& url) {
62  return screensaver_webview_ &&
63      screensaver_webview_->web_contents() &&
64      (screensaver_webview_->web_contents()->GetURL() == url);
65}
66
67////////////////////////////////////////////////////////////////////////////////
68// ScreensaverView, views::WidgetDelegateView implementation.
69views::View* ScreensaverView::GetContentsView() {
70  return this;
71}
72
73////////////////////////////////////////////////////////////////////////////////
74// ScreensaverView, content::WebContentsObserver implementation.
75void ScreensaverView::RenderProcessGone(
76    base::TerminationStatus status) {
77  LOG(ERROR) << "Screensaver terminated with status " << status;
78  termination_count_++;
79
80  if (termination_count_ < kMaxTerminations) {
81    LOG(ERROR) << termination_count_
82               << " terminations is under the threshold of "
83               << kMaxTerminations
84               << "; reloading Screensaver.";
85    LoadScreensaver();
86  } else {
87    LOG(ERROR) << "Exceeded termination threshold, closing Screensaver.";
88    ScreensaverView::CloseScreensaver();
89  }
90}
91
92////////////////////////////////////////////////////////////////////////////////
93// ScreensaverView private methods.
94ScreensaverView::ScreensaverView(const GURL& url)
95    : url_(url),
96      termination_count_(0),
97      screensaver_webview_(NULL),
98      container_window_(NULL) {
99}
100
101ScreensaverView::~ScreensaverView() {
102}
103
104void ScreensaverView::Show() {
105  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
106  // Add the WebView to our view.
107  AddChildWebContents();
108  // Show the window.
109  ShowWindow();
110}
111
112void ScreensaverView::Close() {
113  DCHECK(GetWidget());
114  GetWidget()->Close();
115}
116
117void ScreensaverView::AddChildWebContents() {
118  content::BrowserContext* context =
119      Shell::GetInstance()->delegate()->GetActiveBrowserContext();
120  screensaver_webview_ = new views::WebView(context);
121  SetLayoutManager(new views::FillLayout);
122  AddChildView(screensaver_webview_);
123
124  LoadScreensaver();
125  content::WebContentsObserver::Observe(
126      screensaver_webview_->GetWebContents());
127}
128
129void ScreensaverView::LoadScreensaver() {
130  screensaver_webview_->GetWebContents()->GetController().LoadURL(
131        url_,
132        content::Referrer(),
133        ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
134        std::string());
135}
136
137void ScreensaverView::ShowWindow() {
138  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
139  gfx::Rect screen_rect =
140      Shell::GetScreen()->GetDisplayNearestWindow(root_window).bounds();
141
142  // We want to be the fullscreen topmost child of the root window.
143  // There should be nothing ever really that should show up on top of us.
144  container_window_ = new views::Widget();
145  views::Widget::InitParams params(
146      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
147  params.delegate = this;
148  params.parent = root_window;
149  container_window_->Init(params);
150
151  container_window_->StackAtTop();
152  container_window_->SetBounds(screen_rect);
153  container_window_->Show();
154}
155
156// static
157ScreensaverView* ScreensaverView::GetInstance() {
158  return g_instance;
159}
160
161}  // namespace ash
162