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"
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"
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!
31 const wchar_t* const WindowImpl::kBaseClassName
= L
"Chrome_WidgetWin_";
33 // WindowImpl class information used for registering unique windows.
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
);
48 // WARNING: this class may be used on multiple threads.
49 class ClassRegistrar
{
53 static ClassRegistrar
* GetInstance();
55 void UnregisterClasses();
57 // Returns the atom identifying the class matching |class_info|,
58 // creating and registering a new class if the class is not yet known.
59 ATOM
RetrieveClassAtom(const ClassInfo
& class_info
);
62 // Represents a registered window class.
63 struct RegisteredClass
{
64 RegisteredClass(const ClassInfo
& info
,
65 const base::string16
& name
,
69 // Info used to create the class.
72 // The name given to the window class
75 // The atom identifying the window class.
78 // The handle of the module containing the window proceedure.
83 friend struct DefaultSingletonTraits
<ClassRegistrar
>;
85 typedef std::list
<RegisteredClass
> RegisteredClasses
;
86 RegisteredClasses registered_classes_
;
88 // Counter of how many classes have been registered so far.
89 int registered_count_
;
93 DISALLOW_COPY_AND_ASSIGN(ClassRegistrar
);
96 ClassRegistrar::~ClassRegistrar() {}
99 ClassRegistrar
* ClassRegistrar::GetInstance() {
100 return Singleton
<ClassRegistrar
,
101 LeakySingletonTraits
<ClassRegistrar
> >::get();
104 void ClassRegistrar::UnregisterClasses() {
105 for (RegisteredClasses::iterator i
= registered_classes_
.begin();
106 i
!= registered_classes_
.end(); ++i
) {
107 if (UnregisterClass(MAKEINTATOM(i
->atom
), i
->instance
)) {
108 registered_classes_
.erase(i
);
110 LOG(ERROR
) << "Failed to unregister class " << i
->name
111 << ". Error = " << GetLastError();
116 ATOM
ClassRegistrar::RetrieveClassAtom(const ClassInfo
& class_info
) {
117 base::AutoLock
auto_lock(lock_
);
118 for (RegisteredClasses::const_iterator i
= registered_classes_
.begin();
119 i
!= registered_classes_
.end(); ++i
) {
120 if (class_info
.Equals(i
->info
))
124 // No class found, need to register one.
125 base::string16 name
= base::string16(WindowImpl::kBaseClassName
) +
126 base::IntToString16(registered_count_
++);
128 WNDCLASSEX window_class
;
129 base::win::InitializeWindowClass(
130 name
.c_str(), &base::win::WrappedWindowProc
<WindowImpl::WndProc
>,
131 class_info
.style
, 0, 0, NULL
,
132 reinterpret_cast<HBRUSH
>(GetStockObject(BLACK_BRUSH
)), NULL
,
133 class_info
.icon
, class_info
.small_icon
, &window_class
);
134 HMODULE instance
= window_class
.hInstance
;
135 ATOM atom
= RegisterClassEx(&window_class
);
136 CHECK(atom
) << GetLastError();
138 registered_classes_
.push_back(RegisteredClass(
139 class_info
, name
, atom
, instance
));
144 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo
& info
,
145 const base::string16
& name
,
151 instance(instance
) {}
153 ClassRegistrar::ClassRegistrar() : registered_count_(0) {}
156 ///////////////////////////////////////////////////////////////////////////////
157 // WindowImpl, public
159 WindowImpl::WindowImpl()
161 window_ex_style_(kWindowDefaultExStyle
),
162 class_style_(CS_DBLCLKS
),
165 got_valid_hwnd_(false),
169 WindowImpl::~WindowImpl() {
176 void WindowImpl::UnregisterClassesAtExit() {
177 base::AtExitManager::RegisterTask(
178 base::Bind(&ClassRegistrar::UnregisterClasses
,
179 base::Unretained(ClassRegistrar::GetInstance())));
182 void WindowImpl::Init(HWND parent
, const Rect
& bounds
) {
183 if (window_style_
== 0)
184 window_style_
= parent
? kWindowDefaultChildStyle
: kWindowDefaultStyle
;
186 if (parent
== HWND_DESKTOP
) {
187 // Only non-child windows can have HWND_DESKTOP (0) as their parent.
188 CHECK((window_style_
& WS_CHILD
) == 0);
189 parent
= GetWindowToParentTo(false);
190 } else if (parent
== ::GetDesktopWindow()) {
191 // Any type of window can have the "Desktop Window" as their parent.
192 parent
= GetWindowToParentTo(true);
193 } else if (parent
!= HWND_MESSAGE
) {
194 CHECK(::IsWindow(parent
));
197 int x
, y
, width
, height
;
198 if (bounds
.IsEmpty()) {
199 x
= y
= width
= height
= CW_USEDEFAULT
;
203 width
= bounds
.width();
204 height
= bounds
.height();
207 ATOM atom
= GetWindowClassAtom();
208 bool destroyed
= false;
209 destroyed_
= &destroyed
;
210 HWND hwnd
= CreateWindowEx(window_ex_style_
,
211 reinterpret_cast<wchar_t*>(atom
), NULL
,
212 window_style_
, x
, y
, width
, height
,
213 parent
, NULL
, NULL
, this);
215 // First nccalcszie (during CreateWindow) for captioned windows is
216 // deliberately ignored so force a second one here to get the right
217 // non-client set up.
218 if (hwnd
&& (window_style_
& WS_CAPTION
)) {
219 SetWindowPos(hwnd
, NULL
, 0, 0, 0, 0,
220 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
|
221 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
224 if (!hwnd_
&& GetLastError() == 0) {
225 base::debug::Alias(&destroyed
);
226 base::debug::Alias(&hwnd
);
227 bool got_create
= got_create_
;
228 base::debug::Alias(&got_create
);
229 bool got_valid_hwnd
= got_valid_hwnd_
;
230 base::debug::Alias(&got_valid_hwnd
);
231 WNDCLASSEX class_info
;
232 memset(&class_info
, 0, sizeof(WNDCLASSEX
));
233 class_info
.cbSize
= sizeof(WNDCLASSEX
);
234 BOOL got_class
= GetClassInfoEx(GetModuleHandle(NULL
),
235 reinterpret_cast<wchar_t*>(atom
),
237 base::debug::Alias(&got_class
);
238 bool procs_match
= got_class
&& class_info
.lpfnWndProc
==
239 base::win::WrappedWindowProc
<&WindowImpl::WndProc
>;
240 base::debug::Alias(&procs_match
);
246 CheckWindowCreated(hwnd_
);
248 // The window procedure should have set the data for us.
249 CHECK_EQ(this, GetWindowUserData(hwnd
));
252 HICON
WindowImpl::GetDefaultWindowIcon() const {
256 HICON
WindowImpl::GetSmallWindowIcon() const {
260 LRESULT
WindowImpl::OnWndProc(UINT message
, WPARAM w_param
, LPARAM l_param
) {
261 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
262 tracked_objects::ScopedTracker
tracking_profile1(
263 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 WindowImpl DefWindowProc1"));
268 if (message
== WM_NCDESTROY
)
271 // Handle the message if it's in our message map; otherwise, let the system
273 if (!ProcessWindowMessage(hwnd
, message
, w_param
, l_param
, result
)) {
274 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
275 tracked_objects::ScopedTracker
tracking_profile2(
276 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 WindowImpl DefWindowProc2"));
278 result
= DefWindowProc(hwnd
, message
, w_param
, l_param
);
284 void WindowImpl::ClearUserData() {
285 if (::IsWindow(hwnd_
))
286 gfx::SetWindowUserData(hwnd_
, NULL
);
290 LRESULT CALLBACK
WindowImpl::WndProc(HWND hwnd
,
294 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
295 tracked_objects::ScopedTracker
tracking_profile(
296 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 WindowImpl::WndProc"));
298 if (message
== WM_NCCREATE
) {
299 CREATESTRUCT
* cs
= reinterpret_cast<CREATESTRUCT
*>(l_param
);
300 WindowImpl
* window
= reinterpret_cast<WindowImpl
*>(cs
->lpCreateParams
);
302 gfx::SetWindowUserData(hwnd
, window
);
303 window
->hwnd_
= hwnd
;
304 window
->got_create_
= true;
306 window
->got_valid_hwnd_
= true;
310 WindowImpl
* window
= reinterpret_cast<WindowImpl
*>(GetWindowUserData(hwnd
));
314 return window
->OnWndProc(message
, w_param
, l_param
);
317 ATOM
WindowImpl::GetWindowClassAtom() {
318 HICON icon
= GetDefaultWindowIcon();
319 HICON small_icon
= GetSmallWindowIcon();
320 ClassInfo
class_info(initial_class_style(), icon
, small_icon
);
321 return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info
);