Home | History | Annotate | Download | only in win
      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   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 
    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   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 
    241 void WindowImpl::ClearUserData() {
    242   if (::IsWindow(hwnd_))
    243     gfx::SetWindowUserData(hwnd_, NULL);
    244 }
    245 
    246 // static
    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 
    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