blob: 96f14b1e5e8cb7e254ffe4a62e89f2e160e8a484 [file] [log] [blame]
[email protected]97045192012-03-09 20:53:591// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]052313b2010-02-19 09:43:082// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
[email protected]609eeec22009-05-10 06:21:494
[email protected]9e790bd2011-01-10 23:48:545#include "chrome/browser/ui/views/chrome_views_delegate.h"
[email protected]609eeec22009-05-10 06:21:496
dcheng9603ab92016-04-08 04:17:327#include <memory>
8
fdoray6be72ad2016-06-16 17:46:419#include "base/location.h"
fdoray19e49e92016-09-30 20:42:1610#include "base/logging.h"
fdoray6be72ad2016-06-16 17:46:4111#include "base/message_loop/message_loop.h"
fdoray283082bd2016-06-02 20:18:4612#include "base/single_thread_task_runner.h"
[email protected]2ff320552013-06-10 22:53:1813#include "base/strings/string_util.h"
[email protected]774cc3c2013-06-07 20:26:4514#include "base/strings/utf_string_conversions.h"
fdoray19e49e92016-09-30 20:42:1615#include "base/threading/thread_task_runner_handle.h"
[email protected]b22b27a2013-06-28 05:37:5716#include "base/time/time.h"
avi202f3402015-12-24 23:54:4517#include "build/build_config.h"
[email protected]609eeec22009-05-10 06:21:4918#include "chrome/browser/browser_process.h"
dgnfe075c82016-03-18 11:25:3519#include "chrome/browser/lifetime/keep_alive_types.h"
20#include "chrome/browser/lifetime/scoped_keep_alive.h"
[email protected]f87919d72011-02-02 18:46:1621#include "chrome/browser/profiles/profile_manager.h"
staraz92c518d2016-06-20 18:07:4622#include "chrome/browser/ui/ash/ash_util.h"
dgrogane30f8f02014-09-16 22:41:0823#include "chrome/browser/ui/browser_window_state.h"
ellyjones50ef64e2016-11-22 19:48:1324#include "chrome/browser/ui/views/harmony/harmony_layout_delegate.h"
thestig4a9b0ef2016-08-29 08:22:1225#include "chrome/grit/chrome_unscaled_resources.h"
brettwb1fc1b82016-02-02 00:19:0826#include "components/prefs/pref_service.h"
27#include "components/prefs/scoped_user_pref_update.h"
sdefresne9fb67692015-08-03 18:48:2228#include "components/version_info/version_info.h"
dmazzonib9bfea772015-04-27 21:12:4529#include "content/public/browser/browser_thread.h"
tapted36ffc472014-11-11 22:17:0430#include "content/public/browser/context_factory.h"
ellyjones50ef64e2016-11-22 19:48:1331#include "ui/base/material_design/material_design_controller.h"
[email protected]4af13c722013-11-13 21:16:3932#include "ui/base/resource/resource_bundle.h"
[email protected]0a2703fd2013-04-12 16:14:0833#include "ui/base/ui_base_switches.h"
oshima888290a2016-05-13 20:36:0634#include "ui/display/display.h"
oshimad5c972e2016-04-28 23:17:1435#include "ui/display/screen.h"
tfarina3b0452d2014-12-31 15:20:0936#include "ui/gfx/geometry/rect.h"
afakhry692024d92015-09-14 17:07:3837#include "ui/views/controls/menu/menu_controller.h"
[email protected]c13be0d2011-11-22 02:09:5838#include "ui/views/widget/native_widget.h"
39#include "ui/views/widget/widget.h"
[email protected]609eeec22009-05-10 06:21:4940
[email protected]f7be2197b2010-04-23 00:20:4441#if defined(OS_WIN)
[email protected]0f440df2013-04-02 07:43:2242#include <dwmapi.h>
[email protected]05ac311a2014-04-22 20:49:3543#include <shellapi.h>
robliaocc68a9f2015-02-27 03:36:2244#include "base/profiler/scoped_tracker.h"
[email protected]6c52fef2014-04-22 20:26:5345#include "base/task_runner_util.h"
[email protected]0f440df2013-04-02 07:43:2246#include "base/win/windows_version.h"
pmonette23c8fb7e2016-06-27 20:45:1147#include "chrome/browser/win/app_icon.h"
[email protected]9a8a76d2013-06-29 13:02:1548#include "ui/base/win/shell.h"
[email protected]f7be2197b2010-04-23 00:20:4449#endif
50
[email protected]2a2caa02013-01-22 20:50:3651#if defined(USE_AURA)
dtseng22fad8b2015-03-30 21:45:5752#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
[email protected]98e0f0962014-04-24 23:42:1153#include "ui/aura/window.h"
[email protected]fcc51c952014-02-21 21:31:2654#include "ui/aura/window_event_dispatcher.h"
[email protected]2a2caa02013-01-22 20:50:3655#endif
56
[email protected]2f0dcb62012-09-13 22:49:5157#if defined(USE_AURA) && !defined(OS_CHROMEOS)
[email protected]02957542012-11-13 20:41:2358#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
[email protected]80eb77bd2012-10-05 20:20:2159#include "ui/views/widget/native_widget_aura.h"
[email protected]2f0dcb62012-09-13 22:49:5160#endif
61
[email protected]02abfee2014-01-23 09:27:0262#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
63#include "ui/views/linux_ui/linux_ui.h"
64#endif
65
[email protected]97045192012-03-09 20:53:5966#if defined(USE_ASH)
brettw08fe0e952016-08-26 21:53:3967#include "ash/common/accelerators/accelerator_controller.h" // nogncheck
68#include "ash/common/wm/window_state.h" // nogncheck
69#include "ash/common/wm_shell.h" // nogncheck
70#include "ash/shell.h" // nogncheck
71#include "ash/wm/window_state_aura.h" // nogncheck
72#include "chrome/browser/ui/ash/ash_init.h" // nogncheck
[email protected]57b8bb352012-01-11 05:11:4673#endif
74
[email protected]e9fe8512014-04-21 21:27:0875// Helpers --------------------------------------------------------------------
76
[email protected]f87919d72011-02-02 18:46:1677namespace {
78
[email protected]ec9738b2014-04-20 21:56:0079Profile* GetProfileForWindow(const views::Widget* window) {
80 if (!window)
81 return NULL;
82 return reinterpret_cast<Profile*>(
83 window->GetNativeWindowProperty(Profile::kProfileKey));
84}
85
[email protected]28aec9a2011-02-04 13:45:1186// If the given window has a profile associated with it, use that profile's
87// preference service. Otherwise, store and retrieve the data from Local State.
88// This function may return NULL if the necessary pref service has not yet
89// been initialized.
90// TODO(mirandac): This function will also separate windows by profile in a
91// multi-profile environment.
[email protected]0c2830d2011-08-26 18:05:0992PrefService* GetPrefsForWindow(const views::Widget* window) {
[email protected]ec9738b2014-04-20 21:56:0093 Profile* profile = GetProfileForWindow(window);
[email protected]28aec9a2011-02-04 13:45:1194 if (!profile) {
95 // Use local state for windows that have no explicit profile.
[email protected]f87919d72011-02-02 18:46:1696 return g_browser_process->local_state();
[email protected]f87919d72011-02-02 18:46:1697 }
[email protected]28aec9a2011-02-04 13:45:1198 return profile->GetPrefs();
[email protected]f87919d72011-02-02 18:46:1699}
100
[email protected]6c52fef2014-04-22 20:26:53101#if defined(OS_WIN)
anantaabe5bdc2016-12-03 03:32:47102bool MonitorHasAutohideTaskbarForEdge(UINT edge, HMONITOR monitor) {
[email protected]517904452014-05-31 01:03:30103 APPBARDATA taskbar_data = { sizeof(APPBARDATA), NULL, 0, edge };
anantac64c9032015-11-23 21:28:27104 taskbar_data.hWnd = ::GetForegroundWindow();
robliaocc68a9f2015-02-27 03:36:22105
106 // TODO(robliao): Remove ScopedTracker below once crbug.com/462368 is fixed.
107 tracked_objects::ScopedTracker tracking_profile(
108 FROM_HERE_WITH_EXPLICIT_FUNCTION(
anantaabe5bdc2016-12-03 03:32:47109 "462368 MonitorHasAutohideTaskbarForEdge"));
robliaocc68a9f2015-02-27 03:36:22110
[email protected]517904452014-05-31 01:03:30111 // MSDN documents an ABM_GETAUTOHIDEBAREX, which supposedly takes a monitor
112 // rect and returns autohide bars on that monitor. This sounds like a good
113 // idea for multi-monitor systems. Unfortunately, it appears to not work at
114 // least some of the time (erroneously returning NULL) and there's almost no
115 // online documentation or other sample code using it that suggests ways to
anantac64c9032015-11-23 21:28:27116 // address this problem. We do the following:-
117 // 1. Use the ABM_GETAUTOHIDEBAR message. If it works, i.e. returns a valid
118 // window we are done.
119 // 2. If the ABM_GETAUTOHIDEBAR message does not work we query the auto hide
120 // state of the taskbar and then retrieve its position. That call returns
121 // the edge on which the taskbar is present. If it matches the edge we
122 // are looking for, we are done.
[email protected]6c52fef2014-04-22 20:26:53123 // NOTE: This call spins a nested message loop.
[email protected]517904452014-05-31 01:03:30124 HWND taskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAR,
[email protected]6c52fef2014-04-22 20:26:53125 &taskbar_data));
anantac64c9032015-11-23 21:28:27126 if (!::IsWindow(taskbar)) {
127 APPBARDATA taskbar_data = { sizeof(APPBARDATA), 0, 0, 0};
128 unsigned int taskbar_state = SHAppBarMessage(ABM_GETSTATE,
129 &taskbar_data);
130 if (!(taskbar_state & ABS_AUTOHIDE))
131 return false;
132
133 taskbar_data.hWnd = ::FindWindow(L"Shell_TrayWnd", NULL);
134 if (!::IsWindow(taskbar_data.hWnd))
135 return false;
136
137 SHAppBarMessage(ABM_GETTASKBARPOS, &taskbar_data);
138 if (taskbar_data.uEdge == edge)
139 taskbar = taskbar_data.hWnd;
140 }
anantaa25bf4f2016-02-25 20:38:13141
anantaabe5bdc2016-12-03 03:32:47142 // There is a potential race condition here:
143 // 1. A maximized chrome window is fullscreened.
144 // 2. It is switched back to maximized.
145 // 3. In the process the window gets a WM_NCCACLSIZE message which calls us to
146 // get the autohide state.
147 // 4. The worker thread is invoked. It calls the API to get the autohide
148 // state. On Windows versions earlier than Windows 7, taskbars could
149 // easily be always on top or not.
150 // This meant that we only want to look for taskbars which have the topmost
151 // bit set. However this causes problems in cases where the window on the
152 // main thread is still in the process of switching away from fullscreen.
153 // In this case the taskbar might not yet have the topmost bit set.
154 // 5. The main thread resumes and does not leave space for the taskbar and
155 // hence it does not pop when hovered.
156 //
157 // To address point 4 above, it is best to not check for the WS_EX_TOPMOST
158 // window style on the taskbar, as starting from Windows 7, the topmost
159 // style is always set. We don't support XP and Vista anymore.
160 if (::IsWindow(taskbar)) {
anantaa25bf4f2016-02-25 20:38:13161 if (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONEAREST) == monitor)
162 return true;
163 // In some cases like when the autohide taskbar is on the left of the
164 // secondary monitor, the MonitorFromWindow call above fails to return the
165 // correct monitor the taskbar is on. We fallback to MonitorFromPoint for
166 // the cursor position in that case, which seems to work well.
167 POINT cursor_pos = {0};
168 GetCursorPos(&cursor_pos);
169 if (MonitorFromPoint(cursor_pos, MONITOR_DEFAULTTONEAREST) == monitor)
170 return true;
171 }
172 return false;
[email protected]6c52fef2014-04-22 20:26:53173}
174
175int GetAppbarAutohideEdgesOnWorkerThread(HMONITOR monitor) {
176 DCHECK(monitor);
177
[email protected]6c52fef2014-04-22 20:26:53178 int edges = 0;
anantaabe5bdc2016-12-03 03:32:47179 if (MonitorHasAutohideTaskbarForEdge(ABE_LEFT, monitor))
[email protected]6c52fef2014-04-22 20:26:53180 edges |= views::ViewsDelegate::EDGE_LEFT;
anantaabe5bdc2016-12-03 03:32:47181 if (MonitorHasAutohideTaskbarForEdge(ABE_TOP, monitor))
[email protected]6c52fef2014-04-22 20:26:53182 edges |= views::ViewsDelegate::EDGE_TOP;
anantaabe5bdc2016-12-03 03:32:47183 if (MonitorHasAutohideTaskbarForEdge(ABE_RIGHT, monitor))
[email protected]6c52fef2014-04-22 20:26:53184 edges |= views::ViewsDelegate::EDGE_RIGHT;
anantaabe5bdc2016-12-03 03:32:47185 if (MonitorHasAutohideTaskbarForEdge(ABE_BOTTOM, monitor))
[email protected]6c52fef2014-04-22 20:26:53186 edges |= views::ViewsDelegate::EDGE_BOTTOM;
187 return edges;
188}
189#endif
190
afakhry692024d92015-09-14 17:07:38191#if defined(USE_ASH)
192void ProcessAcceleratorNow(const ui::Accelerator& accelerator) {
193 // TODO(afakhry): See if we need here to send the accelerator to the
194 // FocusManager of the active window in a follow-up CL.
sky89eb8012016-07-22 03:28:31195 ash::WmShell::Get()->accelerator_controller()->Process(accelerator);
afakhry692024d92015-09-14 17:07:38196}
197#endif // defined(USE_ASH)
198
[email protected]f87919d72011-02-02 18:46:16199} // namespace
200
[email protected]e9fe8512014-04-21 21:27:08201
202// ChromeViewsDelegate --------------------------------------------------------
203
[email protected]6c52fef2014-04-22 20:26:53204#if defined(OS_WIN)
205ChromeViewsDelegate::ChromeViewsDelegate()
mohan.reddy1da4b612014-09-18 02:57:57206 : in_autohide_edges_callback_(false),
207 weak_factory_(this) {
[email protected]6c52fef2014-04-22 20:26:53208#else
[email protected]e9fe8512014-04-21 21:27:08209ChromeViewsDelegate::ChromeViewsDelegate() {
[email protected]6c52fef2014-04-22 20:26:53210#endif
[email protected]e9fe8512014-04-21 21:27:08211}
212
213ChromeViewsDelegate::~ChromeViewsDelegate() {
dgn6dd1bb22016-04-13 19:10:04214 DCHECK_EQ(0u, ref_count_);
[email protected]e9fe8512014-04-21 21:27:08215}
[email protected]609eeec22009-05-10 06:21:49216
[email protected]2fdd00a2011-06-13 21:56:26217void ChromeViewsDelegate::SaveWindowPlacement(const views::Widget* window,
[email protected]660a3bc2011-09-16 18:40:55218 const std::string& window_name,
[email protected]609eeec22009-05-10 06:21:49219 const gfx::Rect& bounds,
[email protected]0fbe67bd2011-08-31 23:27:33220 ui::WindowShowState show_state) {
[email protected]0c2830d2011-08-26 18:05:09221 PrefService* prefs = GetPrefsForWindow(window);
[email protected]f87919d72011-02-02 18:46:16222 if (!prefs)
[email protected]609eeec22009-05-10 06:21:49223 return;
224
dcheng9603ab92016-04-08 04:17:32225 std::unique_ptr<DictionaryPrefUpdate> pref_update =
dgrogane30f8f02014-09-16 22:41:08226 chrome::GetWindowPlacementDictionaryReadWrite(window_name, prefs);
227 base::DictionaryValue* window_preferences = pref_update->Get();
[email protected]e2194742010-08-12 05:54:34228 window_preferences->SetInteger("left", bounds.x());
229 window_preferences->SetInteger("top", bounds.y());
230 window_preferences->SetInteger("right", bounds.right());
231 window_preferences->SetInteger("bottom", bounds.bottom());
[email protected]0fbe67bd2011-08-31 23:27:33232 window_preferences->SetBoolean("maximized",
233 show_state == ui::SHOW_STATE_MAXIMIZED);
afakhry25a6b952017-01-27 20:36:50234 // TODO(afakhry): Remove Docked Windows in M58.
varkha86fc7fe22015-07-10 20:36:41235 window_preferences->SetBoolean("docked", show_state == ui::SHOW_STATE_DOCKED);
afakhry25a6b952017-01-27 20:36:50236
oshimad5c972e2016-04-28 23:17:14237 gfx::Rect work_area(display::Screen::GetScreen()
scottmgfb33c342016-01-27 01:30:36238 ->GetDisplayNearestWindow(window->GetNativeView())
239 .work_area());
[email protected]e2194742010-08-12 05:54:34240 window_preferences->SetInteger("work_area_left", work_area.x());
241 window_preferences->SetInteger("work_area_top", work_area.y());
242 window_preferences->SetInteger("work_area_right", work_area.right());
243 window_preferences->SetInteger("work_area_bottom", work_area.bottom());
[email protected]609eeec22009-05-10 06:21:49244}
245
[email protected]0fbe67bd2011-08-31 23:27:33246bool ChromeViewsDelegate::GetSavedWindowPlacement(
[email protected]0194049b2013-11-01 15:23:12247 const views::Widget* widget,
[email protected]660a3bc2011-09-16 18:40:55248 const std::string& window_name,
[email protected]0fbe67bd2011-08-31 23:27:33249 gfx::Rect* bounds,
250 ui::WindowShowState* show_state) const {
[email protected]6b823fc32011-07-14 23:05:16251 PrefService* prefs = g_browser_process->local_state();
[email protected]f87919d72011-02-02 18:46:16252 if (!prefs)
[email protected]609eeec22009-05-10 06:21:49253 return false;
254
tfarina2b8c37632015-08-13 18:38:09255 DCHECK(prefs->FindPreference(window_name));
256 const base::DictionaryValue* dictionary = prefs->GetDictionary(window_name);
[email protected]1d447bd92014-07-03 07:17:42257 int left = 0;
258 int top = 0;
259 int right = 0;
260 int bottom = 0;
[email protected]e2194742010-08-12 05:54:34261 if (!dictionary || !dictionary->GetInteger("left", &left) ||
262 !dictionary->GetInteger("top", &top) ||
263 !dictionary->GetInteger("right", &right) ||
264 !dictionary->GetInteger("bottom", &bottom))
[email protected]609eeec22009-05-10 06:21:49265 return false;
266
267 bounds->SetRect(left, top, right - left, bottom - top);
[email protected]0fbe67bd2011-08-31 23:27:33268
269 bool maximized = false;
270 if (dictionary)
271 dictionary->GetBoolean("maximized", &maximized);
272 *show_state = maximized ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL;
273
[email protected]0194049b2013-11-01 15:23:12274#if defined(USE_ASH)
275 // On Ash environment, a window won't span across displays. Adjust
276 // the bounds to fit the work area.
277 gfx::NativeView window = widget->GetNativeView();
oshimad5c972e2016-04-28 23:17:14278 display::Display display =
279 display::Screen::GetScreen()->GetDisplayMatching(*bounds);
scottmge0c631f2016-02-20 06:16:29280 bounds->AdjustToFit(display.work_area());
281 ash::wm::GetWindowState(window)->set_minimum_visibility(true);
[email protected]0194049b2013-11-01 15:23:12282#endif
[email protected]609eeec22009-05-10 06:21:49283 return true;
284}
285
[email protected]6a054ffa2010-08-06 07:07:18286void ChromeViewsDelegate::NotifyAccessibilityEvent(
[email protected]739c8bc2014-02-25 18:28:13287 views::View* view, ui::AXEvent event_type) {
dtseng22fad8b2015-03-30 21:45:57288#if defined(USE_AURA)
289 AutomationManagerAura::GetInstance()->HandleEvent(
[email protected]ec9738b2014-04-20 21:56:00290 GetProfileForWindow(view->GetWidget()), view, event_type);
[email protected]37ed14e2014-05-01 08:37:58291#endif
[email protected]6a054ffa2010-08-06 07:07:18292}
293
afakhry692024d92015-09-14 17:07:38294views::ViewsDelegate::ProcessMenuAcceleratorResult
295ChromeViewsDelegate::ProcessAcceleratorWhileMenuShowing(
296 const ui::Accelerator& accelerator) {
297#if defined(USE_ASH)
fdoray19e49e92016-09-30 20:42:16298 DCHECK(base::MessageLoopForUI::IsCurrent());
299
staraz92c518d2016-06-20 18:07:46300 // Early return because mash chrome does not have access to ash::Shell
301 if (chrome::IsRunningInMash())
302 return views::ViewsDelegate::ProcessMenuAcceleratorResult::LEAVE_MENU_OPEN;
303
afakhry692024d92015-09-14 17:07:38304 ash::AcceleratorController* accelerator_controller =
sky89eb8012016-07-22 03:28:31305 ash::WmShell::Get()->accelerator_controller();
afakhry692024d92015-09-14 17:07:38306
307 accelerator_controller->accelerator_history()->StoreCurrentAccelerator(
308 accelerator);
309 if (accelerator_controller->ShouldCloseMenuAndRepostAccelerator(
310 accelerator)) {
fdoray19e49e92016-09-30 20:42:16311 base::ThreadTaskRunnerHandle::Get()->PostTask(
fdoray283082bd2016-06-02 20:18:46312 FROM_HERE, base::Bind(ProcessAcceleratorNow, accelerator));
afakhry692024d92015-09-14 17:07:38313 return views::ViewsDelegate::ProcessMenuAcceleratorResult::CLOSE_MENU;
314 }
315
316 ProcessAcceleratorNow(accelerator);
317 return views::ViewsDelegate::ProcessMenuAcceleratorResult::LEAVE_MENU_OPEN;
318#else
319 return views::ViewsDelegate::ProcessMenuAcceleratorResult::LEAVE_MENU_OPEN;
320#endif // defined(USE_ASH)
321}
322
[email protected]609eeec22009-05-10 06:21:49323#if defined(OS_WIN)
324HICON ChromeViewsDelegate::GetDefaultWindowIcon() const {
[email protected]f7be2197b2010-04-23 00:20:44325 return GetAppIcon();
[email protected]609eeec22009-05-10 06:21:49326}
[email protected]ceeed3b32013-12-03 21:46:53327
tmoniuszkocd5b3ee2014-12-15 08:51:04328HICON ChromeViewsDelegate::GetSmallWindowIcon() const {
329 return GetSmallAppIcon();
330}
331
[email protected]4af13c722013-11-13 21:16:39332#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
333gfx::ImageSkia* ChromeViewsDelegate::GetDefaultWindowIcon() const {
334 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
335 return rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_64);
336}
[email protected]609eeec22009-05-10 06:21:49337#endif
[email protected]365e821c2010-04-16 19:38:33338
[email protected]e9fe8512014-04-21 21:27:08339#if defined(USE_ASH)
[email protected]57b8bb352012-01-11 05:11:46340views::NonClientFrameView* ChromeViewsDelegate::CreateDefaultNonClientFrameView(
341 views::Widget* widget) {
oshima4f7917282016-05-10 11:25:03342 return ash::Shell::GetInstance()->CreateDefaultNonClientFrameView(widget);
[email protected]57b8bb352012-01-11 05:11:46343}
[email protected]e9fe8512014-04-21 21:27:08344#endif
[email protected]57b8bb352012-01-11 05:11:46345
[email protected]365e821c2010-04-16 19:38:33346void ChromeViewsDelegate::AddRef() {
dgn6dd1bb22016-04-13 19:10:04347 if (ref_count_ == 0u) {
348 keep_alive_.reset(
349 new ScopedKeepAlive(KeepAliveOrigin::CHROME_VIEWS_DELEGATE,
350 KeepAliveRestartOption::DISABLED));
351 }
352
353 ++ref_count_;
[email protected]365e821c2010-04-16 19:38:33354}
355
356void ChromeViewsDelegate::ReleaseRef() {
dgn6dd1bb22016-04-13 19:10:04357 DCHECK_NE(0u, ref_count_);
358
359 if (--ref_count_ == 0u)
360 keep_alive_.reset();
[email protected]365e821c2010-04-16 19:38:33361}
[email protected]882e27e2011-05-25 19:41:35362
[email protected]e7b18312013-01-04 12:17:18363void ChromeViewsDelegate::OnBeforeWidgetInit(
364 views::Widget::InitParams* params,
365 views::internal::NativeWidgetDelegate* delegate) {
[email protected]fe07d2b2013-12-18 10:18:38366 // We need to determine opacity if it's not already specified.
367 if (params->opacity == views::Widget::InitParams::INFER_OPACITY)
368 params->opacity = GetOpacityForInitParams(*params);
369
[email protected]e7b18312013-01-04 12:17:18370 // If we already have a native_widget, we don't have to try to come
371 // up with one.
372 if (params->native_widget)
373 return;
374
sky7fa479a2016-02-10 21:09:38375 if (!native_widget_factory().is_null()) {
376 params->native_widget = native_widget_factory().Run(*params, delegate);
377 if (params->native_widget)
378 return;
379 }
380
[email protected]0f440df2013-04-02 07:43:22381#if defined(USE_AURA) && !defined(OS_CHROMEOS)
382 bool use_non_toplevel_window =
[email protected]c3476482014-05-27 20:12:24383 params->parent &&
anantaa694c742016-01-13 00:26:13384#if defined(OS_WIN)
385 // Check the force_software_compositing flag only on Windows. If this
386 // flag is on, it means that the widget being created wants to use the
387 // software compositor which requires a top level window. We cannot have
388 // a mixture of compositors active in one view hierarchy.
ananta21d7aae22016-01-11 21:35:51389 !params->force_software_compositing &&
anantaa694c742016-01-13 00:26:13390#else
391 params->type != views::Widget::InitParams::TYPE_MENU &&
392#endif
[email protected]c3476482014-05-27 20:12:24393 params->type != views::Widget::InitParams::TYPE_TOOLTIP;
[email protected]4d9b0832013-06-14 06:25:37394
395#if defined(OS_WIN)
396 // On desktop Linux Chrome must run in an environment that supports a variety
397 // of window managers, some of which do not play nicely with parts of our UI
398 // that have specific expectations about window sizing and placement. For this
[email protected]f7e5d902014-05-22 19:56:31399 // reason windows opened as top level (!params.child) are always constrained
400 // by the browser frame, so we can position them correctly. This has some
401 // negative side effects, like dialogs being clipped by the browser frame, but
402 // the side effects are not as bad as the poor window manager interactions. On
403 // Windows however these WM interactions are not an issue, so we open windows
404 // requested as top_level as actual top level windows on the desktop.
scottmge0c631f2016-02-20 06:16:29405 use_non_toplevel_window = use_non_toplevel_window && params->child;
[email protected]4d9b0832013-06-14 06:25:37406
[email protected]e30ecf712013-11-01 23:21:09407 if (!ui::win::IsAeroGlassEnabled()) {
408 // If we don't have composition (either because Glass is not enabled or
409 // because it was disabled at the command line), anything that requires
410 // transparency will be broken with a toplevel window, so force the use of
411 // a non toplevel window.
412 if (params->opacity == views::Widget::InitParams::TRANSLUCENT_WINDOW &&
ananta21d7aae22016-01-11 21:35:51413 !params->force_software_compositing)
[email protected]e30ecf712013-11-01 23:21:09414 use_non_toplevel_window = true;
415 } else {
416 // If we're on Vista+ with composition enabled, then we can use toplevel
417 // windows for most things (they get blended via WS_EX_COMPOSITED, which
418 // allows for animation effects, but also exceeding the bounds of the parent
419 // window).
scottmgd12621f2016-03-18 16:14:27420 if (params->parent &&
[email protected]e30ecf712013-11-01 23:21:09421 params->type != views::Widget::InitParams::TYPE_CONTROL &&
422 params->type != views::Widget::InitParams::TYPE_WINDOW) {
423 // When we set this to false, we get a DesktopNativeWidgetAura from the
424 // default case (not handled in this function).
425 use_non_toplevel_window = false;
426 }
[email protected]0f440df2013-04-02 07:43:22427 }
428#endif // OS_WIN
Sadrul Habib Chowdhurycf536a32015-11-24 07:40:01429
430 if (!use_non_toplevel_window && !native_widget_factory().is_null()) {
431 params->native_widget = native_widget_factory().Run(*params, delegate);
432 return;
433 }
[email protected]0f440df2013-04-02 07:43:22434#endif // USE_AURA
435
scottmgd12621f2016-03-18 16:14:27436#if defined(OS_CHROMEOS) || defined(USE_ASH)
[email protected]2a2caa02013-01-22 20:50:36437 // When we are doing straight chromeos builds, we still need to handle the
438 // toplevel window case.
[email protected]1403ada92013-02-21 00:11:47439 // There may be a few remaining widgets in Chrome OS that are not top level,
440 // but have neither a context nor a parent. Provide a fallback context so
441 // users don't crash. Developers will hit the DCHECK and should provide a
442 // context.
[email protected]f8c094b82013-10-24 20:28:20443 if (params->context)
444 params->context = params->context->GetRootWindow();
[email protected]f7e5d902014-05-22 19:56:31445 DCHECK(params->parent || params->context || !params->child)
[email protected]391e6b72013-02-04 18:03:01446 << "Please provide a parent or context for this widget.";
447 if (!params->parent && !params->context)
[email protected]2a2caa02013-01-22 20:50:36448 params->context = ash::Shell::GetPrimaryRootWindow();
449#elif defined(USE_AURA)
[email protected]e7b18312013-01-04 12:17:18450 // While the majority of the time, context wasn't plumbed through due to the
sky28f20d62016-10-20 23:21:59451 // existence of a global WindowParentingClient, if this window is toplevel,
452 // it's possible that there is no contextual state that we can use.
[email protected]c3476482014-05-27 20:12:24453 if (params->parent == NULL && params->context == NULL && !params->child) {
scottmgd12621f2016-03-18 16:14:27454 params->native_widget = new views::DesktopNativeWidgetAura(delegate);
[email protected]0f440df2013-04-02 07:43:22455 } else if (use_non_toplevel_window) {
[email protected]98e0f0962014-04-24 23:42:11456 views::NativeWidgetAura* native_widget =
457 new views::NativeWidgetAura(delegate);
458 if (params->parent) {
459 Profile* parent_profile = reinterpret_cast<Profile*>(
460 params->parent->GetNativeWindowProperty(Profile::kProfileKey));
461 native_widget->SetNativeWindowProperty(Profile::kProfileKey,
462 parent_profile);
463 }
464 params->native_widget = native_widget;
[email protected]c3476482014-05-27 20:12:24465 } else {
scottmge0c631f2016-02-20 06:16:29466 params->native_widget = new views::DesktopNativeWidgetAura(delegate);
[email protected]e7b18312013-01-04 12:17:18467 }
468#endif
[email protected]2f0dcb62012-09-13 22:49:51469}
[email protected]01e06a32013-06-07 12:41:33470
[email protected]02abfee2014-01-23 09:27:02471#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
[email protected]e9fe8512014-04-21 21:27:08472bool ChromeViewsDelegate::WindowManagerProvidesTitleBar(bool maximized) {
[email protected]02abfee2014-01-23 09:27:02473 // On Ubuntu Unity, the system always provides a title bar for maximized
474 // windows.
475 views::LinuxUI* ui = views::LinuxUI::instance();
476 return maximized && ui && ui->UnityIsRunning();
[email protected]02abfee2014-01-23 09:27:02477}
[email protected]e9fe8512014-04-21 21:27:08478#endif
[email protected]02abfee2014-01-23 09:27:02479
[email protected]7c1913842014-05-19 18:06:39480ui::ContextFactory* ChromeViewsDelegate::GetContextFactory() {
481 return content::GetContextFactory();
482}
[email protected]7c1913842014-05-19 18:06:39483
fsamuela0bcfe12016-12-14 06:21:49484ui::ContextFactoryPrivate* ChromeViewsDelegate::GetContextFactoryPrivate() {
485 return content::GetContextFactoryPrivate();
486}
487
Dominic Mazzoni0e9bcce2015-03-16 20:51:09488std::string ChromeViewsDelegate::GetApplicationName() {
sdefresne9fb67692015-08-03 18:48:22489 return version_info::GetProductName();
Dominic Mazzoni0e9bcce2015-03-16 20:51:09490}
491
[email protected]6c52fef2014-04-22 20:26:53492#if defined(OS_WIN)
493int ChromeViewsDelegate::GetAppbarAutohideEdges(HMONITOR monitor,
494 const base::Closure& callback) {
495 // Initialize the map with EDGE_BOTTOM. This is important, as if we return an
496 // initial value of 0 (no auto-hide edges) then we'll go fullscreen and
497 // windows will automatically remove WS_EX_TOPMOST from the appbar resulting
498 // in us thinking there is no auto-hide edges. By returning at least one edge
499 // we don't initially go fullscreen until we figure out the real auto-hide
500 // edges.
501 if (!appbar_autohide_edge_map_.count(monitor))
502 appbar_autohide_edge_map_[monitor] = EDGE_BOTTOM;
anantaabe5bdc2016-12-03 03:32:47503
504 // We use the SHAppBarMessage API to get the taskbar autohide state. This API
505 // spins a modal loop which could cause callers to be reentered. To avoid
506 // that we retrieve the taskbar state in a worker thread.
[email protected]6c52fef2014-04-22 20:26:53507 if (monitor && !in_autohide_edges_callback_) {
508 base::PostTaskAndReplyWithResult(
509 content::BrowserThread::GetBlockingPool(),
510 FROM_HERE,
511 base::Bind(&GetAppbarAutohideEdgesOnWorkerThread,
512 monitor),
513 base::Bind(&ChromeViewsDelegate::OnGotAppbarAutohideEdges,
514 weak_factory_.GetWeakPtr(),
515 callback,
516 monitor,
517 appbar_autohide_edge_map_[monitor]));
518 }
519 return appbar_autohide_edge_map_[monitor];
520}
521
522void ChromeViewsDelegate::OnGotAppbarAutohideEdges(
523 const base::Closure& callback,
524 HMONITOR monitor,
525 int returned_edges,
526 int edges) {
527 appbar_autohide_edge_map_[monitor] = edges;
528 if (returned_edges == edges)
529 return;
530
531 base::AutoReset<bool> in_callback_setter(&in_autohide_edges_callback_, true);
532 callback.Run();
533}
534#endif
535
robliao57e58c22015-05-23 00:58:30536scoped_refptr<base::TaskRunner>
537ChromeViewsDelegate::GetBlockingPoolTaskRunner() {
538 return content::BrowserThread::GetBlockingPool();
539}
540
ellyjones50ef64e2016-11-22 19:48:13541gfx::Insets ChromeViewsDelegate::GetDialogButtonInsets() {
542 if (ui::MaterialDesignController::IsSecondaryUiMaterial())
543 return gfx::Insets(HarmonyLayoutDelegate::kHarmonyLayoutUnit);
544 return ViewsDelegate::GetDialogButtonInsets();
545}
546
547int ChromeViewsDelegate::GetDialogRelatedButtonHorizontalSpacing() {
548 if (ui::MaterialDesignController::IsSecondaryUiMaterial())
549 return HarmonyLayoutDelegate::kHarmonyLayoutUnit / 2;
550 return ViewsDelegate::GetDialogRelatedButtonHorizontalSpacing();
551}
552
kylixrd44ec2a4f2017-01-10 21:03:16553int ChromeViewsDelegate::GetDialogRelatedControlVerticalSpacing() {
554 if (ui::MaterialDesignController::IsSecondaryUiMaterial())
555 return HarmonyLayoutDelegate::kHarmonyLayoutUnit / 2;
556 return ViewsDelegate::GetDialogRelatedControlVerticalSpacing();
557}
558
ellyjones9bf7c5862016-12-07 18:22:05559gfx::Insets ChromeViewsDelegate::GetDialogFrameViewInsets() {
kylixrd44ec2a4f2017-01-10 21:03:16560 if (ui::MaterialDesignController::IsSecondaryUiMaterial())
ellyjones9bf7c5862016-12-07 18:22:05561 // Titles are inset at the top and sides, but not at the bottom.
562 return gfx::Insets(HarmonyLayoutDelegate::kHarmonyLayoutUnit,
563 HarmonyLayoutDelegate::kHarmonyLayoutUnit, 0,
564 HarmonyLayoutDelegate::kHarmonyLayoutUnit);
ellyjones9bf7c5862016-12-07 18:22:05565 return ViewsDelegate::GetDialogFrameViewInsets();
566}
567
kylixrd44ec2a4f2017-01-10 21:03:16568gfx::Insets ChromeViewsDelegate::GetBubbleDialogMargins() {
569 if (ui::MaterialDesignController::IsSecondaryUiMaterial())
570 return gfx::Insets(HarmonyLayoutDelegate::kHarmonyLayoutUnit);
571 return ViewsDelegate::GetBubbleDialogMargins();
572}
573
bshea1838dc2015-11-18 22:38:35574#if !defined(USE_ASH)
[email protected]fe07d2b2013-12-18 10:18:38575views::Widget::InitParams::WindowOpacity
576ChromeViewsDelegate::GetOpacityForInitParams(
577 const views::Widget::InitParams& params) {
578 return views::Widget::InitParams::OPAQUE_WINDOW;
579}
580#endif