• 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/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"
15 
16 namespace gfx {
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 
ClassInfogfx::ClassInfo36   ClassInfo(int style, HICON icon)
37       : style(style),
38         icon(icon) {}
39 
40   // Compares two ClassInfos. Returns true if all members match.
Equalsgfx::ClassInfo41   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 
~ClassRegistrar()83 ClassRegistrar::~ClassRegistrar() {}
84 
85 // static
GetInstance()86 ClassRegistrar* ClassRegistrar::GetInstance() {
87   return Singleton<ClassRegistrar,
88                    LeakySingletonTraits<ClassRegistrar> >::get();
89 }
90 
RetrieveClassAtom(const ClassInfo & class_info)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   base::string16 name = base::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       reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)),
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 
RegisteredClass(const ClassInfo & info,ATOM atom)125 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo& info,
126                                                  ATOM atom)
127     : info(info),
128       atom(atom) {}
129 
ClassRegistrar()130 ClassRegistrar::ClassRegistrar() : registered_count_(0) {}
131 
132 
133 ///////////////////////////////////////////////////////////////////////////////
134 // WindowImpl, public
135 
WindowImpl()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 
~WindowImpl()146 WindowImpl::~WindowImpl() {
147   if (destroyed_)
148     *destroyed_ = true;
149   ClearUserData();
150 }
151 
Init(HWND parent,const Rect & bounds)152 void WindowImpl::Init(HWND parent, const 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, GetWindowUserData(hwnd));
220 }
221 
GetDefaultWindowIcon() const222 HICON WindowImpl::GetDefaultWindowIcon() const {
223   return NULL;
224 }
225 
OnWndProc(UINT message,WPARAM w_param,LPARAM l_param)226 LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) {
227   LRESULT result = 0;
228 
229   HWND hwnd = hwnd_;
230   if (message == WM_NCDESTROY)
231     hwnd_ = NULL;
232 
233   // Handle the message if it's in our message map; otherwise, let the system
234   // handle it.
235   if (!ProcessWindowMessage(hwnd, message, w_param, l_param, result))
236     result = DefWindowProc(hwnd, message, w_param, l_param);
237 
238   return result;
239 }
240 
ClearUserData()241 void WindowImpl::ClearUserData() {
242   if (::IsWindow(hwnd_))
243     gfx::SetWindowUserData(hwnd_, NULL);
244 }
245 
246 // static
WndProc(HWND hwnd,UINT message,WPARAM w_param,LPARAM l_param)247 LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd,
248                                      UINT message,
249                                      WPARAM w_param,
250                                      LPARAM l_param) {
251   if (message == WM_NCCREATE) {
252     CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param);
253     WindowImpl* window = reinterpret_cast<WindowImpl*>(cs->lpCreateParams);
254     DCHECK(window);
255     gfx::SetWindowUserData(hwnd, window);
256     window->hwnd_ = hwnd;
257     window->got_create_ = true;
258     if (hwnd)
259       window->got_valid_hwnd_ = true;
260     return TRUE;
261   }
262 
263   WindowImpl* window = reinterpret_cast<WindowImpl*>(GetWindowUserData(hwnd));
264   if (!window)
265     return 0;
266 
267   return window->OnWndProc(message, w_param, l_param);
268 }
269 
GetWindowClassAtom()270 ATOM WindowImpl::GetWindowClassAtom() {
271   HICON icon = GetDefaultWindowIcon();
272   ClassInfo class_info(initial_class_style(), icon);
273   return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info);
274 }
275 
276 }  // namespace gfx
277