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"
9 #include "base/debug/alias.h"
10 #include "base/memory/singleton.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/synchronization/lock.h"
13 #include "base/win/wrapped_window_proc.h"
14 #include "ui/gfx/win/hwnd_util.h"
18 static const DWORD kWindowDefaultChildStyle
=
19 WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
;
20 static const DWORD kWindowDefaultStyle
= WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
;
21 static const DWORD kWindowDefaultExStyle
= 0;
23 ///////////////////////////////////////////////////////////////////////////////
24 // WindowImpl class tracking.
26 // Several external scripts rely explicitly on this base class name for
27 // acquiring the window handle and will break if this is modified!
29 const wchar_t* const WindowImpl::kBaseClassName
= L
"Chrome_WidgetWin_";
31 // WindowImpl class information used for registering unique windows.
36 ClassInfo(int style
, HICON icon
)
40 // Compares two ClassInfos. Returns true if all members match.
41 bool Equals(const ClassInfo
& other
) const {
42 return (other
.style
== style
&& other
.icon
== icon
);
46 // WARNING: this class may be used on multiple threads.
47 class ClassRegistrar
{
51 static ClassRegistrar
* GetInstance();
53 // Returns the atom identifying the class matching |class_info|,
54 // creating and registering a new class if the class is not yet known.
55 ATOM
RetrieveClassAtom(const ClassInfo
& class_info
);
58 // Represents a registered window class.
59 struct RegisteredClass
{
60 RegisteredClass(const ClassInfo
& info
, ATOM atom
);
62 // Info used to create the class.
65 // The atom identifying the window class.
70 friend struct DefaultSingletonTraits
<ClassRegistrar
>;
72 typedef std::list
<RegisteredClass
> RegisteredClasses
;
73 RegisteredClasses registered_classes_
;
75 // Counter of how many classes have been registered so far.
76 int registered_count_
;
80 DISALLOW_COPY_AND_ASSIGN(ClassRegistrar
);
83 ClassRegistrar::~ClassRegistrar() {}
86 ClassRegistrar
* ClassRegistrar::GetInstance() {
87 return Singleton
<ClassRegistrar
,
88 LeakySingletonTraits
<ClassRegistrar
> >::get();
91 ATOM
ClassRegistrar::RetrieveClassAtom(const ClassInfo
& class_info
) {
92 base::AutoLock
auto_lock(lock_
);
93 for (RegisteredClasses::const_iterator i
= registered_classes_
.begin();
94 i
!= registered_classes_
.end(); ++i
) {
95 if (class_info
.Equals(i
->info
))
99 // No class found, need to register one.
100 base::string16 name
= base::string16(WindowImpl::kBaseClassName
) +
101 base::IntToString16(registered_count_
++);
103 WNDCLASSEX window_class
;
104 base::win::InitializeWindowClass(
106 &base::win::WrappedWindowProc
<WindowImpl::WndProc
>,
111 reinterpret_cast<HBRUSH
>(GetStockObject(BLACK_BRUSH
)),
116 HMODULE instance
= window_class
.hInstance
;
117 ATOM atom
= RegisterClassEx(&window_class
);
118 CHECK(atom
) << GetLastError();
120 registered_classes_
.push_back(RegisteredClass(class_info
, atom
));
125 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo
& info
,
130 ClassRegistrar::ClassRegistrar() : registered_count_(0) {}
133 ///////////////////////////////////////////////////////////////////////////////
134 // WindowImpl, public
136 WindowImpl::WindowImpl()
138 window_ex_style_(kWindowDefaultExStyle
),
139 class_style_(CS_DBLCLKS
),
142 got_valid_hwnd_(false),
146 WindowImpl::~WindowImpl() {
152 void WindowImpl::Init(HWND parent
, const Rect
& bounds
) {
153 if (window_style_
== 0)
154 window_style_
= parent
? kWindowDefaultChildStyle
: kWindowDefaultStyle
;
156 if (parent
== HWND_DESKTOP
) {
157 // Only non-child windows can have HWND_DESKTOP (0) as their parent.
158 CHECK((window_style_
& WS_CHILD
) == 0);
159 parent
= GetWindowToParentTo(false);
160 } else if (parent
== ::GetDesktopWindow()) {
161 // Any type of window can have the "Desktop Window" as their parent.
162 parent
= GetWindowToParentTo(true);
163 } else if (parent
!= HWND_MESSAGE
) {
164 CHECK(::IsWindow(parent
));
167 int x
, y
, width
, height
;
168 if (bounds
.IsEmpty()) {
169 x
= y
= width
= height
= CW_USEDEFAULT
;
173 width
= bounds
.width();
174 height
= bounds
.height();
177 ATOM atom
= GetWindowClassAtom();
178 bool destroyed
= false;
179 destroyed_
= &destroyed
;
180 HWND hwnd
= CreateWindowEx(window_ex_style_
,
181 reinterpret_cast<wchar_t*>(atom
), NULL
,
182 window_style_
, x
, y
, width
, height
,
183 parent
, NULL
, NULL
, this);
185 // First nccalcszie (during CreateWindow) for captioned windows is
186 // deliberately ignored so force a second one here to get the right
187 // non-client set up.
188 if (hwnd
&& (window_style_
& WS_CAPTION
)) {
189 SetWindowPos(hwnd
, NULL
, 0, 0, 0, 0,
190 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
|
191 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
194 if (!hwnd_
&& GetLastError() == 0) {
195 base::debug::Alias(&destroyed
);
196 base::debug::Alias(&hwnd
);
197 bool got_create
= got_create_
;
198 base::debug::Alias(&got_create
);
199 bool got_valid_hwnd
= got_valid_hwnd_
;
200 base::debug::Alias(&got_valid_hwnd
);
201 WNDCLASSEX class_info
;
202 memset(&class_info
, 0, sizeof(WNDCLASSEX
));
203 class_info
.cbSize
= sizeof(WNDCLASSEX
);
204 BOOL got_class
= GetClassInfoEx(GetModuleHandle(NULL
),
205 reinterpret_cast<wchar_t*>(atom
),
207 base::debug::Alias(&got_class
);
208 bool procs_match
= got_class
&& class_info
.lpfnWndProc
==
209 base::win::WrappedWindowProc
<&WindowImpl::WndProc
>;
210 base::debug::Alias(&procs_match
);
216 CheckWindowCreated(hwnd_
);
218 // The window procedure should have set the data for us.
219 CHECK_EQ(this, GetWindowUserData(hwnd
));
222 HICON
WindowImpl::GetDefaultWindowIcon() const {
226 LRESULT
WindowImpl::OnWndProc(UINT message
, WPARAM w_param
, LPARAM l_param
) {
230 if (message
== WM_NCDESTROY
)
233 // Handle the message if it's in our message map; otherwise, let the system
235 if (!ProcessWindowMessage(hwnd
, message
, w_param
, l_param
, result
))
236 result
= DefWindowProc(hwnd
, message
, w_param
, l_param
);
241 void WindowImpl::ClearUserData() {
242 if (::IsWindow(hwnd_
))
243 gfx::SetWindowUserData(hwnd_
, NULL
);
247 LRESULT CALLBACK
WindowImpl::WndProc(HWND hwnd
,
251 if (message
== WM_NCCREATE
) {
252 CREATESTRUCT
* cs
= reinterpret_cast<CREATESTRUCT
*>(l_param
);
253 WindowImpl
* window
= reinterpret_cast<WindowImpl
*>(cs
->lpCreateParams
);
255 gfx::SetWindowUserData(hwnd
, window
);
256 window
->hwnd_
= hwnd
;
257 window
->got_create_
= true;
259 window
->got_valid_hwnd_
= true;
263 WindowImpl
* window
= reinterpret_cast<WindowImpl
*>(GetWindowUserData(hwnd
));
267 return window
->OnWndProc(message
, w_param
, l_param
);
270 ATOM
WindowImpl::GetWindowClassAtom() {
271 HICON icon
= GetDefaultWindowIcon();
272 ClassInfo
class_info(initial_class_style(), icon
);
273 return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info
);