Implement MoveFileLocal (with creating a snapshot).
[chromium-blink-merge.git] / ui / gfx / win / window_impl.cc
blob94e315c938c633cda0062725058d85ec9f15f177
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.
5 #include "ui/gfx/win/window_impl.h"
7 #include <list>
9 #include "base/bind.h"
10 #include "base/debug/alias.h"
11 #include "base/memory/singleton.h"
12 #include "base/profiler/scoped_tracker.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/synchronization/lock.h"
15 #include "base/win/wrapped_window_proc.h"
16 #include "ui/gfx/win/hwnd_util.h"
18 namespace gfx {
20 static const DWORD kWindowDefaultChildStyle =
21 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
22 static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
23 static const DWORD kWindowDefaultExStyle = 0;
25 ///////////////////////////////////////////////////////////////////////////////
26 // WindowImpl class tracking.
28 // Several external scripts rely explicitly on this base class name for
29 // acquiring the window handle and will break if this is modified!
30 // static
31 const wchar_t* const WindowImpl::kBaseClassName = L"Chrome_WidgetWin_";
33 // WindowImpl class information used for registering unique windows.
34 struct ClassInfo {
35 UINT style;
36 HICON icon;
37 HICON small_icon;
39 ClassInfo(int style, HICON icon, HICON small_icon)
40 : style(style), icon(icon), small_icon(small_icon) {}
42 // Compares two ClassInfos. Returns true if all members match.
43 bool Equals(const ClassInfo& other) const {
44 return (other.style == style && other.icon == icon);
48 // WARNING: this class may be used on multiple threads.
49 class ClassRegistrar {
50 public:
51 ~ClassRegistrar();
53 static ClassRegistrar* GetInstance();
55 void UnregisterClasses();
57 // Returns the atom identifying the class matching |class_info|,
58 // creating and registering a new class if the class is not yet known.
59 ATOM RetrieveClassAtom(const ClassInfo& class_info);
61 private:
62 // Represents a registered window class.
63 struct RegisteredClass {
64 RegisteredClass(const ClassInfo& info,
65 const base::string16& name,
66 ATOM atom,
67 HINSTANCE instance);
69 // Info used to create the class.
70 ClassInfo info;
72 // The name given to the window class
73 base::string16 name;
75 // The atom identifying the window class.
76 ATOM atom;
78 // The handle of the module containing the window proceedure.
79 HMODULE instance;
82 ClassRegistrar();
83 friend struct DefaultSingletonTraits<ClassRegistrar>;
85 typedef std::list<RegisteredClass> RegisteredClasses;
86 RegisteredClasses registered_classes_;
88 // Counter of how many classes have been registered so far.
89 int registered_count_;
91 base::Lock lock_;
93 DISALLOW_COPY_AND_ASSIGN(ClassRegistrar);
96 ClassRegistrar::~ClassRegistrar() {}
98 // static
99 ClassRegistrar* ClassRegistrar::GetInstance() {
100 return Singleton<ClassRegistrar,
101 LeakySingletonTraits<ClassRegistrar> >::get();
104 void ClassRegistrar::UnregisterClasses() {
105 for (RegisteredClasses::iterator i = registered_classes_.begin();
106 i != registered_classes_.end(); ++i) {
107 if (UnregisterClass(MAKEINTATOM(i->atom), i->instance)) {
108 registered_classes_.erase(i);
109 } else {
110 LOG(ERROR) << "Failed to unregister class " << i->name
111 << ". Error = " << GetLastError();
116 ATOM ClassRegistrar::RetrieveClassAtom(const ClassInfo& class_info) {
117 base::AutoLock auto_lock(lock_);
118 for (RegisteredClasses::const_iterator i = registered_classes_.begin();
119 i != registered_classes_.end(); ++i) {
120 if (class_info.Equals(i->info))
121 return i->atom;
124 // No class found, need to register one.
125 base::string16 name = base::string16(WindowImpl::kBaseClassName) +
126 base::IntToString16(registered_count_++);
128 WNDCLASSEX window_class;
129 base::win::InitializeWindowClass(
130 name.c_str(), &base::win::WrappedWindowProc<WindowImpl::WndProc>,
131 class_info.style, 0, 0, NULL,
132 reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), NULL,
133 class_info.icon, class_info.small_icon, &window_class);
134 HMODULE instance = window_class.hInstance;
135 ATOM atom = RegisterClassEx(&window_class);
136 CHECK(atom) << GetLastError();
138 registered_classes_.push_back(RegisteredClass(
139 class_info, name, atom, instance));
141 return atom;
144 ClassRegistrar::RegisteredClass::RegisteredClass(const ClassInfo& info,
145 const base::string16& name,
146 ATOM atom,
147 HMODULE instance)
148 : info(info),
149 name(name),
150 atom(atom),
151 instance(instance) {}
153 ClassRegistrar::ClassRegistrar() : registered_count_(0) {}
156 ///////////////////////////////////////////////////////////////////////////////
157 // WindowImpl, public
159 WindowImpl::WindowImpl()
160 : window_style_(0),
161 window_ex_style_(kWindowDefaultExStyle),
162 class_style_(CS_DBLCLKS),
163 hwnd_(NULL),
164 got_create_(false),
165 got_valid_hwnd_(false),
166 destroyed_(NULL) {
169 WindowImpl::~WindowImpl() {
170 if (destroyed_)
171 *destroyed_ = true;
172 ClearUserData();
175 // static
176 void WindowImpl::UnregisterClassesAtExit() {
177 base::AtExitManager::RegisterTask(
178 base::Bind(&ClassRegistrar::UnregisterClasses,
179 base::Unretained(ClassRegistrar::GetInstance())));
182 void WindowImpl::Init(HWND parent, const Rect& bounds) {
183 if (window_style_ == 0)
184 window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle;
186 if (parent == HWND_DESKTOP) {
187 // Only non-child windows can have HWND_DESKTOP (0) as their parent.
188 CHECK((window_style_ & WS_CHILD) == 0);
189 parent = GetWindowToParentTo(false);
190 } else if (parent == ::GetDesktopWindow()) {
191 // Any type of window can have the "Desktop Window" as their parent.
192 parent = GetWindowToParentTo(true);
193 } else if (parent != HWND_MESSAGE) {
194 CHECK(::IsWindow(parent));
197 int x, y, width, height;
198 if (bounds.IsEmpty()) {
199 x = y = width = height = CW_USEDEFAULT;
200 } else {
201 x = bounds.x();
202 y = bounds.y();
203 width = bounds.width();
204 height = bounds.height();
207 ATOM atom = GetWindowClassAtom();
208 bool destroyed = false;
209 destroyed_ = &destroyed;
210 HWND hwnd = CreateWindowEx(window_ex_style_,
211 reinterpret_cast<wchar_t*>(atom), NULL,
212 window_style_, x, y, width, height,
213 parent, NULL, NULL, this);
215 // First nccalcszie (during CreateWindow) for captioned windows is
216 // deliberately ignored so force a second one here to get the right
217 // non-client set up.
218 if (hwnd && (window_style_ & WS_CAPTION)) {
219 SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
220 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE |
221 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
224 if (!hwnd_ && GetLastError() == 0) {
225 base::debug::Alias(&destroyed);
226 base::debug::Alias(&hwnd);
227 bool got_create = got_create_;
228 base::debug::Alias(&got_create);
229 bool got_valid_hwnd = got_valid_hwnd_;
230 base::debug::Alias(&got_valid_hwnd);
231 WNDCLASSEX class_info;
232 memset(&class_info, 0, sizeof(WNDCLASSEX));
233 class_info.cbSize = sizeof(WNDCLASSEX);
234 BOOL got_class = GetClassInfoEx(GetModuleHandle(NULL),
235 reinterpret_cast<wchar_t*>(atom),
236 &class_info);
237 base::debug::Alias(&got_class);
238 bool procs_match = got_class && class_info.lpfnWndProc ==
239 base::win::WrappedWindowProc<&WindowImpl::WndProc>;
240 base::debug::Alias(&procs_match);
241 CHECK(false);
243 if (!destroyed)
244 destroyed_ = NULL;
246 CheckWindowCreated(hwnd_);
248 // The window procedure should have set the data for us.
249 CHECK_EQ(this, GetWindowUserData(hwnd));
252 HICON WindowImpl::GetDefaultWindowIcon() const {
253 return nullptr;
256 HICON WindowImpl::GetSmallWindowIcon() const {
257 return nullptr;
260 LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) {
261 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
262 tracked_objects::ScopedTracker tracking_profile1(
263 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 WindowImpl DefWindowProc1"));
265 LRESULT result = 0;
267 HWND hwnd = hwnd_;
268 if (message == WM_NCDESTROY)
269 hwnd_ = NULL;
271 // Handle the message if it's in our message map; otherwise, let the system
272 // handle it.
273 if (!ProcessWindowMessage(hwnd, message, w_param, l_param, result)) {
274 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
275 tracked_objects::ScopedTracker tracking_profile2(
276 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 WindowImpl DefWindowProc2"));
278 result = DefWindowProc(hwnd, message, w_param, l_param);
281 return result;
284 void WindowImpl::ClearUserData() {
285 if (::IsWindow(hwnd_))
286 gfx::SetWindowUserData(hwnd_, NULL);
289 // static
290 LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd,
291 UINT message,
292 WPARAM w_param,
293 LPARAM l_param) {
294 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
295 tracked_objects::ScopedTracker tracking_profile(
296 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 WindowImpl::WndProc"));
298 if (message == WM_NCCREATE) {
299 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param);
300 WindowImpl* window = reinterpret_cast<WindowImpl*>(cs->lpCreateParams);
301 DCHECK(window);
302 gfx::SetWindowUserData(hwnd, window);
303 window->hwnd_ = hwnd;
304 window->got_create_ = true;
305 if (hwnd)
306 window->got_valid_hwnd_ = true;
307 return TRUE;
310 WindowImpl* window = reinterpret_cast<WindowImpl*>(GetWindowUserData(hwnd));
311 if (!window)
312 return 0;
314 return window->OnWndProc(message, w_param, l_param);
317 ATOM WindowImpl::GetWindowClassAtom() {
318 HICON icon = GetDefaultWindowIcon();
319 HICON small_icon = GetSmallWindowIcon();
320 ClassInfo class_info(initial_class_style(), icon, small_icon);
321 return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info);
324 } // namespace gfx