OLD | NEW |
| (Empty) |
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/common/frame/custom_frame_view_ash.h" | |
6 | |
7 #include <algorithm> | |
8 #include <vector> | |
9 | |
10 #include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h
" | |
11 #include "ash/common/frame/frame_border_hit_test.h" | |
12 #include "ash/common/frame/header_view.h" | |
13 #include "ash/common/wm/window_state.h" | |
14 #include "ash/common/wm/window_state_delegate.h" | |
15 #include "ash/common/wm/window_state_observer.h" | |
16 #include "ash/common/wm_shell.h" | |
17 #include "ash/common/wm_window.h" | |
18 #include "ash/shared/immersive_fullscreen_controller.h" | |
19 #include "ash/shared/immersive_fullscreen_controller_delegate.h" | |
20 #include "ui/aura/client/aura_constants.h" | |
21 #include "ui/aura/window.h" | |
22 #include "ui/aura/window_observer.h" | |
23 #include "ui/gfx/geometry/rect.h" | |
24 #include "ui/gfx/geometry/rect_conversions.h" | |
25 #include "ui/gfx/geometry/size.h" | |
26 #include "ui/views/view.h" | |
27 #include "ui/views/view_targeter.h" | |
28 #include "ui/views/widget/widget.h" | |
29 #include "ui/views/widget/widget_delegate.h" | |
30 | |
31 namespace ash { | |
32 | |
33 namespace { | |
34 | |
35 /////////////////////////////////////////////////////////////////////////////// | |
36 // CustomFrameViewAshWindowStateDelegate | |
37 | |
38 // Handles a user's fullscreen request (Shift+F4/F4). Puts the window into | |
39 // immersive fullscreen if immersive fullscreen is enabled for non-browser | |
40 // windows. | |
41 class CustomFrameViewAshWindowStateDelegate : public wm::WindowStateDelegate, | |
42 public wm::WindowStateObserver, | |
43 public aura::WindowObserver { | |
44 public: | |
45 CustomFrameViewAshWindowStateDelegate(wm::WindowState* window_state, | |
46 CustomFrameViewAsh* custom_frame_view, | |
47 bool enable_immersive) | |
48 : window_state_(nullptr) { | |
49 // Add a window state observer to exit fullscreen properly in case | |
50 // fullscreen is exited without going through | |
51 // WindowState::ToggleFullscreen(). This is the case when exiting | |
52 // immersive fullscreen via the "Restore" window control. | |
53 // TODO(pkotwicz): This is a hack. Remove ASAP. http://crbug.com/319048 | |
54 window_state_ = window_state; | |
55 window_state_->AddObserver(this); | |
56 window_state_->window()->aura_window()->AddObserver(this); | |
57 | |
58 if (!enable_immersive) | |
59 return; | |
60 | |
61 immersive_fullscreen_controller_ = | |
62 WmShell::Get()->CreateImmersiveFullscreenController(); | |
63 if (immersive_fullscreen_controller_) { | |
64 custom_frame_view->InitImmersiveFullscreenControllerForView( | |
65 immersive_fullscreen_controller_.get()); | |
66 } | |
67 } | |
68 ~CustomFrameViewAshWindowStateDelegate() override { | |
69 if (window_state_) { | |
70 window_state_->RemoveObserver(this); | |
71 window_state_->window()->aura_window()->RemoveObserver(this); | |
72 } | |
73 } | |
74 | |
75 private: | |
76 // Overridden from wm::WindowStateDelegate: | |
77 bool ToggleFullscreen(wm::WindowState* window_state) override { | |
78 bool enter_fullscreen = !window_state->IsFullscreen(); | |
79 if (enter_fullscreen) | |
80 window_state_->window()->SetShowState(ui::SHOW_STATE_FULLSCREEN); | |
81 else | |
82 window_state->Restore(); | |
83 if (immersive_fullscreen_controller_) { | |
84 immersive_fullscreen_controller_->SetEnabled( | |
85 ImmersiveFullscreenController::WINDOW_TYPE_OTHER, enter_fullscreen); | |
86 } | |
87 return true; | |
88 } | |
89 // Overridden from aura::WindowObserver: | |
90 void OnWindowDestroying(aura::Window* window) override { | |
91 window_state_->RemoveObserver(this); | |
92 window->RemoveObserver(this); | |
93 window_state_ = nullptr; | |
94 } | |
95 // Overridden from wm::WindowStateObserver: | |
96 void OnPostWindowStateTypeChange(wm::WindowState* window_state, | |
97 wm::WindowStateType old_type) override { | |
98 if (!window_state->IsFullscreen() && !window_state->IsMinimized() && | |
99 immersive_fullscreen_controller_ && | |
100 immersive_fullscreen_controller_->IsEnabled()) { | |
101 immersive_fullscreen_controller_->SetEnabled( | |
102 ImmersiveFullscreenController::WINDOW_TYPE_OTHER, false); | |
103 } | |
104 } | |
105 | |
106 wm::WindowState* window_state_; | |
107 std::unique_ptr<ImmersiveFullscreenController> | |
108 immersive_fullscreen_controller_; | |
109 | |
110 DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshWindowStateDelegate); | |
111 }; | |
112 | |
113 } // namespace | |
114 | |
115 /////////////////////////////////////////////////////////////////////////////// | |
116 // CustomFrameViewAsh::OverlayView | |
117 | |
118 // View which takes up the entire widget and contains the HeaderView. HeaderView | |
119 // is a child of OverlayView to avoid creating a larger texture than necessary | |
120 // when painting the HeaderView to its own layer. | |
121 class CustomFrameViewAsh::OverlayView : public views::View, | |
122 public views::ViewTargeterDelegate { | |
123 public: | |
124 explicit OverlayView(HeaderView* header_view); | |
125 ~OverlayView() override; | |
126 | |
127 // views::View: | |
128 void Layout() override; | |
129 | |
130 private: | |
131 // views::ViewTargeterDelegate: | |
132 bool DoesIntersectRect(const views::View* target, | |
133 const gfx::Rect& rect) const override; | |
134 | |
135 HeaderView* header_view_; | |
136 | |
137 DISALLOW_COPY_AND_ASSIGN(OverlayView); | |
138 }; | |
139 | |
140 CustomFrameViewAsh::OverlayView::OverlayView(HeaderView* header_view) | |
141 : header_view_(header_view) { | |
142 AddChildView(header_view); | |
143 SetEventTargeter( | |
144 std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); | |
145 } | |
146 | |
147 CustomFrameViewAsh::OverlayView::~OverlayView() {} | |
148 | |
149 /////////////////////////////////////////////////////////////////////////////// | |
150 // CustomFrameViewAsh::OverlayView, views::View overrides: | |
151 | |
152 void CustomFrameViewAsh::OverlayView::Layout() { | |
153 // Layout |header_view_| because layout affects the result of | |
154 // GetPreferredOnScreenHeight(). | |
155 header_view_->Layout(); | |
156 | |
157 int onscreen_height = header_view_->GetPreferredOnScreenHeight(); | |
158 if (onscreen_height == 0) { | |
159 header_view_->SetVisible(false); | |
160 } else { | |
161 int height = header_view_->GetPreferredHeight(); | |
162 header_view_->SetBounds(0, onscreen_height - height, width(), height); | |
163 header_view_->SetVisible(true); | |
164 } | |
165 } | |
166 | |
167 /////////////////////////////////////////////////////////////////////////////// | |
168 // CustomFrameViewAsh::OverlayView, views::ViewTargeterDelegate overrides: | |
169 | |
170 bool CustomFrameViewAsh::OverlayView::DoesIntersectRect( | |
171 const views::View* target, | |
172 const gfx::Rect& rect) const { | |
173 CHECK_EQ(target, this); | |
174 // Grab events in the header view. Return false for other events so that they | |
175 // can be handled by the client view. | |
176 return header_view_->HitTestRect(rect); | |
177 } | |
178 | |
179 //////////////////////////////////////////////////////////////////////////////// | |
180 // CustomFrameViewAsh, public: | |
181 | |
182 // static | |
183 const char CustomFrameViewAsh::kViewClassName[] = "CustomFrameViewAsh"; | |
184 | |
185 CustomFrameViewAsh::CustomFrameViewAsh( | |
186 views::Widget* frame, | |
187 ImmersiveFullscreenControllerDelegate* immersive_delegate, | |
188 bool enable_immersive) | |
189 : frame_(frame), | |
190 header_view_(new HeaderView(frame)), | |
191 immersive_delegate_(immersive_delegate ? immersive_delegate | |
192 : header_view_) { | |
193 WmWindow* frame_window = WmWindow::Get(frame->GetNativeWindow()); | |
194 frame_window->InstallResizeHandleWindowTargeter(nullptr); | |
195 // |header_view_| is set as the non client view's overlay view so that it can | |
196 // overlay the web contents in immersive fullscreen. | |
197 frame->non_client_view()->SetOverlayView(new OverlayView(header_view_)); | |
198 frame_window->aura_window()->SetProperty( | |
199 aura::client::kTopViewColor, header_view_->GetInactiveFrameColor()); | |
200 | |
201 // A delegate for a more complex way of fullscreening the window may already | |
202 // be set. This is the case for packaged apps. | |
203 wm::WindowState* window_state = frame_window->GetWindowState(); | |
204 if (!window_state->HasDelegate()) { | |
205 window_state->SetDelegate(std::unique_ptr<wm::WindowStateDelegate>( | |
206 new CustomFrameViewAshWindowStateDelegate(window_state, this, | |
207 enable_immersive))); | |
208 } | |
209 } | |
210 | |
211 CustomFrameViewAsh::~CustomFrameViewAsh() {} | |
212 | |
213 void CustomFrameViewAsh::InitImmersiveFullscreenControllerForView( | |
214 ImmersiveFullscreenController* immersive_fullscreen_controller) { | |
215 immersive_fullscreen_controller->Init(immersive_delegate_, frame_, | |
216 header_view_); | |
217 } | |
218 | |
219 void CustomFrameViewAsh::SetFrameColors(SkColor active_frame_color, | |
220 SkColor inactive_frame_color) { | |
221 header_view_->SetFrameColors(active_frame_color, inactive_frame_color); | |
222 WmWindow* frame_window = WmWindow::Get(frame_->GetNativeWindow()); | |
223 frame_window->aura_window()->SetProperty( | |
224 aura::client::kTopViewColor, header_view_->GetInactiveFrameColor()); | |
225 } | |
226 | |
227 //////////////////////////////////////////////////////////////////////////////// | |
228 // CustomFrameViewAsh, views::NonClientFrameView overrides: | |
229 | |
230 gfx::Rect CustomFrameViewAsh::GetBoundsForClientView() const { | |
231 gfx::Rect client_bounds = bounds(); | |
232 client_bounds.Inset(0, NonClientTopBorderHeight(), 0, 0); | |
233 return client_bounds; | |
234 } | |
235 | |
236 gfx::Rect CustomFrameViewAsh::GetWindowBoundsForClientBounds( | |
237 const gfx::Rect& client_bounds) const { | |
238 gfx::Rect window_bounds = client_bounds; | |
239 window_bounds.Inset(0, -NonClientTopBorderHeight(), 0, 0); | |
240 return window_bounds; | |
241 } | |
242 | |
243 int CustomFrameViewAsh::NonClientHitTest(const gfx::Point& point) { | |
244 return FrameBorderNonClientHitTest( | |
245 this, header_view_->caption_button_container(), point); | |
246 } | |
247 | |
248 void CustomFrameViewAsh::GetWindowMask(const gfx::Size& size, | |
249 gfx::Path* window_mask) { | |
250 // No window masks in Aura. | |
251 } | |
252 | |
253 void CustomFrameViewAsh::ResetWindowControls() { | |
254 header_view_->ResetWindowControls(); | |
255 } | |
256 | |
257 void CustomFrameViewAsh::UpdateWindowIcon() {} | |
258 | |
259 void CustomFrameViewAsh::UpdateWindowTitle() { | |
260 header_view_->SchedulePaintForTitle(); | |
261 } | |
262 | |
263 void CustomFrameViewAsh::SizeConstraintsChanged() { | |
264 header_view_->SizeConstraintsChanged(); | |
265 } | |
266 | |
267 void CustomFrameViewAsh::ActivationChanged(bool active) { | |
268 // The icons differ between active and inactive. | |
269 header_view_->SchedulePaint(); | |
270 } | |
271 | |
272 //////////////////////////////////////////////////////////////////////////////// | |
273 // CustomFrameViewAsh, views::View overrides: | |
274 | |
275 gfx::Size CustomFrameViewAsh::GetPreferredSize() const { | |
276 gfx::Size pref = frame_->client_view()->GetPreferredSize(); | |
277 gfx::Rect bounds(0, 0, pref.width(), pref.height()); | |
278 return frame_->non_client_view() | |
279 ->GetWindowBoundsForClientBounds(bounds) | |
280 .size(); | |
281 } | |
282 | |
283 void CustomFrameViewAsh::Layout() { | |
284 views::NonClientFrameView::Layout(); | |
285 WmWindow* frame_window = WmWindow::Get(frame_->GetNativeWindow()); | |
286 frame_window->aura_window()->SetProperty(aura::client::kTopViewInset, | |
287 NonClientTopBorderHeight()); | |
288 } | |
289 | |
290 const char* CustomFrameViewAsh::GetClassName() const { | |
291 return kViewClassName; | |
292 } | |
293 | |
294 gfx::Size CustomFrameViewAsh::GetMinimumSize() const { | |
295 gfx::Size min_client_view_size(frame_->client_view()->GetMinimumSize()); | |
296 return gfx::Size( | |
297 std::max(header_view_->GetMinimumWidth(), min_client_view_size.width()), | |
298 NonClientTopBorderHeight() + min_client_view_size.height()); | |
299 } | |
300 | |
301 gfx::Size CustomFrameViewAsh::GetMaximumSize() const { | |
302 gfx::Size max_client_size(frame_->client_view()->GetMaximumSize()); | |
303 int width = 0; | |
304 int height = 0; | |
305 | |
306 if (max_client_size.width() > 0) | |
307 width = std::max(header_view_->GetMinimumWidth(), max_client_size.width()); | |
308 if (max_client_size.height() > 0) | |
309 height = NonClientTopBorderHeight() + max_client_size.height(); | |
310 | |
311 return gfx::Size(width, height); | |
312 } | |
313 | |
314 void CustomFrameViewAsh::SchedulePaintInRect(const gfx::Rect& r) { | |
315 // We may end up here before |header_view_| has been added to the Widget. | |
316 if (header_view_->GetWidget()) { | |
317 // The HeaderView is not a child of CustomFrameViewAsh. Redirect the paint | |
318 // to HeaderView instead. | |
319 gfx::RectF to_paint(r); | |
320 views::View::ConvertRectToTarget(this, header_view_, &to_paint); | |
321 header_view_->SchedulePaintInRect(gfx::ToEnclosingRect(to_paint)); | |
322 } else { | |
323 views::NonClientFrameView::SchedulePaintInRect(r); | |
324 } | |
325 } | |
326 | |
327 void CustomFrameViewAsh::VisibilityChanged(views::View* starting_from, | |
328 bool is_visible) { | |
329 if (is_visible) | |
330 header_view_->UpdateAvatarIcon(); | |
331 } | |
332 | |
333 views::View* CustomFrameViewAsh::GetHeaderView() { | |
334 return header_view_; | |
335 } | |
336 | |
337 const views::View* CustomFrameViewAsh::GetAvatarIconViewForTest() const { | |
338 return header_view_->avatar_icon(); | |
339 } | |
340 | |
341 //////////////////////////////////////////////////////////////////////////////// | |
342 // CustomFrameViewAsh, private: | |
343 | |
344 // views::NonClientFrameView: | |
345 bool CustomFrameViewAsh::DoesIntersectRect(const views::View* target, | |
346 const gfx::Rect& rect) const { | |
347 CHECK_EQ(target, this); | |
348 // NonClientView hit tests the NonClientFrameView first instead of going in | |
349 // z-order. Return false so that events get to the OverlayView. | |
350 return false; | |
351 } | |
352 | |
353 FrameCaptionButtonContainerView* | |
354 CustomFrameViewAsh::GetFrameCaptionButtonContainerViewForTest() { | |
355 return header_view_->caption_button_container(); | |
356 } | |
357 | |
358 int CustomFrameViewAsh::NonClientTopBorderHeight() const { | |
359 return frame_->IsFullscreen() ? 0 : header_view_->GetPreferredHeight(); | |
360 } | |
361 | |
362 } // namespace ash | |
OLD | NEW |