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 HBRUSH background = NULL; 104 WNDCLASSEX window_class; 105 base::win::InitializeWindowClass( 106 name.c_str(), 107 &base::win::WrappedWindowProc<WindowImpl::WndProc>, 108 class_info.style, 109 0, 110 0, 111 NULL, 112 reinterpret_cast<HBRUSH>(background + 1), 113 NULL, 114 class_info.icon, 115 class_info.icon, 116 &window_class); 117 HMODULE instance = window_class.hInstance; 118 ATOM atom = RegisterClassEx(&window_class); 119 CHECK(atom) << GetLastError(); 120 121 registered_classes_.push_back(RegisteredClass(class_info, atom)); 122 123 return atom; 124 } 125 126 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo& info, 127 ATOM atom) 128 : info(info), 129 atom(atom) {} 130 131 ClassRegistrar::ClassRegistrar() : registered_count_(0) {} 132 133 134 /////////////////////////////////////////////////////////////////////////////// 135 // WindowImpl, public 136 137 WindowImpl::WindowImpl() 138 : window_style_(0), 139 window_ex_style_(kWindowDefaultExStyle), 140 class_style_(CS_DBLCLKS), 141 hwnd_(NULL), 142 got_create_(false), 143 got_valid_hwnd_(false), 144 destroyed_(NULL) { 145 } 146 147 WindowImpl::~WindowImpl() { 148 if (destroyed_) 149 *destroyed_ = true; 150 ClearUserData(); 151 } 152 153 void WindowImpl::Init(HWND parent, const gfx::Rect& bounds) { 154 if (window_style_ == 0) 155 window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle; 156 157 if (parent == HWND_DESKTOP) { 158 // Only non-child windows can have HWND_DESKTOP (0) as their parent. 159 CHECK((window_style_ & WS_CHILD) == 0); 160 parent = GetWindowToParentTo(false); 161 } else if (parent == ::GetDesktopWindow()) { 162 // Any type of window can have the "Desktop Window" as their parent. 163 parent = GetWindowToParentTo(true); 164 } else if (parent != HWND_MESSAGE) { 165 CHECK(::IsWindow(parent)); 166 } 167 168 int x, y, width, height; 169 if (bounds.IsEmpty()) { 170 x = y = width = height = CW_USEDEFAULT; 171 } else { 172 x = bounds.x(); 173 y = bounds.y(); 174 width = bounds.width(); 175 height = bounds.height(); 176 } 177 178 ATOM atom = GetWindowClassAtom(); 179 bool destroyed = false; 180 destroyed_ = &destroyed; 181 HWND hwnd = CreateWindowEx(window_ex_style_, 182 reinterpret_cast<wchar_t*>(atom), NULL, 183 window_style_, x, y, width, height, 184 parent, NULL, NULL, this); 185 186 // First nccalcszie (during CreateWindow) for captioned windows is 187 // deliberately ignored so force a second one here to get the right 188 // non-client set up. 189 if (hwnd && (window_style_ & WS_CAPTION)) { 190 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, 191 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | 192 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW); 193 } 194 195 if (!hwnd_ && GetLastError() == 0) { 196 base::debug::Alias(&destroyed); 197 base::debug::Alias(&hwnd); 198 bool got_create = got_create_; 199 base::debug::Alias(&got_create); 200 bool got_valid_hwnd = got_valid_hwnd_; 201 base::debug::Alias(&got_valid_hwnd); 202 WNDCLASSEX class_info; 203 memset(&class_info, 0, sizeof(WNDCLASSEX)); 204 class_info.cbSize = sizeof(WNDCLASSEX); 205 BOOL got_class = GetClassInfoEx(GetModuleHandle(NULL), 206 reinterpret_cast<wchar_t*>(atom), 207 &class_info); 208 base::debug::Alias(&got_class); 209 bool procs_match = got_class && class_info.lpfnWndProc == 210 base::win::WrappedWindowProc<&WindowImpl::WndProc>; 211 base::debug::Alias(&procs_match); 212 CHECK(false); 213 } 214 if (!destroyed) 215 destroyed_ = NULL; 216 217 CheckWindowCreated(hwnd_); 218 219 // The window procedure should have set the data for us. 220 CHECK_EQ(this, ui::GetWindowUserData(hwnd)); 221 } 222 223 HICON WindowImpl::GetDefaultWindowIcon() const { 224 return NULL; 225 } 226 227 LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) { 228 LRESULT result = 0; 229 230 // Handle the message if it's in our message map; otherwise, let the system 231 // handle it. 232 if (!ProcessWindowMessage(hwnd_, message, w_param, l_param, result)) 233 result = DefWindowProc(hwnd_, message, w_param, l_param); 234 235 return result; 236 } 237 238 void WindowImpl::ClearUserData() { 239 if (::IsWindow(hwnd_)) 240 ui::SetWindowUserData(hwnd_, NULL); 241 } 242 243 // static 244 LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, 245 UINT message, 246 WPARAM w_param, 247 LPARAM l_param) { 248 if (message == WM_NCCREATE) { 249 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param); 250 WindowImpl* window = reinterpret_cast<WindowImpl*>(cs->lpCreateParams); 251 DCHECK(window); 252 ui::SetWindowUserData(hwnd, window); 253 window->hwnd_ = hwnd; 254 window->got_create_ = true; 255 if (hwnd) 256 window->got_valid_hwnd_ = true; 257 return TRUE; 258 } 259 260 WindowImpl* window = reinterpret_cast<WindowImpl*>( 261 ui::GetWindowUserData(hwnd)); 262 if (!window) 263 return 0; 264 265 return window->OnWndProc(message, w_param, l_param); 266 } 267 268 ATOM WindowImpl::GetWindowClassAtom() { 269 HICON icon = GetDefaultWindowIcon(); 270 ClassInfo class_info(initial_class_style(), icon); 271 return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info); 272 } 273 274 } // namespace ui 275