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
&&
45 other
.small_icon
== small_icon
);
49 // WARNING: this class may be used on multiple threads.
50 class 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
);
63 // Represents a registered window class.
64 struct RegisteredClass
{
65 RegisteredClass(const ClassInfo
& info
,
66 const base::string16
& name
,
70 // Info used to create the class.
73 // The name given to the window class
76 // The atom identifying the window class.
79 // The handle of the module containing the window proceedure.
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_
;
94 DISALLOW_COPY_AND_ASSIGN(ClassRegistrar
);
97 ClassRegistrar::~ClassRegistrar() {}
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
);
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
))
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
));
145 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo
& info
,
146 const base::string16
& name
,
152 instance(instance
) {}
154 ClassRegistrar::ClassRegistrar() : registered_count_(0) {}
157 ///////////////////////////////////////////////////////////////////////////////
158 // WindowImpl, public
160 WindowImpl::WindowImpl()
162 window_ex_style_(kWindowDefaultExStyle
),
163 class_style_(CS_DBLCLKS
),
166 got_valid_hwnd_(false),
170 WindowImpl::~WindowImpl() {
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
;
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
),
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
);
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 {
257 HICON
WindowImpl::GetSmallWindowIcon() const {
261 LRESULT
WindowImpl::OnWndProc(UINT message
, WPARAM w_param
, LPARAM l_param
) {
265 if (message
== WM_NCDESTROY
)
268 // Handle the message if it's in our message map; otherwise, let the system
270 if (!ProcessWindowMessage(hwnd
, message
, w_param
, l_param
, result
))
271 result
= DefWindowProc(hwnd
, message
, w_param
, l_param
);
276 void WindowImpl::ClearUserData() {
277 if (::IsWindow(hwnd_
))
278 gfx::SetWindowUserData(hwnd_
, NULL
);
282 LRESULT CALLBACK
WindowImpl::WndProc(HWND hwnd
,
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
);
294 gfx::SetWindowUserData(hwnd
, window
);
295 window
->hwnd_
= hwnd
;
296 window
->got_create_
= true;
298 window
->got_valid_hwnd_
= true;
302 WindowImpl
* window
= reinterpret_cast<WindowImpl
*>(GetWindowUserData(hwnd
));
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
);