chrome_views_delegate.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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 "chrome/browser/ui/views/chrome_views_delegate.h" 6 7#include "base/command_line.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/prefs/pref_service.h" 10#include "base/string_util.h" 11#include "base/utf_string_conversions.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/browser/prefs/scoped_user_pref_update.h" 14#include "chrome/browser/profiles/profile_manager.h" 15#include "chrome/browser/ui/views/accessibility/accessibility_event_router_views.h" 16#include "chrome/common/pref_names.h" 17#include "ui/base/ui_base_switches.h" 18#include "ui/gfx/rect.h" 19#include "ui/gfx/screen.h" 20#include "ui/views/widget/native_widget.h" 21#include "ui/views/widget/widget.h" 22 23#if defined(OS_WIN) 24#include <dwmapi.h> 25#include "base/win/windows_version.h" 26#include "chrome/browser/app_icon_win.h" 27#endif 28 29#if defined(USE_AURA) 30#include "ui/aura/root_window.h" 31#endif 32 33#if defined(USE_AURA) && !defined(OS_CHROMEOS) 34#include "chrome/browser/ui/host_desktop.h" 35#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" 36#include "ui/views/widget/native_widget_aura.h" 37#endif 38 39#if defined(USE_ASH) 40#include "ash/shell.h" 41#include "chrome/browser/ui/ash/ash_init.h" 42#include "chrome/browser/ui/ash/ash_util.h" 43#endif 44 45namespace { 46 47// If the given window has a profile associated with it, use that profile's 48// preference service. Otherwise, store and retrieve the data from Local State. 49// This function may return NULL if the necessary pref service has not yet 50// been initialized. 51// TODO(mirandac): This function will also separate windows by profile in a 52// multi-profile environment. 53PrefService* GetPrefsForWindow(const views::Widget* window) { 54 Profile* profile = reinterpret_cast<Profile*>( 55 window->GetNativeWindowProperty(Profile::kProfileKey)); 56 if (!profile) { 57 // Use local state for windows that have no explicit profile. 58 return g_browser_process->local_state(); 59 } 60 return profile->GetPrefs(); 61} 62 63} // namespace 64 65/////////////////////////////////////////////////////////////////////////////// 66// ChromeViewsDelegate, views::ViewsDelegate implementation: 67 68void ChromeViewsDelegate::SaveWindowPlacement(const views::Widget* window, 69 const std::string& window_name, 70 const gfx::Rect& bounds, 71 ui::WindowShowState show_state) { 72 PrefService* prefs = GetPrefsForWindow(window); 73 if (!prefs) 74 return; 75 76 DCHECK(prefs->FindPreference(window_name.c_str())); 77 DictionaryPrefUpdate update(prefs, window_name.c_str()); 78 DictionaryValue* window_preferences = update.Get(); 79 window_preferences->SetInteger("left", bounds.x()); 80 window_preferences->SetInteger("top", bounds.y()); 81 window_preferences->SetInteger("right", bounds.right()); 82 window_preferences->SetInteger("bottom", bounds.bottom()); 83 window_preferences->SetBoolean("maximized", 84 show_state == ui::SHOW_STATE_MAXIMIZED); 85 gfx::Rect work_area(gfx::Screen::GetScreenFor(window->GetNativeView())-> 86 GetDisplayMatching(bounds).work_area()); 87 window_preferences->SetInteger("work_area_left", work_area.x()); 88 window_preferences->SetInteger("work_area_top", work_area.y()); 89 window_preferences->SetInteger("work_area_right", work_area.right()); 90 window_preferences->SetInteger("work_area_bottom", work_area.bottom()); 91} 92 93bool ChromeViewsDelegate::GetSavedWindowPlacement( 94 const std::string& window_name, 95 gfx::Rect* bounds, 96 ui::WindowShowState* show_state) const { 97 PrefService* prefs = g_browser_process->local_state(); 98 if (!prefs) 99 return false; 100 101 DCHECK(prefs->FindPreference(window_name.c_str())); 102 const DictionaryValue* dictionary = prefs->GetDictionary(window_name.c_str()); 103 int left, top, right, bottom; 104 if (!dictionary || !dictionary->GetInteger("left", &left) || 105 !dictionary->GetInteger("top", &top) || 106 !dictionary->GetInteger("right", &right) || 107 !dictionary->GetInteger("bottom", &bottom)) 108 return false; 109 110 bounds->SetRect(left, top, right - left, bottom - top); 111 112 bool maximized = false; 113 if (dictionary) 114 dictionary->GetBoolean("maximized", &maximized); 115 *show_state = maximized ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL; 116 117 return true; 118} 119 120void ChromeViewsDelegate::NotifyAccessibilityEvent( 121 views::View* view, ui::AccessibilityTypes::Event event_type) { 122 AccessibilityEventRouterViews::GetInstance()->HandleAccessibilityEvent( 123 view, event_type); 124} 125 126void ChromeViewsDelegate::NotifyMenuItemFocused(const string16& menu_name, 127 const string16& menu_item_name, 128 int item_index, 129 int item_count, 130 bool has_submenu) { 131 AccessibilityEventRouterViews::GetInstance()->HandleMenuItemFocused( 132 menu_name, menu_item_name, item_index, item_count, has_submenu); 133} 134 135#if defined(OS_WIN) 136HICON ChromeViewsDelegate::GetDefaultWindowIcon() const { 137 return GetAppIcon(); 138} 139#endif 140 141views::NonClientFrameView* ChromeViewsDelegate::CreateDefaultNonClientFrameView( 142 views::Widget* widget) { 143#if defined(USE_ASH) 144 if (chrome::IsNativeViewInAsh(widget->GetNativeView())) 145 return ash::Shell::GetInstance()->CreateDefaultNonClientFrameView(widget); 146#endif 147 return NULL; 148} 149 150bool ChromeViewsDelegate::UseTransparentWindows() const { 151#if defined(USE_ASH) 152 // TODO(scottmg): http://crbug.com/133312. This needs context to determine 153 // if it's desktop or ash. 154#if defined(OS_CHROMEOS) 155 return true; 156#else 157 NOTIMPLEMENTED(); 158 return false; 159#endif 160#else 161 return false; 162#endif 163} 164 165void ChromeViewsDelegate::AddRef() { 166 g_browser_process->AddRefModule(); 167} 168 169void ChromeViewsDelegate::ReleaseRef() { 170 g_browser_process->ReleaseModule(); 171} 172 173content::WebContents* ChromeViewsDelegate::CreateWebContents( 174 content::BrowserContext* browser_context, 175 content::SiteInstance* site_instance) { 176 return NULL; 177} 178 179void ChromeViewsDelegate::OnBeforeWidgetInit( 180 views::Widget::InitParams* params, 181 views::internal::NativeWidgetDelegate* delegate) { 182 // If we already have a native_widget, we don't have to try to come 183 // up with one. 184 if (params->native_widget) 185 return; 186 187#if defined(USE_AURA) && !defined(OS_CHROMEOS) 188 bool use_non_toplevel_window = 189 params->parent && params->type != views::Widget::InitParams::TYPE_MENU; 190#if defined(OS_WIN) 191 // If we're on Vista+ with composition enabled, then we can use toplevel 192 // windows for most things (they get blended via WS_EX_COMPOSITED, which 193 // allows for animation effects, but also exceeding the bounds of the parent 194 // window). 195 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 196 BOOL composition_enabled = FALSE; 197 HRESULT hr = DwmIsCompositionEnabled(&composition_enabled); 198 if (CommandLine::ForCurrentProcess()->HasSwitch( 199 switches::kDisableDwmComposition)) 200 composition_enabled = FALSE; 201 if (SUCCEEDED(hr) && composition_enabled) { 202 if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH && 203 params->parent && 204 params->type != views::Widget::InitParams::TYPE_CONTROL && 205 params->type != views::Widget::InitParams::TYPE_WINDOW) { 206 // When we set this to false, we get a DesktopNativeWidgetAura from the 207 // default case (not handled in this function). 208 use_non_toplevel_window = false; 209 } 210 } 211 } 212#endif // OS_WIN 213#endif // USE_AURA 214 215#if defined(OS_CHROMEOS) 216 // When we are doing straight chromeos builds, we still need to handle the 217 // toplevel window case. 218 // There may be a few remaining widgets in Chrome OS that are not top level, 219 // but have neither a context nor a parent. Provide a fallback context so 220 // users don't crash. Developers will hit the DCHECK and should provide a 221 // context. 222 DCHECK(params->parent || params->context || params->top_level) 223 << "Please provide a parent or context for this widget."; 224 if (!params->parent && !params->context) 225 params->context = ash::Shell::GetPrimaryRootWindow(); 226#elif defined(USE_AURA) 227 // While the majority of the time, context wasn't plumbed through due to the 228 // existence of a global StackingClient, if this window is a toplevel, it's 229 // possible that there is no contextual state that we can use. 230 if (params->parent == NULL && params->context == NULL && params->top_level) { 231 // We need to make a decision about where to place this window based on the 232 // desktop type. 233 switch (chrome::GetActiveDesktop()) { 234 case chrome::HOST_DESKTOP_TYPE_NATIVE: 235 // If we're native, we should give this window its own toplevel desktop 236 // widget. 237 params->native_widget = new views::DesktopNativeWidgetAura(delegate); 238 break; 239#if defined(USE_ASH) 240 case chrome::HOST_DESKTOP_TYPE_ASH: 241 // If we're in ash, give this window the context of the main monitor. 242 params->context = ash::Shell::GetPrimaryRootWindow(); 243 break; 244#endif 245 default: 246 NOTREACHED(); 247 } 248 } else if (use_non_toplevel_window) { 249 params->native_widget = new views::NativeWidgetAura(delegate); 250 } else if (params->type != views::Widget::InitParams::TYPE_TOOLTIP) { 251 // TODO(erg): Once we've threaded context to everywhere that needs it, we 252 // should remove this check here. 253 gfx::NativeView to_check = 254 params->context ? params->context : params->parent; 255 if (chrome::GetHostDesktopTypeForNativeView(to_check) == 256 chrome::HOST_DESKTOP_TYPE_NATIVE) { 257 params->native_widget = new views::DesktopNativeWidgetAura(delegate); 258 } 259 } 260#endif 261} 262