OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "ui/base/win/window_impl.h" | |
6 | |
7 #include <list> | |
8 | |
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/base/win/hwnd_util.h" | |
15 | |
16 namespace ui { | |
17 | |
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; | |
22 | |
23 /////////////////////////////////////////////////////////////////////////////// | |
24 // WindowImpl class tracking. | |
25 | |
26 // Several external scripts rely explicitly on this base class name for | |
27 // acquiring the window handle and will break if this is modified! | |
28 // static | |
29 const wchar_t* const WindowImpl::kBaseClassName = L"Chrome_WidgetWin_"; | |
30 | |
31 // WindowImpl class information used for registering unique windows. | |
32 struct ClassInfo { | |
33 UINT style; | |
34 HICON icon; | |
35 | |
36 ClassInfo(int style, HICON icon) | |
37 : style(style), | |
38 icon(icon) {} | |
39 | |
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); | |
43 } | |
44 }; | |
45 | |
46 // WARNING: this class may be used on multiple threads. | |
47 class ClassRegistrar { | |
48 public: | |
49 ~ClassRegistrar(); | |
50 | |
51 static ClassRegistrar* GetInstance(); | |
52 | |
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); | |
56 | |
57 private: | |
58 // Represents a registered window class. | |
59 struct RegisteredClass { | |
60 RegisteredClass(const ClassInfo& info, ATOM atom); | |
61 | |
62 // Info used to create the class. | |
63 ClassInfo info; | |
64 | |
65 // The atom identifying the window class. | |
66 ATOM atom; | |
67 }; | |
68 | |
69 ClassRegistrar(); | |
70 friend struct DefaultSingletonTraits<ClassRegistrar>; | |
71 | |
72 typedef std::list<RegisteredClass> RegisteredClasses; | |
73 RegisteredClasses registered_classes_; | |
74 | |
75 // Counter of how many classes have been registered so far. | |
76 int registered_count_; | |
77 | |
78 base::Lock lock_; | |
79 | |
80 DISALLOW_COPY_AND_ASSIGN(ClassRegistrar); | |
81 }; | |
82 | |
83 ClassRegistrar::~ClassRegistrar() {} | |
84 | |
85 // static | |
86 ClassRegistrar* ClassRegistrar::GetInstance() { | |
87 return Singleton<ClassRegistrar, | |
88 LeakySingletonTraits<ClassRegistrar> >::get(); | |
89 } | |
90 | |
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)) | |
96 return i->atom; | |
97 } | |
98 | |
99 // No class found, need to register one. | |
100 string16 name = string16(WindowImpl::kBaseClassName) + | |
101 base::IntToString16(registered_count_++); | |
102 | |
103 WNDCLASSEX window_class; | |
104 base::win::InitializeWindowClass( | |
105 name.c_str(), | |
106 &base::win::WrappedWindowProc<WindowImpl::WndProc>, | |
107 class_info.style, | |
108 0, | |
109 0, | |
110 NULL, | |
111 NULL, | |
112 NULL, | |
113 class_info.icon, | |
114 class_info.icon, | |
115 &window_class); | |
116 HMODULE instance = window_class.hInstance; | |
117 ATOM atom = RegisterClassEx(&window_class); | |
118 CHECK(atom) << GetLastError(); | |
119 | |
120 registered_classes_.push_back(RegisteredClass(class_info, atom)); | |
121 | |
122 return atom; | |
123 } | |
124 | |
125 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo& info, | |
126 ATOM atom) | |
127 : info(info), | |
128 atom(atom) {} | |
129 | |
130 ClassRegistrar::ClassRegistrar() : registered_count_(0) {} | |
131 | |
132 | |
133 /////////////////////////////////////////////////////////////////////////////// | |
134 // WindowImpl, public | |
135 | |
136 WindowImpl::WindowImpl() | |
137 : window_style_(0), | |
138 window_ex_style_(kWindowDefaultExStyle), | |
139 class_style_(CS_DBLCLKS), | |
140 hwnd_(NULL), | |
141 got_create_(false), | |
142 got_valid_hwnd_(false), | |
143 destroyed_(NULL) { | |
144 } | |
145 | |
146 WindowImpl::~WindowImpl() { | |
147 if (destroyed_) | |
148 *destroyed_ = true; | |
149 ClearUserData(); | |
150 } | |
151 | |
152 void WindowImpl::Init(HWND parent, const gfx::Rect& bounds) { | |
153 if (window_style_ == 0) | |
154 window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle; | |
155 | |
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)); | |
165 } | |
166 | |
167 int x, y, width, height; | |
168 if (bounds.IsEmpty()) { | |
169 x = y = width = height = CW_USEDEFAULT; | |
170 } else { | |
171 x = bounds.x(); | |
172 y = bounds.y(); | |
173 width = bounds.width(); | |
174 height = bounds.height(); | |
175 } | |
176 | |
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); | |
184 | |
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); | |
192 } | |
193 | |
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), | |
206 &class_info); | |
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); | |
211 CHECK(false); | |
212 } | |
213 if (!destroyed) | |
214 destroyed_ = NULL; | |
215 | |
216 CheckWindowCreated(hwnd_); | |
217 | |
218 // The window procedure should have set the data for us. | |
219 CHECK_EQ(this, ui::GetWindowUserData(hwnd)); | |
220 } | |
221 | |
222 HICON WindowImpl::GetDefaultWindowIcon() const { | |
223 return NULL; | |
224 } | |
225 | |
226 LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) { | |
227 LRESULT result = 0; | |
228 | |
229 // Handle the message if it's in our message map; otherwise, let the system | |
230 // handle it. | |
231 if (!ProcessWindowMessage(hwnd_, message, w_param, l_param, result)) | |
232 result = DefWindowProc(hwnd_, message, w_param, l_param); | |
233 | |
234 return result; | |
235 } | |
236 | |
237 void WindowImpl::ClearUserData() { | |
238 if (::IsWindow(hwnd_)) | |
239 ui::SetWindowUserData(hwnd_, NULL); | |
240 } | |
241 | |
242 // static | |
243 LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, | |
244 UINT message, | |
245 WPARAM w_param, | |
246 LPARAM l_param) { | |
247 if (message == WM_NCCREATE) { | |
248 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param); | |
249 WindowImpl* window = reinterpret_cast<WindowImpl*>(cs->lpCreateParams); | |
250 DCHECK(window); | |
251 ui::SetWindowUserData(hwnd, window); | |
252 window->hwnd_ = hwnd; | |
253 window->got_create_ = true; | |
254 if (hwnd) | |
255 window->got_valid_hwnd_ = true; | |
256 return TRUE; | |
257 } | |
258 | |
259 WindowImpl* window = reinterpret_cast<WindowImpl*>( | |
260 ui::GetWindowUserData(hwnd)); | |
261 if (!window) | |
262 return 0; | |
263 | |
264 return window->OnWndProc(message, w_param, l_param); | |
265 } | |
266 | |
267 ATOM WindowImpl::GetWindowClassAtom() { | |
268 HICON icon = GetDefaultWindowIcon(); | |
269 ClassInfo class_info(initial_class_style(), icon); | |
270 return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info); | |
271 } | |
272 | |
273 } // namespace ui | |
OLD | NEW |