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.
5 #include "chrome/browser/ui/views/frame/browser_frame.h"
8 #include "base/command_line.h"
9 #include "base/i18n/rtl.h"
10 #include "chrome/browser/app_mode/app_mode_utils.h"
11 #include "chrome/browser/themes/theme_service.h"
12 #include "chrome/browser/themes/theme_service_factory.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_list.h"
15 #include "chrome/browser/ui/browser_window_state.h"
16 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
17 #include "chrome/browser/ui/views/frame/browser_root_view.h"
18 #include "chrome/browser/ui/views/frame/browser_view.h"
19 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
20 #include "chrome/browser/ui/views/frame/native_browser_frame.h"
21 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
22 #include "chrome/browser/ui/views/frame/system_menu_model_builder.h"
23 #include "chrome/browser/ui/views/frame/top_container_view.h"
24 #include "chrome/browser/web_applications/web_app.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "ui/aura/root_window.h"
27 #include "ui/aura/window.h"
28 #include "ui/base/hit_test.h"
29 #include "ui/base/theme_provider.h"
30 #include "ui/gfx/font.h"
31 #include "ui/gfx/screen.h"
32 #include "ui/views/controls/menu/menu_runner.h"
33 #include "ui/views/widget/native_widget.h"
35 #if defined(OS_WIN) && !defined(USE_AURA)
36 #include "chrome/browser/ui/views/frame/glass_browser_frame_view.h"
37 #include "ui/views/widget/native_widget_win.h"
40 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
41 #include "chrome/browser/shell_integration_linux.h"
45 #include "chrome/browser/ui/ash/ash_init.h"
48 #if defined(OS_CHROMEOS)
49 #include "ash/session_state_delegate.h"
52 ////////////////////////////////////////////////////////////////////////////////
53 // BrowserFrame, public:
55 BrowserFrame::BrowserFrame(BrowserView
* browser_view
)
56 : native_browser_frame_(NULL
),
58 browser_frame_view_(NULL
),
59 browser_view_(browser_view
),
60 theme_provider_(ThemeServiceFactory::GetForProfile(
61 browser_view_
->browser()->profile())) {
62 browser_view_
->set_frame(this);
63 set_is_secondary_widget(false);
64 // Don't focus anything on creation, selecting a tab will set the focus.
65 set_focus_on_creation(false);
68 BrowserFrame::~BrowserFrame() {
72 const gfx::Font
& BrowserFrame::GetTitleFont() {
73 #if !defined(OS_WIN) || defined(USE_AURA)
74 static gfx::Font
* title_font
= new gfx::Font
;
76 static gfx::Font
* title_font
=
77 new gfx::Font(views::NativeWidgetWin::GetWindowTitleFont());
82 void BrowserFrame::InitBrowserFrame() {
83 native_browser_frame_
=
84 NativeBrowserFrameFactory::CreateNativeBrowserFrame(this, browser_view_
);
85 views::Widget::InitParams params
;
86 params
.delegate
= browser_view_
;
87 params
.native_widget
= native_browser_frame_
->AsNativeWidget();
88 if (browser_view_
->browser()->is_type_tabbed()) {
89 // Typed panel/popup can only return a size once the widget has been
91 chrome::GetSavedWindowBoundsAndShowState(browser_view_
->browser(),
96 if (browser_view_
->browser()->host_desktop_type() ==
97 chrome::HOST_DESKTOP_TYPE_ASH
|| chrome::ShouldOpenAshOnStartup()) {
98 params
.context
= ash::Shell::GetPrimaryRootWindow();
100 // If this window is under ASH on Windows, we need it to be translucent.
101 params
.opacity
= views::Widget::InitParams::TRANSLUCENT_WINDOW
;
106 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
107 // Set up a custom WM_CLASS for some sorts of window types. This allows
108 // task switchers in X11 environments to distinguish between main browser
109 // windows and e.g app windows.
110 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
111 const Browser
& browser
= *browser_view_
->browser();
112 params
.wm_class_class
= ShellIntegrationLinux::GetProgramClassName();
113 params
.wm_class_name
= params
.wm_class_class
;
114 if (browser
.is_app() && !browser
.is_devtools()) {
115 // This window is a hosted app or v1 packaged app.
116 // NOTE: v2 packaged app windows are created by NativeAppWindowViews.
117 params
.wm_class_name
= web_app::GetWMClassFromAppName(browser
.app_name());
118 } else if (command_line
.HasSwitch(switches::kUserDataDir
)) {
119 // Set the class name to e.g. "Chrome (/tmp/my-user-data)". The
120 // class name will show up in the alt-tab list in gnome-shell if
121 // you're running a binary that doesn't have a matching .desktop
123 const std::string user_data_dir
=
124 command_line
.GetSwitchValueNative(switches::kUserDataDir
);
125 params
.wm_class_name
+= " (" + user_data_dir
+ ")";
127 const char kX11WindowRoleBrowser
[] = "browser";
128 const char kX11WindowRolePopup
[] = "pop-up";
129 params
.wm_role_name
= browser_view_
->browser()->is_type_tabbed() ?
130 std::string(kX11WindowRoleBrowser
) : std::string(kX11WindowRolePopup
);
131 #endif // defined(OS_LINUX)
135 if (!native_browser_frame_
->UsesNativeSystemMenu()) {
136 DCHECK(non_client_view());
137 non_client_view()->set_context_menu_controller(this);
141 void BrowserFrame::SetThemeProvider(scoped_ptr
<ui::ThemeProvider
> provider
) {
142 owned_theme_provider_
= provider
.Pass();
143 theme_provider_
= owned_theme_provider_
.get();
146 int BrowserFrame::GetMinimizeButtonOffset() const {
147 return native_browser_frame_
->GetMinimizeButtonOffset();
150 gfx::Rect
BrowserFrame::GetBoundsForTabStrip(views::View
* tabstrip
) const {
151 return browser_frame_view_
->GetBoundsForTabStrip(tabstrip
);
154 int BrowserFrame::GetTopInset() const {
155 return browser_frame_view_
->GetTopInset();
158 int BrowserFrame::GetThemeBackgroundXInset() const {
159 return browser_frame_view_
->GetThemeBackgroundXInset();
162 void BrowserFrame::UpdateThrobber(bool running
) {
163 browser_frame_view_
->UpdateThrobber(running
);
166 views::View
* BrowserFrame::GetFrameView() const {
167 return browser_frame_view_
;
170 ///////////////////////////////////////////////////////////////////////////////
171 // BrowserFrame, views::Widget overrides:
173 views::internal::RootView
* BrowserFrame::CreateRootView() {
174 root_view_
= new BrowserRootView(browser_view_
, this);
178 views::NonClientFrameView
* BrowserFrame::CreateNonClientFrameView() {
179 browser_frame_view_
=
180 chrome::CreateBrowserNonClientFrameView(this, browser_view_
);
181 return browser_frame_view_
;
184 bool BrowserFrame::GetAccelerator(int command_id
,
185 ui::Accelerator
* accelerator
) {
186 return browser_view_
->GetAccelerator(command_id
, accelerator
);
189 ui::ThemeProvider
* BrowserFrame::GetThemeProvider() const {
190 return theme_provider_
;
193 void BrowserFrame::SchedulePaintInRect(const gfx::Rect
& rect
) {
194 views::Widget::SchedulePaintInRect(rect
);
196 // Paint the frame caption area and window controls during immersive reveal.
198 browser_view_
->immersive_mode_controller()->IsRevealed()) {
199 // This function should not be reentrant because the TopContainerView
200 // paints to a layer for the duration of the immersive reveal.
201 views::View
* top_container
= browser_view_
->top_container();
202 CHECK(top_container
->layer());
203 top_container
->SchedulePaintInRect(rect
);
207 void BrowserFrame::OnNativeWidgetActivationChanged(bool active
) {
209 // When running under remote desktop, if the remote desktop client is not
210 // active on the users desktop, then none of the windows contained in the
211 // remote desktop will be activated. However, NativeWidgetWin::Activate()
212 // will still bring this browser window to the foreground. We explicitly
213 // set ourselves as the last active browser window to ensure that we get
214 // treated as such by the rest of Chrome.
215 BrowserList::SetLastActive(browser_view_
->browser());
217 Widget::OnNativeWidgetActivationChanged(active
);
220 void BrowserFrame::ShowContextMenuForView(views::View
* source
,
222 ui::MenuSourceType source_type
) {
223 if (chrome::IsRunningInForcedAppMode())
226 // Only show context menu if point is in unobscured parts of browser, i.e.
227 // if NonClientHitTest returns :
228 // - HTCAPTION: in title bar or unobscured part of tabstrip
229 // - HTNOWHERE: as the name implies.
230 gfx::Point
point_in_view_coords(p
);
231 views::View::ConvertPointFromScreen(non_client_view(), &point_in_view_coords
);
232 int hit_test
= non_client_view()->NonClientHitTest(point_in_view_coords
);
233 if (hit_test
== HTCAPTION
|| hit_test
== HTNOWHERE
) {
234 menu_runner_
.reset(new views::MenuRunner(GetSystemMenuModel()));
235 if (menu_runner_
->RunMenuAt(source
->GetWidget(), NULL
,
236 gfx::Rect(p
, gfx::Size(0,0)), views::MenuItemView::TOPLEFT
,
238 views::MenuRunner::HAS_MNEMONICS
| views::MenuRunner::CONTEXT_MENU
) ==
239 views::MenuRunner::MENU_DELETED
)
244 ui::MenuModel
* BrowserFrame::GetSystemMenuModel() {
245 #if defined(OS_CHROMEOS)
246 ash::SessionStateDelegate
* delegate
=
247 ash::Shell::GetInstance()->session_state_delegate();
248 if (delegate
&& delegate
->NumberOfLoggedInUsers() > 1) {
249 // In Multi user mode, the number of users as well as the order of users
250 // can change. Coming here we have more then one user and since the menu
251 // model contains the user information, it must get updated to show any
252 // changes happened since the last invocation.
253 menu_model_builder_
.reset();
256 if (!menu_model_builder_
.get()) {
257 menu_model_builder_
.reset(
258 new SystemMenuModelBuilder(browser_view_
, browser_view_
->browser()));
259 menu_model_builder_
->Init();
261 return menu_model_builder_
->menu_model();
264 AvatarMenuButton
* BrowserFrame::GetAvatarMenuButton() {
265 return browser_frame_view_
->avatar_button();
268 NewAvatarButton
* BrowserFrame::GetNewAvatarMenuButton() {
269 return browser_frame_view_
->new_avatar_button();
272 #if !defined(OS_WIN) || defined(USE_AURA)
273 bool BrowserFrame::ShouldLeaveOffsetNearTopBorder() {
274 return !IsMaximized();