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

Side by Side Diff: chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc

Issue 947343003: Split out Ash/Aura parts of ChromeNativeAppWindowViews. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Ready for review. Created 5 years, 10 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
OLDNEW
(Empty)
1 // Copyright 2015 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/ui/views/apps/chrome_native_app_window_views_aura.h"
6
7 #include "apps/ui/views/app_window_frame_view.h"
8 #include "ash/ash_constants.h"
9 #include "ash/frame/custom_frame_view_ash.h"
10 #include "ash/screen_util.h"
11 #include "ash/shell.h"
12 #include "ash/wm/immersive_fullscreen_controller.h"
13 #include "ash/wm/panels/panel_frame_view.h"
14 #include "ash/wm/window_properties.h"
15 #include "ash/wm/window_state.h"
16 #include "ash/wm/window_state_delegate.h"
17 #include "ash/wm/window_state_observer.h"
18 #include "chrome/browser/ui/ash/ash_util.h"
19 #include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h"
20 #include "chrome/browser/ui/host_desktop.h"
21 #include "chrome/browser/ui/views/apps/shaped_app_window_targeter.h"
22 #include "ui/aura/client/aura_constants.h"
23 #include "ui/aura/window.h"
24 #include "ui/aura/window_observer.h"
25 #include "ui/base/hit_test.h"
26 #include "ui/base/models/simple_menu_model.h"
27 #include "ui/gfx/image/image_skia.h"
28 #include "ui/views/controls/menu/menu_runner.h"
29 #include "ui/views/widget/widget.h"
30 #include "ui/wm/core/easy_resize_window_targeter.h"
31
32 #if defined(OS_CHROMEOS)
33 #include "ash/shell_window_ids.h"
34 #endif
35
36 using extensions::AppWindow;
37
38 namespace {
39
40 // This class handles a user's fullscreen request (Shift+F4/F4).
41 class NativeAppWindowStateDelegate : public ash::wm::WindowStateDelegate,
42 public ash::wm::WindowStateObserver,
43 public aura::WindowObserver {
44 public:
45 NativeAppWindowStateDelegate(AppWindow* app_window,
46 extensions::NativeAppWindow* native_app_window)
47 : app_window_(app_window),
48 window_state_(
49 ash::wm::GetWindowState(native_app_window->GetNativeWindow())) {
50 // Add a window state observer to exit fullscreen properly in case
51 // fullscreen is exited without going through AppWindow::Restore(). This
52 // is the case when exiting immersive fullscreen via the "Restore" window
53 // control.
54 // TODO(pkotwicz): This is a hack. Remove ASAP. http://crbug.com/319048
55 window_state_->AddObserver(this);
56 window_state_->window()->AddObserver(this);
57 }
58 ~NativeAppWindowStateDelegate() override {
59 if (window_state_) {
60 window_state_->RemoveObserver(this);
61 window_state_->window()->RemoveObserver(this);
62 }
63 }
64
65 private:
66 // Overridden from ash::wm::WindowStateDelegate.
67 bool ToggleFullscreen(ash::wm::WindowState* window_state) override {
68 // Windows which cannot be maximized should not be fullscreened.
69 DCHECK(window_state->IsFullscreen() || window_state->CanMaximize());
70 if (window_state->IsFullscreen())
71 app_window_->Restore();
72 else if (window_state->CanMaximize())
73 app_window_->OSFullscreen();
74 return true;
75 }
76
77 // Overridden from ash::wm::WindowStateObserver:
78 void OnPostWindowStateTypeChange(ash::wm::WindowState* window_state,
79 ash::wm::WindowStateType old_type) override {
80 // Since the window state might get set by a window manager, it is possible
81 // to come here before the application set its |BaseWindow|.
82 if (!window_state->IsFullscreen() && !window_state->IsMinimized() &&
83 app_window_->GetBaseWindow() &&
84 app_window_->GetBaseWindow()->IsFullscreenOrPending()) {
85 app_window_->Restore();
86 // Usually OnNativeWindowChanged() is called when the window bounds are
87 // changed as a result of a state type change. Because the change in state
88 // type has already occurred, we need to call OnNativeWindowChanged()
89 // explicitly.
90 app_window_->OnNativeWindowChanged();
91 }
92 }
93
94 // Overridden from aura::WindowObserver:
95 void OnWindowDestroying(aura::Window* window) override {
96 window_state_->RemoveObserver(this);
97 window_state_->window()->RemoveObserver(this);
98 window_state_ = NULL;
99 }
100
101 // Not owned.
102 AppWindow* app_window_;
103 ash::wm::WindowState* window_state_;
104
105 DISALLOW_COPY_AND_ASSIGN(NativeAppWindowStateDelegate);
106 };
107
108 } // namespace
109
110 ChromeNativeAppWindowViewsAura::ChromeNativeAppWindowViewsAura() {
111 }
112
113 ChromeNativeAppWindowViewsAura::~ChromeNativeAppWindowViewsAura() {
114 }
115
116 gfx::NativeView ChromeNativeAppWindowViewsAura::GetImeWindowContainer() {
117 #if defined(OS_CHROMEOS)
118 return ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
119 ash::kShellWindowId_ImeWindowParentContainer);
120 #else
121 return ChromeNativeAppWindowViews::GetImeWindowContainer();
122 #endif
123 }
124
125 gfx::Rect ChromeNativeAppWindowViewsAura::GetPanelWindowInitialBounds(
126 gfx::Size preferred_size_) {
127 if (ash::Shell::HasInstance()) {
128 // Open a new panel on the target root.
129 return ash::ScreenUtil::ConvertRectToScreen(
130 ash::Shell::GetTargetRootWindow(), gfx::Rect(preferred_size_));
131 }
132
133 return gfx::Rect(preferred_size_);
134 }
135
136 apps::AppWindowFrameView*
137 ChromeNativeAppWindowViewsAura::CreateNonStandardAppFrame() {
138 apps::AppWindowFrameView* frame =
139 ChromeNativeAppWindowViews::CreateNonStandardAppFrame();
tapted 2015/02/25 05:54:35 It might be nicer to have something like void OnA
140
141 // For Aura windows on the Ash desktop the sizes are different and the user
142 // can resize the window from slightly outside the bounds as well.
143 if (chrome::IsNativeWindowInAsh(widget()->GetNativeWindow())) {
144 frame->SetResizeSizes(ash::kResizeInsideBoundsSize,
145 ash::kResizeOutsideBoundsSize,
146 ash::kResizeAreaCornerSize);
147 }
148
149 #if !defined(OS_CHROMEOS)
150 // For non-Ash windows, install an easy resize window targeter, which ensures
151 // that the root window (not the app) receives mouse events on the edges.
152 if (chrome::GetHostDesktopTypeForNativeWindow(widget()->GetNativeWindow()) !=
153 chrome::HOST_DESKTOP_TYPE_ASH) {
154 aura::Window* window = widget()->GetNativeWindow();
155 int resize_inside = frame->resize_inside_bounds_size();
156 gfx::Insets inset(resize_inside, resize_inside, resize_inside,
157 resize_inside);
158 // Add the EasyResizeWindowTargeter on the window, not its root window. The
159 // root window does not have a delegate, which is needed to handle the event
160 // in Linux.
161 window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
162 new wm::EasyResizeWindowTargeter(window, inset, inset)));
163 }
164 #endif
165
166 return frame;
167 }
168
169 gfx::Rect ChromeNativeAppWindowViewsAura::GetRestoredBounds() const {
170 gfx::Rect* bounds =
171 widget()->GetNativeWindow()->GetProperty(ash::kRestoreBoundsOverrideKey);
172 if (bounds && !bounds->IsEmpty())
173 return *bounds;
174
175 return ChromeNativeAppWindowViews::GetRestoredBounds();
176 }
177
178 ui::WindowShowState ChromeNativeAppWindowViewsAura::GetRestoredState() const {
179 // Use kRestoreShowStateKey in case a window is minimized/hidden.
180 ui::WindowShowState restore_state = widget()->GetNativeWindow()->GetProperty(
181 aura::client::kRestoreShowStateKey);
182 if (widget()->GetNativeWindow()->GetProperty(
183 ash::kRestoreBoundsOverrideKey)) {
184 // If an override is given, we use that restore state (after filtering).
185 restore_state = widget()->GetNativeWindow()->GetProperty(
186 ash::kRestoreShowStateOverrideKey);
187 } else {
188 // Otherwise first normal states are checked.
189 if (IsMaximized())
190 return ui::SHOW_STATE_MAXIMIZED;
191 if (IsFullscreen()) {
192 if (immersive_fullscreen_controller_.get() &&
193 immersive_fullscreen_controller_->IsEnabled()) {
194 // Restore windows which were previously in immersive fullscreen to
195 // maximized. Restoring the window to a different fullscreen type
196 // makes for a bad experience.
197 return ui::SHOW_STATE_MAXIMIZED;
198 }
199 return ui::SHOW_STATE_FULLSCREEN;
200 }
201 }
202 // Whitelist states to return so that invalid and transient states
203 // are not saved and used to restore windows when they are recreated.
204 switch (restore_state) {
205 case ui::SHOW_STATE_NORMAL:
206 case ui::SHOW_STATE_MAXIMIZED:
207 case ui::SHOW_STATE_FULLSCREEN:
208 return restore_state;
209
210 case ui::SHOW_STATE_DEFAULT:
211 case ui::SHOW_STATE_MINIMIZED:
212 case ui::SHOW_STATE_INACTIVE:
213 case ui::SHOW_STATE_END:
214 return ui::SHOW_STATE_NORMAL;
215 }
216
217 return ui::SHOW_STATE_NORMAL;
218 }
219
220 bool ChromeNativeAppWindowViewsAura::IsAlwaysOnTop() const {
221 if (app_window()->window_type_is_panel()) {
222 return ash::wm::GetWindowState(widget()->GetNativeWindow())
223 ->panel_attached();
224 } else {
tapted 2015/02/25 05:54:35 nit: "no else after return" perhaps ternary-if-el
jackhou1 2015/02/25 22:57:51 Done.
225 return widget()->IsAlwaysOnTop();
226 }
227 }
228
229 void ChromeNativeAppWindowViewsAura::ShowContextMenuForView(
230 views::View* source,
231 const gfx::Point& p,
232 ui::MenuSourceType source_type) {
233 #if defined(OS_CHROMEOS)
234 scoped_ptr<ui::MenuModel> model =
235 CreateMultiUserContextMenu(app_window()->GetNativeWindow());
236 if (!model.get())
237 return;
238
239 // Only show context menu if point is in caption.
240 gfx::Point point_in_view_coords(p);
241 views::View::ConvertPointFromScreen(widget()->non_client_view(),
242 &point_in_view_coords);
243 int hit_test =
244 widget()->non_client_view()->NonClientHitTest(point_in_view_coords);
245 if (hit_test == HTCAPTION) {
246 menu_runner_.reset(new views::MenuRunner(
247 model.get(),
248 views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
249 if (menu_runner_->RunMenuAt(source->GetWidget(), NULL,
250 gfx::Rect(p, gfx::Size(0, 0)),
251 views::MENU_ANCHOR_TOPLEFT, source_type) ==
252 views::MenuRunner::MENU_DELETED) {
253 return;
254 }
255 }
256 #endif
257 }
258
259 views::NonClientFrameView*
260 ChromeNativeAppWindowViewsAura::CreateNonClientFrameView(
261 views::Widget* widget) {
262 if (chrome::IsNativeViewInAsh(widget->GetNativeView())) {
263 // Set the delegate now because CustomFrameViewAsh sets the
264 // WindowStateDelegate if one is not already set.
265 ash::wm::GetWindowState(GetNativeWindow())
266 ->SetDelegate(
267 scoped_ptr<ash::wm::WindowStateDelegate>(
268 new NativeAppWindowStateDelegate(app_window(), this)).Pass());
269
270 if (IsFrameless())
271 return CreateNonStandardAppFrame();
272
273 if (app_window()->window_type_is_panel()) {
274 views::NonClientFrameView* frame_view =
275 new ash::PanelFrameView(widget, ash::PanelFrameView::FRAME_ASH);
276 frame_view->set_context_menu_controller(this);
277 return frame_view;
278 }
279
280 ash::CustomFrameViewAsh* custom_frame_view =
281 new ash::CustomFrameViewAsh(widget);
282 // Non-frameless app windows can be put into immersive fullscreen.
283 immersive_fullscreen_controller_.reset(
284 new ash::ImmersiveFullscreenController());
285 custom_frame_view->InitImmersiveFullscreenControllerForView(
286 immersive_fullscreen_controller_.get());
287 custom_frame_view->GetHeaderView()->set_context_menu_controller(this);
288
289 if (HasFrameColor()) {
290 custom_frame_view->SetFrameColors(ActiveFrameColor(),
291 InactiveFrameColor());
292 }
293
294 return custom_frame_view;
295 }
296
297 return ChromeNativeAppWindowViews::CreateNonClientFrameView(widget);
298 }
299
300 void ChromeNativeAppWindowViewsAura::SetFullscreen(int fullscreen_types) {
301 ChromeNativeAppWindowViews::SetFullscreen(fullscreen_types);
302
303 if (immersive_fullscreen_controller_.get()) {
304 // |immersive_fullscreen_controller_| should only be set if immersive
305 // fullscreen is the fullscreen type used by the OS.
306 immersive_fullscreen_controller_->SetEnabled(
307 ash::ImmersiveFullscreenController::WINDOW_TYPE_PACKAGED_APP,
308 (fullscreen_types & AppWindow::FULLSCREEN_TYPE_OS) != 0);
309 // Autohide the shelf instead of hiding the shelf completely when only in
310 // OS fullscreen.
311 ash::wm::WindowState* window_state =
312 ash::wm::GetWindowState(widget()->GetNativeWindow());
313 window_state->set_hide_shelf_when_fullscreen(fullscreen_types !=
314 AppWindow::FULLSCREEN_TYPE_OS);
315 DCHECK(ash::Shell::HasInstance());
316 ash::Shell::GetInstance()->UpdateShelfVisibility();
317 }
318 }
319
320 void ChromeNativeAppWindowViewsAura::UpdateShape(scoped_ptr<SkRegion> region) {
321 bool had_shape = shape() != nullptr;
322
323 ChromeNativeAppWindowViews::UpdateShape(region.Pass());
324
325 aura::Window* native_window = widget()->GetNativeWindow();
326 if (shape()) {
327 widget()->SetShape(new SkRegion(*shape()));
tapted 2015/02/25 05:54:35 these Widget::SetShape calls should be in the supe
jackhou1 2015/02/25 22:57:52 I don't think adding OnShapeChanged makes a big di
jackhou1 2015/02/25 22:57:52 Looks like it does. On Linux setting and unsetting
328 if (!had_shape) {
329 native_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
330 new ShapedAppWindowTargeter(native_window, this)));
331 }
332 } else {
333 widget()->SetShape(nullptr);
334 if (had_shape)
335 native_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>());
336 }
337 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698