BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / ui / views / apps / chrome_native_app_window_views.cc
blobbd6baf262e3a915b7f9556798d4b7222a81ba334
1 // Copyright 2014 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.
5 #include "chrome/browser/ui/views/apps/chrome_native_app_window_views.h"
7 #include "apps/ui/views/app_window_frame_view.h"
8 #include "chrome/app/chrome_command_ids.h"
9 #include "chrome/browser/app_mode/app_mode_utils.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h"
12 #include "chrome/browser/ui/views/frame/taskbar_decorator.h"
13 #include "components/favicon/content/content_favicon_driver.h"
14 #include "components/ui/zoom/page_zoom.h"
15 #include "components/ui/zoom/zoom_controller.h"
16 #include "ui/views/controls/webview/webview.h"
17 #include "ui/views/widget/widget.h"
19 using extensions::AppWindow;
21 namespace {
23 const int kMinPanelWidth = 100;
24 const int kMinPanelHeight = 100;
25 const int kDefaultPanelWidth = 200;
26 const int kDefaultPanelHeight = 300;
28 struct AcceleratorMapping {
29 ui::KeyboardCode keycode;
30 int modifiers;
31 int command_id;
34 const AcceleratorMapping kAppWindowAcceleratorMap[] = {
35 { ui::VKEY_W, ui::EF_CONTROL_DOWN, IDC_CLOSE_WINDOW },
36 { ui::VKEY_W, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, IDC_CLOSE_WINDOW },
37 { ui::VKEY_F4, ui::EF_ALT_DOWN, IDC_CLOSE_WINDOW },
40 // These accelerators will only be available in kiosk mode. These allow the
41 // user to manually zoom app windows. This is only necessary in kiosk mode
42 // (in normal mode, the user can zoom via the screen magnifier).
43 // TODO(xiyuan): Write a test for kiosk accelerators.
44 const AcceleratorMapping kAppWindowKioskAppModeAcceleratorMap[] = {
45 { ui::VKEY_OEM_MINUS, ui::EF_CONTROL_DOWN, IDC_ZOOM_MINUS },
46 { ui::VKEY_OEM_MINUS, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
47 IDC_ZOOM_MINUS },
48 { ui::VKEY_SUBTRACT, ui::EF_CONTROL_DOWN, IDC_ZOOM_MINUS },
49 { ui::VKEY_OEM_PLUS, ui::EF_CONTROL_DOWN, IDC_ZOOM_PLUS },
50 { ui::VKEY_OEM_PLUS, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, IDC_ZOOM_PLUS },
51 { ui::VKEY_ADD, ui::EF_CONTROL_DOWN, IDC_ZOOM_PLUS },
52 { ui::VKEY_0, ui::EF_CONTROL_DOWN, IDC_ZOOM_NORMAL },
53 { ui::VKEY_NUMPAD0, ui::EF_CONTROL_DOWN, IDC_ZOOM_NORMAL },
56 void AddAcceleratorsFromMapping(const AcceleratorMapping mapping[],
57 size_t mapping_length,
58 std::map<ui::Accelerator, int>* accelerators) {
59 for (size_t i = 0; i < mapping_length; ++i) {
60 ui::Accelerator accelerator(mapping[i].keycode, mapping[i].modifiers);
61 (*accelerators)[accelerator] = mapping[i].command_id;
65 const std::map<ui::Accelerator, int>& GetAcceleratorTable() {
66 typedef std::map<ui::Accelerator, int> AcceleratorMap;
67 CR_DEFINE_STATIC_LOCAL(AcceleratorMap, accelerators, ());
68 if (!chrome::IsRunningInForcedAppMode()) {
69 if (accelerators.empty()) {
70 AddAcceleratorsFromMapping(
71 kAppWindowAcceleratorMap,
72 arraysize(kAppWindowAcceleratorMap),
73 &accelerators);
75 return accelerators;
78 CR_DEFINE_STATIC_LOCAL(AcceleratorMap, app_mode_accelerators, ());
79 if (app_mode_accelerators.empty()) {
80 AddAcceleratorsFromMapping(
81 kAppWindowAcceleratorMap,
82 arraysize(kAppWindowAcceleratorMap),
83 &app_mode_accelerators);
84 AddAcceleratorsFromMapping(
85 kAppWindowKioskAppModeAcceleratorMap,
86 arraysize(kAppWindowKioskAppModeAcceleratorMap),
87 &app_mode_accelerators);
89 return app_mode_accelerators;
92 } // namespace
94 ChromeNativeAppWindowViews::ChromeNativeAppWindowViews()
95 : has_frame_color_(false),
96 active_frame_color_(SK_ColorBLACK),
97 inactive_frame_color_(SK_ColorBLACK) {
100 ChromeNativeAppWindowViews::~ChromeNativeAppWindowViews() {}
102 void ChromeNativeAppWindowViews::OnBeforeWidgetInit(
103 const AppWindow::CreateParams& create_params,
104 views::Widget::InitParams* init_params,
105 views::Widget* widget) {
108 void ChromeNativeAppWindowViews::OnBeforePanelWidgetInit(
109 bool use_default_bounds,
110 views::Widget::InitParams* init_params,
111 views::Widget* widget) {
114 void ChromeNativeAppWindowViews::InitializeDefaultWindow(
115 const AppWindow::CreateParams& create_params) {
116 views::Widget::InitParams init_params(views::Widget::InitParams::TYPE_WINDOW);
117 init_params.delegate = this;
118 init_params.remove_standard_frame = IsFrameless() || has_frame_color_;
119 init_params.use_system_default_icon = true;
120 if (create_params.alpha_enabled) {
121 init_params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
123 // The given window is most likely not rectangular since it uses
124 // transparency and has no standard frame, don't show a shadow for it.
125 // TODO(skuhne): If we run into an application which should have a shadow
126 // but does not have, a new attribute has to be added.
127 if (IsFrameless())
128 init_params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
130 init_params.keep_on_top = create_params.always_on_top;
131 init_params.visible_on_all_workspaces =
132 create_params.visible_on_all_workspaces;
134 OnBeforeWidgetInit(create_params, &init_params, widget());
135 widget()->Init(init_params);
137 // The frame insets are required to resolve the bounds specifications
138 // correctly. So we set the window bounds and constraints now.
139 gfx::Insets frame_insets = GetFrameInsets();
140 gfx::Rect window_bounds = create_params.GetInitialWindowBounds(frame_insets);
141 SetContentSizeConstraints(create_params.GetContentMinimumSize(frame_insets),
142 create_params.GetContentMaximumSize(frame_insets));
143 if (!window_bounds.IsEmpty()) {
144 using BoundsSpecification = AppWindow::BoundsSpecification;
145 bool position_specified =
146 window_bounds.x() != BoundsSpecification::kUnspecifiedPosition &&
147 window_bounds.y() != BoundsSpecification::kUnspecifiedPosition;
148 if (!position_specified)
149 widget()->CenterWindow(window_bounds.size());
150 else
151 widget()->SetBounds(window_bounds);
154 #if defined(OS_CHROMEOS)
155 if (create_params.is_ime_window)
156 return;
157 #endif
159 // Register accelarators supported by app windows.
160 // TODO(jeremya/stevenjb): should these be registered for panels too?
161 views::FocusManager* focus_manager = GetFocusManager();
162 const std::map<ui::Accelerator, int>& accelerator_table =
163 GetAcceleratorTable();
164 const bool is_kiosk_app_mode = chrome::IsRunningInForcedAppMode();
166 // Ensures that kiosk mode accelerators are enabled when in kiosk mode (to be
167 // future proof). This is needed because GetAcceleratorTable() uses a static
168 // to store data and only checks kiosk mode once. If a platform app is
169 // launched before kiosk mode starts, the kiosk accelerators will not be
170 // registered. This CHECK catches the case.
171 CHECK(!is_kiosk_app_mode ||
172 accelerator_table.size() ==
173 arraysize(kAppWindowAcceleratorMap) +
174 arraysize(kAppWindowKioskAppModeAcceleratorMap));
176 // Ensure there is a ZoomController in kiosk mode, otherwise the processing
177 // of the accelerators will cause a crash. Note CHECK here because DCHECK
178 // will not be noticed, as this could only be relevant on real hardware.
179 CHECK(!is_kiosk_app_mode ||
180 ui_zoom::ZoomController::FromWebContents(web_view()->GetWebContents()));
182 for (std::map<ui::Accelerator, int>::const_iterator iter =
183 accelerator_table.begin();
184 iter != accelerator_table.end(); ++iter) {
185 if (is_kiosk_app_mode && !chrome::IsCommandAllowedInAppMode(iter->second))
186 continue;
188 focus_manager->RegisterAccelerator(
189 iter->first, ui::AcceleratorManager::kNormalPriority, this);
193 void ChromeNativeAppWindowViews::InitializePanelWindow(
194 const AppWindow::CreateParams& create_params) {
195 views::Widget::InitParams params(views::Widget::InitParams::TYPE_PANEL);
196 params.delegate = this;
198 gfx::Rect initial_window_bounds =
199 create_params.GetInitialWindowBounds(gfx::Insets());
200 preferred_size_ = gfx::Size(initial_window_bounds.width(),
201 initial_window_bounds.height());
202 if (preferred_size_.width() == 0)
203 preferred_size_.set_width(kDefaultPanelWidth);
204 else if (preferred_size_.width() < kMinPanelWidth)
205 preferred_size_.set_width(kMinPanelWidth);
207 if (preferred_size_.height() == 0)
208 preferred_size_.set_height(kDefaultPanelHeight);
209 else if (preferred_size_.height() < kMinPanelHeight)
210 preferred_size_.set_height(kMinPanelHeight);
212 // When a panel is not docked it will be placed at a default origin in the
213 // currently active target root window.
214 bool use_default_bounds = create_params.state != ui::SHOW_STATE_DOCKED;
215 // Sanitize initial origin reseting it in case it was not specified.
216 using BoundsSpecification = AppWindow::BoundsSpecification;
217 bool position_specified =
218 initial_window_bounds.x() != BoundsSpecification::kUnspecifiedPosition &&
219 initial_window_bounds.y() != BoundsSpecification::kUnspecifiedPosition;
220 params.bounds = (use_default_bounds || !position_specified) ?
221 gfx::Rect(preferred_size_) :
222 gfx::Rect(initial_window_bounds.origin(), preferred_size_);
223 OnBeforePanelWidgetInit(use_default_bounds, &params, widget());
224 widget()->Init(params);
225 widget()->set_focus_on_creation(create_params.focused);
228 views::NonClientFrameView*
229 ChromeNativeAppWindowViews::CreateStandardDesktopAppFrame() {
230 return views::WidgetDelegateView::CreateNonClientFrameView(widget());
233 // ui::BaseWindow implementation.
235 gfx::Rect ChromeNativeAppWindowViews::GetRestoredBounds() const {
236 return widget()->GetRestoredBounds();
239 ui::WindowShowState ChromeNativeAppWindowViews::GetRestoredState() const {
240 if (IsMaximized())
241 return ui::SHOW_STATE_MAXIMIZED;
242 if (IsFullscreen())
243 return ui::SHOW_STATE_FULLSCREEN;
245 return ui::SHOW_STATE_NORMAL;
248 bool ChromeNativeAppWindowViews::IsAlwaysOnTop() const {
249 // TODO(jackhou): On Mac, only docked panels are always-on-top.
250 return app_window()->window_type_is_panel() || widget()->IsAlwaysOnTop();
253 // views::WidgetDelegate implementation.
255 gfx::ImageSkia ChromeNativeAppWindowViews::GetWindowAppIcon() {
256 gfx::Image app_icon = app_window()->app_icon();
257 if (app_icon.IsEmpty())
258 return GetWindowIcon();
259 else
260 return *app_icon.ToImageSkia();
263 gfx::ImageSkia ChromeNativeAppWindowViews::GetWindowIcon() {
264 content::WebContents* web_contents = app_window()->web_contents();
265 if (web_contents) {
266 favicon::FaviconDriver* favicon_driver =
267 favicon::ContentFaviconDriver::FromWebContents(web_contents);
268 gfx::Image app_icon = favicon_driver->GetFavicon();
269 if (!app_icon.IsEmpty())
270 return *app_icon.ToImageSkia();
272 return gfx::ImageSkia();
275 views::NonClientFrameView* ChromeNativeAppWindowViews::CreateNonClientFrameView(
276 views::Widget* widget) {
277 return (IsFrameless() || has_frame_color_) ?
278 CreateNonStandardAppFrame() : CreateStandardDesktopAppFrame();
281 bool ChromeNativeAppWindowViews::WidgetHasHitTestMask() const {
282 return shape_ != NULL;
285 void ChromeNativeAppWindowViews::GetWidgetHitTestMask(gfx::Path* mask) const {
286 shape_->getBoundaryPath(mask);
289 // views::View implementation.
291 gfx::Size ChromeNativeAppWindowViews::GetPreferredSize() const {
292 if (!preferred_size_.IsEmpty())
293 return preferred_size_;
294 return NativeAppWindowViews::GetPreferredSize();
297 bool ChromeNativeAppWindowViews::AcceleratorPressed(
298 const ui::Accelerator& accelerator) {
299 const std::map<ui::Accelerator, int>& accelerator_table =
300 GetAcceleratorTable();
301 std::map<ui::Accelerator, int>::const_iterator iter =
302 accelerator_table.find(accelerator);
303 DCHECK(iter != accelerator_table.end());
304 int command_id = iter->second;
305 switch (command_id) {
306 case IDC_CLOSE_WINDOW:
307 Close();
308 return true;
309 case IDC_ZOOM_MINUS:
310 ui_zoom::PageZoom::Zoom(web_view()->GetWebContents(),
311 content::PAGE_ZOOM_OUT);
312 return true;
313 case IDC_ZOOM_NORMAL:
314 ui_zoom::PageZoom::Zoom(web_view()->GetWebContents(),
315 content::PAGE_ZOOM_RESET);
316 return true;
317 case IDC_ZOOM_PLUS:
318 ui_zoom::PageZoom::Zoom(web_view()->GetWebContents(),
319 content::PAGE_ZOOM_IN);
320 return true;
321 default:
322 NOTREACHED() << "Unknown accelerator sent to app window.";
324 return NativeAppWindowViews::AcceleratorPressed(accelerator);
327 // NativeAppWindow implementation.
329 void ChromeNativeAppWindowViews::SetFullscreen(int fullscreen_types) {
330 // Fullscreen not supported by panels.
331 if (app_window()->window_type_is_panel())
332 return;
334 widget()->SetFullscreen(fullscreen_types != AppWindow::FULLSCREEN_TYPE_NONE);
337 bool ChromeNativeAppWindowViews::IsFullscreenOrPending() const {
338 return widget()->IsFullscreen();
341 void ChromeNativeAppWindowViews::UpdateShape(scoped_ptr<SkRegion> region) {
342 shape_ = region.Pass();
343 widget()->SetShape(shape() ? new SkRegion(*shape()) : nullptr);
344 widget()->OnSizeConstraintsChanged();
347 bool ChromeNativeAppWindowViews::HasFrameColor() const {
348 return has_frame_color_;
351 SkColor ChromeNativeAppWindowViews::ActiveFrameColor() const {
352 return active_frame_color_;
355 SkColor ChromeNativeAppWindowViews::InactiveFrameColor() const {
356 return inactive_frame_color_;
359 // NativeAppWindowViews implementation.
361 void ChromeNativeAppWindowViews::InitializeWindow(
362 AppWindow* app_window,
363 const AppWindow::CreateParams& create_params) {
364 DCHECK(widget());
365 has_frame_color_ = create_params.has_frame_color;
366 active_frame_color_ = create_params.active_frame_color;
367 inactive_frame_color_ = create_params.inactive_frame_color;
368 if (create_params.window_type == AppWindow::WINDOW_TYPE_PANEL ||
369 create_params.window_type == AppWindow::WINDOW_TYPE_V1_PANEL) {
370 InitializePanelWindow(create_params);
371 } else {
372 InitializeDefaultWindow(create_params);
374 extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryViews(
375 Profile::FromBrowserContext(app_window->browser_context()),
376 widget()->GetFocusManager(),
377 extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY,
378 NULL));