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/strings/string_number_conversions.h"
13 #include "base/synchronization/lock.h"
14 #include "base/win/wrapped_window_proc.h"
15 #include "ui/gfx/win/hwnd_util.h"
19 static const DWORD kWindowDefaultChildStyle
=
20 WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
;
21 static const DWORD kWindowDefaultStyle
= WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
;
22 static const DWORD kWindowDefaultExStyle
= 0;
24 ///////////////////////////////////////////////////////////////////////////////
25 // WindowImpl class tracking.
27 // Several external scripts rely explicitly on this base class name for
28 // acquiring the window handle and will break if this is modified!
30 const wchar_t* const WindowImpl::kBaseClassName
= L
"Chrome_WidgetWin_";
32 // WindowImpl class information used for registering unique windows.
37 ClassInfo(int style
, HICON icon
)
41 // Compares two ClassInfos. Returns true if all members match.
42 bool Equals(const ClassInfo
& other
) const {
43 return (other
.style
== style
&& other
.icon
== icon
);
47 // WARNING: this class may be used on multiple threads.
48 class ClassRegistrar
{
52 static ClassRegistrar
* GetInstance();
54 void UnregisterClasses();
56 // Returns the atom identifying the class matching |class_info|,
57 // creating and registering a new class if the class is not yet known.
58 ATOM
RetrieveClassAtom(const ClassInfo
& class_info
);
61 // Represents a registered window class.
62 struct RegisteredClass
{
63 RegisteredClass(const ClassInfo
& info
,
64 const base::string16
& name
,
68 // Info used to create the class.
71 // The name given to the window class
74 // The atom identifying the window class.
77 // The handle of the module containing the window proceedure.
82 friend struct DefaultSingletonTraits
<ClassRegistrar
>;
84 typedef std::list
<RegisteredClass
> RegisteredClasses
;
85 RegisteredClasses registered_classes_
;
87 // Counter of how many classes have been registered so far.
88 int registered_count_
;
92 DISALLOW_COPY_AND_ASSIGN(ClassRegistrar
);
95 ClassRegistrar::~ClassRegistrar() {}
98 ClassRegistrar
* ClassRegistrar::GetInstance() {
99 return Singleton
<ClassRegistrar
,
100 LeakySingletonTraits
<ClassRegistrar
> >::get();
103 void ClassRegistrar::UnregisterClasses() {
104 for (RegisteredClasses::iterator i
= registered_classes_
.begin();
105 i
!= registered_classes_
.end(); ++i
) {
106 if (UnregisterClass(MAKEINTATOM(i
->atom
), i
->instance
)) {
107 registered_classes_
.erase(i
);
109 LOG(ERROR
) << "Failed to unregister class " << i
->name
110 << ". Error = " << GetLastError();
115 ATOM
ClassRegistrar::RetrieveClassAtom(const ClassInfo
& class_info
) {
116 base::AutoLock
auto_lock(lock_
);
117 for (RegisteredClasses::const_iterator i
= registered_classes_
.begin();
118 i
!= registered_classes_
.end(); ++i
) {
119 if (class_info
.Equals(i
->info
))
123 // No class found, need to register one.
124 base::string16 name
= base::string16(WindowImpl::kBaseClassName
) +
125 base::IntToString16(registered_count_
++);
127 WNDCLASSEX window_class
;
128 base::win::InitializeWindowClass(
130 &base::win::WrappedWindowProc
<WindowImpl::WndProc
>,
135 reinterpret_cast<HBRUSH
>(GetStockObject(BLACK_BRUSH
)),
140 HMODULE instance
= window_class
.hInstance
;
141 ATOM atom
= RegisterClassEx(&window_class
);
142 CHECK(atom
) << GetLastError();
144 registered_classes_
.push_back(RegisteredClass(
145 class_info
, name
, atom
, instance
));
150 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo
& info
,
151 const base::string16
& name
,
157 instance(instance
) {}
159 ClassRegistrar::ClassRegistrar() : registered_count_(0) {}
162 ///////////////////////////////////////////////////////////////////////////////
163 // WindowImpl, public
165 WindowImpl::WindowImpl()
167 window_ex_style_(kWindowDefaultExStyle
),
168 class_style_(CS_DBLCLKS
),
171 got_valid_hwnd_(false),
175 WindowImpl::~WindowImpl() {
182 void WindowImpl::UnregisterClassesAtExit() {
183 base::AtExitManager::RegisterTask(
184 base::Bind(&ClassRegistrar::UnregisterClasses
,
185 base::Unretained(ClassRegistrar::GetInstance())));
188 void WindowImpl::Init(HWND parent
, const Rect
& bounds
) {
189 if (window_style_
== 0)
190 window_style_
= parent
? kWindowDefaultChildStyle
: kWindowDefaultStyle
;
192 if (parent
== HWND_DESKTOP
) {
193 // Only non-child windows can have HWND_DESKTOP (0) as their parent.
194 CHECK((window_style_
& WS_CHILD
) == 0);
195 parent
= GetWindowToParentTo(false);
196 } else if (parent
== ::GetDesktopWindow()) {
197 // Any type of window can have the "Desktop Window" as their parent.
198 parent
= GetWindowToParentTo(true);
199 } else if (parent
!= HWND_MESSAGE
) {
200 CHECK(::IsWindow(parent
));
203 int x
, y
, width
, height
;
204 if (bounds
.IsEmpty()) {
205 x
= y
= width
= height
= CW_USEDEFAULT
;
209 width
= bounds
.width();
210 height
= bounds
.height();
213 ATOM atom
= GetWindowClassAtom();
214 bool destroyed
= false;
215 destroyed_
= &destroyed
;
216 HWND hwnd
= CreateWindowEx(window_ex_style_
,
217 reinterpret_cast<wchar_t*>(atom
), NULL
,
218 window_style_
, x
, y
, width
, height
,
219 parent
, NULL
, NULL
, this);
221 // First nccalcszie (during CreateWindow) for captioned windows is
222 // deliberately ignored so force a second one here to get the right
223 // non-client set up.
224 if (hwnd
&& (window_style_
& WS_CAPTION
)) {
225 SetWindowPos(hwnd
, NULL
, 0, 0, 0, 0,
226 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
|
227 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
230 if (!hwnd_
&& GetLastError() == 0) {
231 base::debug::Alias(&destroyed
);
232 base::debug::Alias(&hwnd
);
233 bool got_create
= got_create_
;
234 base::debug::Alias(&got_create
);
235 bool got_valid_hwnd
= got_valid_hwnd_
;
236 base::debug::Alias(&got_valid_hwnd
);
237 WNDCLASSEX class_info
;
238 memset(&class_info
, 0, sizeof(WNDCLASSEX
));
239 class_info
.cbSize
= sizeof(WNDCLASSEX
);
240 BOOL got_class
= GetClassInfoEx(GetModuleHandle(NULL
),
241 reinterpret_cast<wchar_t*>(atom
),
243 base::debug::Alias(&got_class
);
244 bool procs_match
= got_class
&& class_info
.lpfnWndProc
==
245 base::win::WrappedWindowProc
<&WindowImpl::WndProc
>;
246 base::debug::Alias(&procs_match
);
252 CheckWindowCreated(hwnd_
);
254 // The window procedure should have set the data for us.
255 CHECK_EQ(this, GetWindowUserData(hwnd
));
258 HICON
WindowImpl::GetDefaultWindowIcon() const {
262 LRESULT
WindowImpl::OnWndProc(UINT message
, WPARAM w_param
, LPARAM l_param
) {
266 if (message
== WM_NCDESTROY
)
269 // Handle the message if it's in our message map; otherwise, let the system
271 if (!ProcessWindowMessage(hwnd
, message
, w_param
, l_param
, result
))
272 result
= DefWindowProc(hwnd
, message
, w_param
, l_param
);
277 void WindowImpl::ClearUserData() {
278 if (::IsWindow(hwnd_
))
279 gfx::SetWindowUserData(hwnd_
, NULL
);
283 LRESULT CALLBACK
WindowImpl::WndProc(HWND hwnd
,
287 if (message
== WM_NCCREATE
) {
288 CREATESTRUCT
* cs
= reinterpret_cast<CREATESTRUCT
*>(l_param
);
289 WindowImpl
* window
= reinterpret_cast<WindowImpl
*>(cs
->lpCreateParams
);
291 gfx::SetWindowUserData(hwnd
, window
);
292 window
->hwnd_
= hwnd
;
293 window
->got_create_
= true;
295 window
->got_valid_hwnd_
= true;
299 WindowImpl
* window
= reinterpret_cast<WindowImpl
*>(GetWindowUserData(hwnd
));
303 return window
->OnWndProc(message
, w_param
, l_param
);
306 ATOM
WindowImpl::GetWindowClassAtom() {
307 HICON icon
= GetDefaultWindowIcon();
308 ClassInfo
class_info(initial_class_style(), icon
);
309 return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info
);