Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: chrome/browser/ui/views/fullscreen_exit_bubble_views.cc

Issue 7549005: Abstract fullscreen exit bubble logic to bring Linux's behaviour in line with (Closed) Base URL: /usr/local/google/chromium2/src@trunk
Patch Set: Rebase attempt #3. Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/ui/views/fullscreen_exit_bubble_views.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/views/fullscreen_exit_bubble.h" 5 #include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h"
6 6
7 #include "base/message_loop.h" 7 #include "base/message_loop.h"
8 #include "base/utf_string_conversions.h" 8 #include "base/utf_string_conversions.h"
9 #include "chrome/app/chrome_command_ids.h" 9 #include "chrome/app/chrome_command_ids.h"
10 #include "grit/generated_resources.h" 10 #include "grit/generated_resources.h"
11 #include "ui/base/animation/slide_animation.h" 11 #include "ui/base/animation/slide_animation.h"
12 #include "ui/base/keycodes/keyboard_codes.h" 12 #include "ui/base/keycodes/keyboard_codes.h"
13 #include "ui/base/l10n/l10n_util.h" 13 #include "ui/base/l10n/l10n_util.h"
14 #include "ui/base/resource/resource_bundle.h" 14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/canvas_skia.h" 15 #include "ui/gfx/canvas_skia.h"
16 #include "ui/gfx/screen.h" 16 #include "ui/gfx/screen.h"
17 #include "views/controls/link.h" 17 #include "views/controls/link.h"
18 #include "views/widget/widget.h" 18 #include "views/widget/widget.h"
19 19
20 #if defined(OS_WIN) 20 #if defined(OS_WIN)
21 #include "ui/base/l10n/l10n_util_win.h" 21 #include "ui/base/l10n/l10n_util_win.h"
22 #endif 22 #endif
23 23
24 // FullscreenExitView ---------------------------------------------------------- 24 // FullscreenExitView ----------------------------------------------------------
25 25
26 class FullscreenExitBubble::FullscreenExitView : public views::View { 26 class FullscreenExitBubbleViews::FullscreenExitView : public views::View {
27 public: 27 public:
28 FullscreenExitView(FullscreenExitBubble* bubble, 28 FullscreenExitView(FullscreenExitBubbleViews* bubble,
29 const std::wstring& accelerator); 29 const std::wstring& accelerator);
30 virtual ~FullscreenExitView(); 30 virtual ~FullscreenExitView();
31 31
32 // views::View 32 // views::View
33 virtual gfx::Size GetPreferredSize(); 33 virtual gfx::Size GetPreferredSize();
34 34
35 private: 35 private:
36 static const int kPaddingPixels; // Number of pixels around all sides of link
37
38 // views::View 36 // views::View
39 virtual void Layout(); 37 virtual void Layout();
40 virtual void OnPaint(gfx::Canvas* canvas); 38 virtual void OnPaint(gfx::Canvas* canvas);
41 39
42 // Clickable hint text to show in the bubble. 40 // Clickable hint text to show in the bubble.
43 views::Link link_; 41 views::Link link_;
44 }; 42 };
45 43
46 const int FullscreenExitBubble::FullscreenExitView::kPaddingPixels = 8; 44 FullscreenExitBubbleViews::FullscreenExitView::FullscreenExitView(
47 45 FullscreenExitBubbleViews* bubble,
48 FullscreenExitBubble::FullscreenExitView::FullscreenExitView(
49 FullscreenExitBubble* bubble,
50 const std::wstring& accelerator) { 46 const std::wstring& accelerator) {
51 link_.set_parent_owned(false); 47 link_.set_parent_owned(false);
52 #if !defined(OS_CHROMEOS) 48 #if !defined(OS_CHROMEOS)
53 link_.SetText( 49 link_.SetText(
54 UTF16ToWide(l10n_util::GetStringFUTF16(IDS_EXIT_FULLSCREEN_MODE, 50 UTF16ToWide(l10n_util::GetStringFUTF16(IDS_EXIT_FULLSCREEN_MODE,
55 WideToUTF16(accelerator)))); 51 WideToUTF16(accelerator))));
56 #else 52 #else
57 link_.SetText( 53 link_.SetText(
58 UTF16ToWide(l10n_util::GetStringUTF16(IDS_EXIT_FULLSCREEN_MODE))); 54 UTF16ToWide(l10n_util::GetStringUTF16(IDS_EXIT_FULLSCREEN_MODE)));
59 #endif 55 #endif
60 link_.set_listener(bubble); 56 link_.set_listener(bubble);
61 link_.SetFont(ResourceBundle::GetSharedInstance().GetFont( 57 link_.SetFont(ResourceBundle::GetSharedInstance().GetFont(
62 ResourceBundle::LargeFont)); 58 ResourceBundle::LargeFont));
63 link_.SetNormalColor(SK_ColorWHITE); 59 link_.SetNormalColor(SK_ColorWHITE);
64 link_.SetHighlightedColor(SK_ColorWHITE); 60 link_.SetHighlightedColor(SK_ColorWHITE);
65 AddChildView(&link_); 61 AddChildView(&link_);
66 } 62 }
67 63
68 FullscreenExitBubble::FullscreenExitView::~FullscreenExitView() { 64 FullscreenExitBubbleViews::FullscreenExitView::~FullscreenExitView() {
69 } 65 }
70 66
71 gfx::Size FullscreenExitBubble::FullscreenExitView::GetPreferredSize() { 67 gfx::Size FullscreenExitBubbleViews::FullscreenExitView::GetPreferredSize() {
72 gfx::Size preferred_size(link_.GetPreferredSize()); 68 gfx::Size preferred_size(link_.GetPreferredSize());
73 preferred_size.Enlarge(kPaddingPixels * 2, kPaddingPixels * 2); 69 preferred_size.Enlarge(kPaddingPx * 2, kPaddingPx * 2);
74 return preferred_size; 70 return preferred_size;
75 } 71 }
76 72
77 void FullscreenExitBubble::FullscreenExitView::Layout() { 73 void FullscreenExitBubbleViews::FullscreenExitView::Layout() {
78 gfx::Size link_preferred_size(link_.GetPreferredSize()); 74 gfx::Size link_preferred_size(link_.GetPreferredSize());
79 link_.SetBounds(kPaddingPixels, 75 link_.SetBounds(kPaddingPx,
80 height() - kPaddingPixels - link_preferred_size.height(), 76 height() - kPaddingPx - link_preferred_size.height(),
81 link_preferred_size.width(), link_preferred_size.height()); 77 link_preferred_size.width(), link_preferred_size.height());
82 } 78 }
83 79
84 void FullscreenExitBubble::FullscreenExitView::OnPaint(gfx::Canvas* canvas) { 80 void FullscreenExitBubbleViews::FullscreenExitView::OnPaint(gfx::Canvas* canvas) {
85 // Create a round-bottomed rect to fill the whole View. 81 // Create a round-bottomed rect to fill the whole View.
86 SkRect rect; 82 SkRect rect;
87 SkScalar padding = SkIntToScalar(kPaddingPixels); 83 SkScalar padding = SkIntToScalar(kPaddingPx);
88 // The "-padding" top coordinate ensures that the rect is always tall enough 84 // The "-padding" top coordinate ensures that the rect is always tall enough
89 // to contain the complete rounded corner radius. If we set this to 0, as the 85 // to contain the complete rounded corner radius. If we set this to 0, as the
90 // popup slides offscreen (in reality, squishes to 0 height), the corners will 86 // popup slides offscreen (in reality, squishes to 0 height), the corners will
91 // flatten out as the height becomes less than the corner radius. 87 // flatten out as the height becomes less than the corner radius.
92 rect.set(0, -padding, SkIntToScalar(width()), SkIntToScalar(height())); 88 rect.set(0, -padding, SkIntToScalar(width()), SkIntToScalar(height()));
93 SkScalar rad[8] = { 0, 0, 0, 0, padding, padding, padding, padding }; 89 SkScalar rad[8] = { 0, 0, 0, 0, padding, padding, padding, padding };
94 SkPath path; 90 SkPath path;
95 path.addRoundRect(rect, rad, SkPath::kCW_Direction); 91 path.addRoundRect(rect, rad, SkPath::kCW_Direction);
96 92
97 // Fill it black. 93 // Fill it black.
98 SkPaint paint; 94 SkPaint paint;
99 paint.setStyle(SkPaint::kFill_Style); 95 paint.setStyle(SkPaint::kFill_Style);
100 paint.setFlags(SkPaint::kAntiAlias_Flag); 96 paint.setFlags(SkPaint::kAntiAlias_Flag);
101 paint.setColor(SK_ColorBLACK); 97 paint.setColor(SK_ColorBLACK);
102 canvas->AsCanvasSkia()->drawPath(path, paint); 98 canvas->AsCanvasSkia()->drawPath(path, paint);
103 } 99 }
104 100
105 // FullscreenExitBubble -------------------------------------------------------- 101 // FullscreenExitBubbleViews ---------------------------------------------------
106 102
107 const double FullscreenExitBubble::kOpacity = 0.7; 103 FullscreenExitBubbleViews::FullscreenExitBubbleViews(
108 const int FullscreenExitBubble::kInitialDelayMs = 2300;
109 const int FullscreenExitBubble::kIdleTimeMs = 2300;
110 const int FullscreenExitBubble::kPositionCheckHz = 10;
111 const int FullscreenExitBubble::kSlideInRegionHeightPx = 4;
112 const int FullscreenExitBubble::kSlideInDurationMs = 350;
113 const int FullscreenExitBubble::kSlideOutDurationMs = 700;
114
115 FullscreenExitBubble::FullscreenExitBubble(
116 views::Widget* frame, 104 views::Widget* frame,
117 CommandUpdater::CommandUpdaterDelegate* delegate) 105 CommandUpdater::CommandUpdaterDelegate* delegate)
118 : root_view_(frame->GetRootView()), 106 : FullscreenExitBubble(delegate),
119 delegate_(delegate), 107 root_view_(frame->GetRootView()),
120 popup_(NULL), 108 popup_(NULL),
121 size_animation_(new ui::SlideAnimation(this)) { 109 size_animation_(new ui::SlideAnimation(this)) {
122 size_animation_->Reset(1); 110 size_animation_->Reset(1);
123 111
124 // Create the contents view. 112 // Create the contents view.
125 views::Accelerator accelerator(ui::VKEY_UNKNOWN, false, false, false); 113 views::Accelerator accelerator(ui::VKEY_UNKNOWN, false, false, false);
126 bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator); 114 bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator);
127 DCHECK(got_accelerator); 115 DCHECK(got_accelerator);
128 view_ = new FullscreenExitView( 116 view_ = new FullscreenExitView(
129 this, UTF16ToWideHack(accelerator.GetShortcutText())); 117 this, UTF16ToWideHack(accelerator.GetShortcutText()));
130 118
131 // Initialize the popup. 119 // Initialize the popup.
132 popup_ = new views::Widget; 120 popup_ = new views::Widget;
133 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 121 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
134 params.transparent = true; 122 params.transparent = true;
135 params.can_activate = false; 123 params.can_activate = false;
136 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 124 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
137 params.parent = frame->GetNativeView(); 125 params.parent = frame->GetNativeView();
138 params.bounds = GetPopupRect(false); 126 params.bounds = GetPopupRect(false);
139 popup_->Init(params); 127 popup_->Init(params);
140 popup_->SetContentsView(view_); 128 popup_->SetContentsView(view_);
141 popup_->SetOpacity(static_cast<unsigned char>(0xff * kOpacity)); 129 popup_->SetOpacity(static_cast<unsigned char>(0xff * kOpacity));
142 popup_->Show(); // This does not activate the popup. 130 popup_->Show(); // This does not activate the popup.
143 131
144 // Start the initial delay timer and begin watching the mouse. 132 StartWatchingMouse();
145 initial_delay_.Start(base::TimeDelta::FromMilliseconds(kInitialDelayMs), this,
146 &FullscreenExitBubble::CheckMousePosition);
147 gfx::Point cursor_pos = gfx::Screen::GetCursorScreenPoint();
148 last_mouse_pos_ = cursor_pos;
149 views::View::ConvertPointToView(NULL, root_view_, &last_mouse_pos_);
150 mouse_position_checker_.Start(
151 base::TimeDelta::FromMilliseconds(1000 / kPositionCheckHz), this,
152 &FullscreenExitBubble::CheckMousePosition);
153 } 133 }
154 134
155 FullscreenExitBubble::~FullscreenExitBubble() { 135 FullscreenExitBubbleViews::~FullscreenExitBubbleViews() {
156 // This is tricky. We may be in an ATL message handler stack, in which case 136 // This is tricky. We may be in an ATL message handler stack, in which case
157 // the popup cannot be deleted yet. We also can't set the popup's ownership 137 // the popup cannot be deleted yet. We also can't set the popup's ownership
158 // model to NATIVE_WIDGET_OWNS_WIDGET because if the user closed the last tab 138 // model to NATIVE_WIDGET_OWNS_WIDGET because if the user closed the last tab
159 // while in fullscreen mode, Windows has already destroyed the popup HWND by 139 // while in fullscreen mode, Windows has already destroyed the popup HWND by
160 // the time we get here, and thus either the popup will already have been 140 // the time we get here, and thus either the popup will already have been
161 // deleted (if we set this in our constructor) or the popup will never get 141 // deleted (if we set this in our constructor) or the popup will never get
162 // another OnFinalMessage() call (if not, as currently). So instead, we tell 142 // another OnFinalMessage() call (if not, as currently). So instead, we tell
163 // the popup to synchronously hide, and then asynchronously close and delete 143 // the popup to synchronously hide, and then asynchronously close and delete
164 // itself. 144 // itself.
165 popup_->Close(); 145 popup_->Close();
166 MessageLoop::current()->DeleteSoon(FROM_HERE, popup_); 146 MessageLoop::current()->DeleteSoon(FROM_HERE, popup_);
167 } 147 }
168 148
169 void FullscreenExitBubble::LinkClicked(views::Link* source, int event_flags) { 149 void FullscreenExitBubbleViews::LinkClicked(
170 delegate_->ExecuteCommand(IDC_FULLSCREEN); 150 views::Link* source, int event_flags) {
151 ToggleFullscreen();
171 } 152 }
172 153
173 void FullscreenExitBubble::AnimationProgressed( 154 void FullscreenExitBubbleViews::AnimationProgressed(
174 const ui::Animation* animation) { 155 const ui::Animation* animation) {
175 gfx::Rect popup_rect(GetPopupRect(false)); 156 gfx::Rect popup_rect(GetPopupRect(false));
176 if (popup_rect.IsEmpty()) { 157 if (popup_rect.IsEmpty()) {
177 popup_->Hide(); 158 popup_->Hide();
178 } else { 159 } else {
179 popup_->SetBounds(popup_rect); 160 popup_->SetBounds(popup_rect);
180 popup_->Show(); 161 popup_->Show();
181 } 162 }
182 } 163 }
183 void FullscreenExitBubble::AnimationEnded( 164 void FullscreenExitBubbleViews::AnimationEnded(
184 const ui::Animation* animation) { 165 const ui::Animation* animation) {
185 AnimationProgressed(animation); 166 AnimationProgressed(animation);
186 } 167 }
187 168
188 void FullscreenExitBubble::CheckMousePosition() { 169 void FullscreenExitBubbleViews::Hide() {
189 // Desired behavior: 170 size_animation_->SetSlideDuration(kSlideOutDurationMs);
190 // 171 size_animation_->Hide();
191 // +------------+-----------------------------+------------+ 172 }
192 // | _ _ _ _ | Exit full screen mode (F11) | _ _ _ _ | Slide-in region
193 // | _ _ _ _ \_____________________________/ _ _ _ _ | Neutral region
194 // | | Slide-out region
195 // : :
196 //
197 // * If app is not active, we hide the popup.
198 // * If the mouse is offscreen or in the slide-out region, we hide the popup.
199 // * If the mouse goes idle, we hide the popup.
200 // * If the mouse is in the slide-in-region and not idle, we show the popup.
201 // * If the mouse is in the neutral region and not idle, and the popup is
202 // currently sliding out, we show it again. This facilitates users
203 // correcting us if they try to mouse horizontally towards the popup and
204 // unintentionally drop too low.
205 // * Otherwise, we do nothing, because the mouse is in the neutral region and
206 // either the popup is hidden or the mouse is not idle, so we don't want to
207 // change anything's state.
208 173
174 void FullscreenExitBubbleViews::Show() {
175 size_animation_->SetSlideDuration(kSlideInDurationMs);
176 size_animation_->Show();
177 }
178
179 bool FullscreenExitBubbleViews::IsAnimating() {
180 return size_animation_->GetCurrentValue() != 0;
181 }
182
183 bool FullscreenExitBubbleViews::IsWindowActive() {
184 return root_view_->GetWidget()->IsActive();
185 }
186
187 bool FullscreenExitBubbleViews::WindowContainsPoint(gfx::Point pos) {
188 return root_view_->HitTest(pos);
189 }
190
191 gfx::Point FullscreenExitBubbleViews::GetCursorScreenPoint() {
209 gfx::Point cursor_pos = gfx::Screen::GetCursorScreenPoint(); 192 gfx::Point cursor_pos = gfx::Screen::GetCursorScreenPoint();
210 gfx::Point transformed_pos(cursor_pos); 193 gfx::Point transformed_pos(cursor_pos);
211 views::View::ConvertPointToView(NULL, root_view_, &transformed_pos); 194 views::View::ConvertPointToView(NULL, root_view_, &transformed_pos);
212 195 return transformed_pos;
213 // Check to see whether the mouse is idle.
214 if (transformed_pos != last_mouse_pos_) {
215 // The mouse moved; reset the idle timer.
216 idle_timeout_.Stop(); // If the timer isn't running, this is a no-op.
217 idle_timeout_.Start(base::TimeDelta::FromMilliseconds(kIdleTimeMs), this,
218 &FullscreenExitBubble::CheckMousePosition);
219 }
220 last_mouse_pos_ = transformed_pos;
221
222 if ((!root_view_->GetWidget()->IsActive()) ||
223 !root_view_->HitTest(transformed_pos) ||
224 (cursor_pos.y() >= GetPopupRect(true).bottom()) ||
225 !idle_timeout_.IsRunning()) {
226 // The cursor is offscreen, in the slide-out region, or idle.
227 Hide();
228 } else if ((cursor_pos.y() < kSlideInRegionHeightPx) ||
229 (size_animation_->GetCurrentValue() != 0)) {
230 // The cursor is not idle, and either it's in the slide-in region or it's in
231 // the neutral region and we're sliding out.
232 size_animation_->SetSlideDuration(kSlideInDurationMs);
233 size_animation_->Show();
234 }
235 } 196 }
236 197
237 void FullscreenExitBubble::Hide() { 198 gfx::Rect FullscreenExitBubbleViews::GetPopupRect(
238 // Allow the bubble to hide if the window is deactivated or our initial delay
239 // finishes.
240 if ((!root_view_->GetWidget()->IsActive()) || !initial_delay_.IsRunning()) {
241 size_animation_->SetSlideDuration(kSlideOutDurationMs);
242 size_animation_->Hide();
243 }
244 }
245
246 gfx::Rect FullscreenExitBubble::GetPopupRect(
247 bool ignore_animation_state) const { 199 bool ignore_animation_state) const {
248 gfx::Size size(view_->GetPreferredSize()); 200 gfx::Size size(view_->GetPreferredSize());
249 if (!ignore_animation_state) { 201 if (!ignore_animation_state) {
250 size.set_height(static_cast<int>(static_cast<double>(size.height()) * 202 size.set_height(static_cast<int>(static_cast<double>(size.height()) *
251 size_animation_->GetCurrentValue())); 203 size_animation_->GetCurrentValue()));
252 } 204 }
253 // NOTE: don't use the bounds of the root_view_. On linux changing window 205 // NOTE: don't use the bounds of the root_view_. On linux changing window
254 // size is async. Instead we use the size of the screen. 206 // size is async. Instead we use the size of the screen.
255 gfx::Rect screen_bounds = gfx::Screen::GetMonitorAreaNearestWindow( 207 gfx::Rect screen_bounds = gfx::Screen::GetMonitorAreaNearestWindow(
256 root_view_->GetWidget()->GetNativeView()); 208 root_view_->GetWidget()->GetNativeView());
257 gfx::Point origin(screen_bounds.x() + 209 gfx::Point origin(screen_bounds.x() +
258 (screen_bounds.width() - size.width()) / 2, 210 (screen_bounds.width() - size.width()) / 2,
259 screen_bounds.y()); 211 screen_bounds.y());
260 return gfx::Rect(origin, size); 212 return gfx::Rect(origin, size);
261 } 213 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/fullscreen_exit_bubble_views.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698