• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gfx/win/window_impl.h"
6 
7 #include <list>
8 
9 #include "base/bind.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"
16 
17 namespace gfx {
18 
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;
23 
24 ///////////////////////////////////////////////////////////////////////////////
25 // WindowImpl class tracking.
26 
27 // Several external scripts rely explicitly on this base class name for
28 // acquiring the window handle and will break if this is modified!
29 // static
30 const wchar_t* const WindowImpl::kBaseClassName = L"Chrome_WidgetWin_";
31 
32 // WindowImpl class information used for registering unique windows.
33 struct ClassInfo {
34   UINT style;
35   HICON icon;
36 
ClassInfogfx::ClassInfo37   ClassInfo(int style, HICON icon)
38       : style(style),
39         icon(icon) {}
40 
41   // Compares two ClassInfos. Returns true if all members match.
Equalsgfx::ClassInfo42   bool Equals(const ClassInfo& other) const {
43     return (other.style == style && other.icon == icon);
44   }
45 };
46 
47 // WARNING: this class may be used on multiple threads.
48 class ClassRegistrar {
49  public:
50   ~ClassRegistrar();
51 
52   static ClassRegistrar* GetInstance();
53 
54   void UnregisterClasses();
55 
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);
59 
60  private:
61   // Represents a registered window class.
62   struct RegisteredClass {
63     RegisteredClass(const ClassInfo& info,
64                     const base::string16& name,
65                     ATOM atom,
66                     HINSTANCE instance);
67 
68     // Info used to create the class.
69     ClassInfo info;
70 
71     // The name given to the window class
72     base::string16 name;
73 
74     // The atom identifying the window class.
75     ATOM atom;
76 
77     // The handle of the module containing the window proceedure.
78     HMODULE instance;
79   };
80 
81   ClassRegistrar();
82   friend struct DefaultSingletonTraits<ClassRegistrar>;
83 
84   typedef std::list<RegisteredClass> RegisteredClasses;
85   RegisteredClasses registered_classes_;
86 
87   // Counter of how many classes have been registered so far.
88   int registered_count_;
89 
90   base::Lock lock_;
91 
92   DISALLOW_COPY_AND_ASSIGN(ClassRegistrar);
93 };
94 
~ClassRegistrar()95 ClassRegistrar::~ClassRegistrar() {}
96 
97 // static
GetInstance()98 ClassRegistrar* ClassRegistrar::GetInstance() {
99   return Singleton<ClassRegistrar,
100       LeakySingletonTraits<ClassRegistrar> >::get();
101 }
102 
UnregisterClasses()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);
108      } else {
109        LOG(ERROR) << "Failed to unregister class " << i->name
110                   << ". Error = " << GetLastError();
111      }
112    }
113 }
114 
RetrieveClassAtom(const ClassInfo & class_info)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))
120       return i->atom;
121   }
122 
123   // No class found, need to register one.
124   base::string16 name = base::string16(WindowImpl::kBaseClassName) +
125       base::IntToString16(registered_count_++);
126 
127   WNDCLASSEX window_class;
128   base::win::InitializeWindowClass(
129       name.c_str(),
130       &base::win::WrappedWindowProc<WindowImpl::WndProc>,
131       class_info.style,
132       0,
133       0,
134       NULL,
135       reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)),
136       NULL,
137       class_info.icon,
138       class_info.icon,
139       &window_class);
140   HMODULE instance = window_class.hInstance;
141   ATOM atom = RegisterClassEx(&window_class);
142   CHECK(atom) << GetLastError();
143 
144   registered_classes_.push_back(RegisteredClass(
145       class_info, name, atom, instance));
146 
147   return atom;
148 }
149 
RegisteredClass(const ClassInfo & info,const base::string16 & name,ATOM atom,HMODULE instance)150 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo& info,
151                                                  const base::string16& name,
152                                                  ATOM atom,
153                                                  HMODULE instance)
154     : info(info),
155       name(name),
156       atom(atom),
157       instance(instance) {}
158 
ClassRegistrar()159 ClassRegistrar::ClassRegistrar() : registered_count_(0) {}
160 
161 
162 ///////////////////////////////////////////////////////////////////////////////
163 // WindowImpl, public
164 
WindowImpl()165 WindowImpl::WindowImpl()
166     : window_style_(0),
167       window_ex_style_(kWindowDefaultExStyle),
168       class_style_(CS_DBLCLKS),
169       hwnd_(NULL),
170       got_create_(false),
171       got_valid_hwnd_(false),
172       destroyed_(NULL) {
173 }
174 
~WindowImpl()175 WindowImpl::~WindowImpl() {
176   if (destroyed_)
177     *destroyed_ = true;
178   ClearUserData();
179 }
180 
181 // static
UnregisterClassesAtExit()182 void WindowImpl::UnregisterClassesAtExit() {
183   base::AtExitManager::RegisterTask(
184       base::Bind(&ClassRegistrar::UnregisterClasses,
185                  base::Unretained(ClassRegistrar::GetInstance())));
186 }
187 
Init(HWND parent,const Rect & bounds)188 void WindowImpl::Init(HWND parent, const Rect& bounds) {
189   if (window_style_ == 0)
190     window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle;
191 
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));
201   }
202 
203   int x, y, width, height;
204   if (bounds.IsEmpty()) {
205     x = y = width = height = CW_USEDEFAULT;
206   } else {
207     x = bounds.x();
208     y = bounds.y();
209     width = bounds.width();
210     height = bounds.height();
211   }
212 
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);
220 
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);
228   }
229 
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),
242                                     &class_info);
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);
247     CHECK(false);
248   }
249   if (!destroyed)
250     destroyed_ = NULL;
251 
252   CheckWindowCreated(hwnd_);
253 
254   // The window procedure should have set the data for us.
255   CHECK_EQ(this, GetWindowUserData(hwnd));
256 }
257 
GetDefaultWindowIcon() const258 HICON WindowImpl::GetDefaultWindowIcon() const {
259   return NULL;
260 }
261 
OnWndProc(UINT message,WPARAM w_param,LPARAM l_param)262 LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) {
263   LRESULT result = 0;
264 
265   HWND hwnd = hwnd_;
266   if (message == WM_NCDESTROY)
267     hwnd_ = NULL;
268 
269   // Handle the message if it's in our message map; otherwise, let the system
270   // handle it.
271   if (!ProcessWindowMessage(hwnd, message, w_param, l_param, result))
272     result = DefWindowProc(hwnd, message, w_param, l_param);
273 
274   return result;
275 }
276 
ClearUserData()277 void WindowImpl::ClearUserData() {
278   if (::IsWindow(hwnd_))
279     gfx::SetWindowUserData(hwnd_, NULL);
280 }
281 
282 // static
WndProc(HWND hwnd,UINT message,WPARAM w_param,LPARAM l_param)283 LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd,
284                                      UINT message,
285                                      WPARAM w_param,
286                                      LPARAM l_param) {
287   if (message == WM_NCCREATE) {
288     CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param);
289     WindowImpl* window = reinterpret_cast<WindowImpl*>(cs->lpCreateParams);
290     DCHECK(window);
291     gfx::SetWindowUserData(hwnd, window);
292     window->hwnd_ = hwnd;
293     window->got_create_ = true;
294     if (hwnd)
295       window->got_valid_hwnd_ = true;
296     return TRUE;
297   }
298 
299   WindowImpl* window = reinterpret_cast<WindowImpl*>(GetWindowUserData(hwnd));
300   if (!window)
301     return 0;
302 
303   return window->OnWndProc(message, w_param, l_param);
304 }
305 
GetWindowClassAtom()306 ATOM WindowImpl::GetWindowClassAtom() {
307   HICON icon = GetDefaultWindowIcon();
308   ClassInfo class_info(initial_class_style(), icon);
309   return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info);
310 }
311 
312 }  // namespace gfx
313