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 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 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 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 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 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 gfx::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 gfx::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*>(GetWindowUserData(hwnd)); 260 if (!window) 261 return 0; 262 263 return window->OnWndProc(message, w_param, l_param); 264 } 265 266 ATOM WindowImpl::GetWindowClassAtom() { 267 HICON icon = GetDefaultWindowIcon(); 268 ClassInfo class_info(initial_class_style(), icon); 269 return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info); 270 } 271 272 } // namespace gfx 273