Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / ui / gfx / win / window_impl.cc
blob97da6f94f86f9c537683e9b70d6635b3bb9c68c8
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 "ui/gfx/win/window_impl.h"
7 #include <list>
9 #include "base/bind.h"
10 #include "base/debug/alias.h"
11 #include "base/memory/singleton.h"
12 #include "base/profiler/scoped_tracker.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/synchronization/lock.h"
15 #include "base/win/wrapped_window_proc.h"
16 #include "ui/gfx/win/hwnd_util.h"
18 namespace gfx {
20 static const DWORD kWindowDefaultChildStyle =
21 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
22 static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
23 static const DWORD kWindowDefaultExStyle = 0;
25 ///////////////////////////////////////////////////////////////////////////////
26 // WindowImpl class tracking.
28 // Several external scripts rely explicitly on this base class name for
29 // acquiring the window handle and will break if this is modified!
30 // static
31 const wchar_t* const WindowImpl::kBaseClassName = L"Chrome_WidgetWin_";
33 // WindowImpl class information used for registering unique windows.
34 struct ClassInfo {
35 UINT style;
36 HICON icon;
37 HICON small_icon;
39 ClassInfo(int style, HICON icon, HICON small_icon)
40 : style(style), icon(icon), small_icon(small_icon) {}
42 // Compares two ClassInfos. Returns true if all members match.
43 bool Equals(const ClassInfo& other) const {
44 return (other.style == style && other.icon == icon &&
45 other.small_icon == small_icon);
49 // WARNING: this class may be used on multiple threads.
50 class ClassRegistrar {
51 public:
52 ~ClassRegistrar();
54 static ClassRegistrar* GetInstance();
56 void UnregisterClasses();
58 // Returns the atom identifying the class matching |class_info|,
59 // creating and registering a new class if the class is not yet known.
60 ATOM RetrieveClassAtom(const ClassInfo& class_info);
62 private:
63 // Represents a registered window class.
64 struct RegisteredClass {
65 RegisteredClass(const ClassInfo& info,
66 const base::string16& name,
67 ATOM atom,
68 HINSTANCE instance);
70 // Info used to create the class.
71 ClassInfo info;
73 // The name given to the window class
74 base::string16 name;
76 // The atom identifying the window class.
77 ATOM atom;
79 // The handle of the module containing the window proceedure.
80 HMODULE instance;
83 ClassRegistrar();
84 friend struct DefaultSingletonTraits<ClassRegistrar>;
86 typedef std::list<RegisteredClass> RegisteredClasses;
87 RegisteredClasses registered_classes_;
89 // Counter of how many classes have been registered so far.
90 int registered_count_;
92 base::Lock lock_;
94 DISALLOW_COPY_AND_ASSIGN(ClassRegistrar);
97 ClassRegistrar::~ClassRegistrar() {}
99 // static
100 ClassRegistrar* ClassRegistrar::GetInstance() {
101 return Singleton<ClassRegistrar,
102 LeakySingletonTraits<ClassRegistrar> >::get();
105 void ClassRegistrar::UnregisterClasses() {
106 for (RegisteredClasses::iterator i = registered_classes_.begin();
107 i != registered_classes_.end(); ++i) {
108 if (UnregisterClass(MAKEINTATOM(i->atom), i->instance)) {
109 registered_classes_.erase(i);
110 } else {
111 LOG(ERROR) << "Failed to unregister class " << i->name
112 << ". Error = " << GetLastError();
117 ATOM ClassRegistrar::RetrieveClassAtom(const ClassInfo& class_info) {
118 base::AutoLock auto_lock(lock_);
119 for (RegisteredClasses::const_iterator i = registered_classes_.begin();
120 i != registered_classes_.end(); ++i) {
121 if (class_info.Equals(i->info))
122 return i->atom;
125 // No class found, need to register one.
126 base::string16 name = base::string16(WindowImpl::kBaseClassName) +
127 base::IntToString16(registered_count_++);
129 WNDCLASSEX window_class;
130 base::win::InitializeWindowClass(
131 name.c_str(), &base::win::WrappedWindowProc<WindowImpl::WndProc>,
132 class_info.style, 0, 0, NULL,
133 reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), NULL,
134 class_info.icon, class_info.small_icon, &window_class);
135 HMODULE instance = window_class.hInstance;
136 ATOM atom = RegisterClassEx(&window_class);
137 CHECK(atom) << GetLastError();
139 registered_classes_.push_back(RegisteredClass(
140 class_info, name, atom, instance));
142 return atom;
145 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo& info,
146 const base::string16& name,
147 ATOM atom,
148 HMODULE instance)
149 : info(info),
150 name(name),
151 atom(atom),
152 instance(instance) {}
154 ClassRegistrar::ClassRegistrar() : registered_count_(0) {}
157 ///////////////////////////////////////////////////////////////////////////////
158 // WindowImpl, public
160 WindowImpl::WindowImpl()
161 : window_style_(0),
162 window_ex_style_(kWindowDefaultExStyle),
163 class_style_(CS_DBLCLKS),
164 hwnd_(NULL),
165 got_create_(false),
166 got_valid_hwnd_(false),
167 destroyed_(NULL) {
170 WindowImpl::~WindowImpl() {
171 if (destroyed_)
172 *destroyed_ = true;
173 ClearUserData();
176 // static
177 void WindowImpl::UnregisterClassesAtExit() {
178 base::AtExitManager::RegisterTask(
179 base::Bind(&ClassRegistrar::UnregisterClasses,
180 base::Unretained(ClassRegistrar::GetInstance())));
183 void WindowImpl::Init(HWND parent, const Rect& bounds) {
184 if (window_style_ == 0)
185 window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle;
187 if (parent == HWND_DESKTOP) {
188 // Only non-child windows can have HWND_DESKTOP (0) as their parent.
189 CHECK((window_style_ & WS_CHILD) == 0);
190 parent = GetWindowToParentTo(false);
191 } else if (parent == ::GetDesktopWindow()) {
192 // Any type of window can have the "Desktop Window" as their parent.
193 parent = GetWindowToParentTo(true);
194 } else if (parent != HWND_MESSAGE) {
195 CHECK(::IsWindow(parent));
198 int x, y, width, height;
199 if (bounds.IsEmpty()) {
200 x = y = width = height = CW_USEDEFAULT;
201 } else {
202 x = bounds.x();
203 y = bounds.y();
204 width = bounds.width();
205 height = bounds.height();
208 ATOM atom = GetWindowClassAtom();
209 bool destroyed = false;
210 destroyed_ = &destroyed;
211 HWND hwnd = CreateWindowEx(window_ex_style_,
212 reinterpret_cast<wchar_t*>(atom), NULL,
213 window_style_, x, y, width, height,
214 parent, NULL, NULL, this);
216 // First nccalcszie (during CreateWindow) for captioned windows is
217 // deliberately ignored so force a second one here to get the right
218 // non-client set up.
219 if (hwnd && (window_style_ & WS_CAPTION)) {
220 SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
221 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE |
222 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
225 if (!hwnd_ && GetLastError() == 0) {
226 base::debug::Alias(&destroyed);
227 base::debug::Alias(&hwnd);
228 bool got_create = got_create_;
229 base::debug::Alias(&got_create);
230 bool got_valid_hwnd = got_valid_hwnd_;
231 base::debug::Alias(&got_valid_hwnd);
232 WNDCLASSEX class_info;
233 memset(&class_info, 0, sizeof(WNDCLASSEX));
234 class_info.cbSize = sizeof(WNDCLASSEX);
235 BOOL got_class = GetClassInfoEx(GetModuleHandle(NULL),
236 reinterpret_cast<wchar_t*>(atom),
237 &class_info);
238 base::debug::Alias(&got_class);
239 bool procs_match = got_class && class_info.lpfnWndProc ==
240 base::win::WrappedWindowProc<&WindowImpl::WndProc>;
241 base::debug::Alias(&procs_match);
242 CHECK(false);
244 if (!destroyed)
245 destroyed_ = NULL;
247 CheckWindowCreated(hwnd_);
249 // The window procedure should have set the data for us.
250 CHECK_EQ(this, GetWindowUserData(hwnd));
253 HICON WindowImpl::GetDefaultWindowIcon() const {
254 return nullptr;
257 HICON WindowImpl::GetSmallWindowIcon() const {
258 return nullptr;
261 LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) {
262 LRESULT result = 0;
264 HWND hwnd = hwnd_;
265 if (message == WM_NCDESTROY)
266 hwnd_ = NULL;
268 // Handle the message if it's in our message map; otherwise, let the system
269 // handle it.
270 if (!ProcessWindowMessage(hwnd, message, w_param, l_param, result))
271 result = DefWindowProc(hwnd, message, w_param, l_param);
273 return result;
276 void WindowImpl::ClearUserData() {
277 if (::IsWindow(hwnd_))
278 gfx::SetWindowUserData(hwnd_, NULL);
281 // static
282 LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd,
283 UINT message,
284 WPARAM w_param,
285 LPARAM l_param) {
286 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
287 tracked_objects::ScopedTracker tracking_profile(
288 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 WindowImpl::WndProc"));
290 if (message == WM_NCCREATE) {
291 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param);
292 WindowImpl* window = reinterpret_cast<WindowImpl*>(cs->lpCreateParams);
293 DCHECK(window);
294 gfx::SetWindowUserData(hwnd, window);
295 window->hwnd_ = hwnd;
296 window->got_create_ = true;
297 if (hwnd)
298 window->got_valid_hwnd_ = true;
299 return TRUE;
302 WindowImpl* window = reinterpret_cast<WindowImpl*>(GetWindowUserData(hwnd));
303 if (!window)
304 return 0;
306 return window->OnWndProc(message, w_param, l_param);
309 ATOM WindowImpl::GetWindowClassAtom() {
310 HICON icon = GetDefaultWindowIcon();
311 HICON small_icon = GetSmallWindowIcon();
312 ClassInfo class_info(initial_class_style(), icon, small_icon);
313 return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info);
316 } // namespace gfx