Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / gfx / win / hwnd_util.cc
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/hwnd_util.h"
6
7 #include "base/i18n/rtl.h"
8 #include "base/strings/string_util.h"
9 #include "base/win/metro.h"
10 #include "base/win/win_util.h"
11 #include "ui/gfx/point.h"
12 #include "ui/gfx/rect.h"
13 #include "ui/gfx/size.h"
14
15 namespace gfx {
16
17 namespace {
18
19 // Adjust the window to fit.
20 void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) {
21   if (fit_to_monitor) {
22     // Get the monitor.
23     HMONITOR hmon = MonitorFromRect(&bounds, MONITOR_DEFAULTTONEAREST);
24     if (hmon) {
25       MONITORINFO mi;
26       mi.cbSize = sizeof(mi);
27       GetMonitorInfo(hmon, &mi);
28       Rect window_rect(bounds);
29       Rect monitor_rect(mi.rcWork);
30       Rect new_window_rect = window_rect;
31       new_window_rect.AdjustToFit(monitor_rect);
32       if (new_window_rect != window_rect) {
33         // Window doesn't fit on monitor, move and possibly resize.
34         SetWindowPos(hwnd, 0, new_window_rect.x(), new_window_rect.y(),
35                      new_window_rect.width(), new_window_rect.height(),
36                      SWP_NOACTIVATE | SWP_NOZORDER);
37         return;
38       }
39       // Else fall through.
40     } else {
41       NOTREACHED() << "Unable to find default monitor";
42       // Fall through.
43     }
44   }  // Else fall through.
45
46   // The window is not being fit to monitor, or the window fits on the monitor
47   // as is, or we have no monitor info; reset the bounds.
48   ::SetWindowPos(hwnd, 0, bounds.left, bounds.top,
49                  bounds.right - bounds.left, bounds.bottom - bounds.top,
50                  SWP_NOACTIVATE | SWP_NOZORDER);
51 }
52
53 // Turn off optimizations for these functions so they show up in crash reports.
54 MSVC_DISABLE_OPTIMIZE();
55
56 void CrashOutOfMemory() {
57   PLOG(FATAL);
58 }
59
60 void CrashAccessDenied() {
61   PLOG(FATAL);
62 }
63
64 // Crash isn't one of the ones we commonly see.
65 void CrashOther() {
66   PLOG(FATAL);
67 }
68
69 MSVC_ENABLE_OPTIMIZE();
70
71 }  // namespace
72
73 base::string16 GetClassName(HWND window) {
74   // GetClassNameW will return a truncated result (properly null terminated) if
75   // the given buffer is not large enough.  So, it is not possible to determine
76   // that we got the entire class name if the result is exactly equal to the
77   // size of the buffer minus one.
78   DWORD buffer_size = MAX_PATH;
79   while (true) {
80     std::wstring output;
81     DWORD size_ret =
82         GetClassNameW(window, WriteInto(&output, buffer_size), buffer_size);
83     if (size_ret == 0)
84       break;
85     if (size_ret < (buffer_size - 1)) {
86       output.resize(size_ret);
87       return output;
88     }
89     buffer_size *= 2;
90   }
91   return std::wstring();  // error
92 }
93
94 #pragma warning(push)
95 #pragma warning(disable:4312 4244)
96
97 WNDPROC SetWindowProc(HWND hwnd, WNDPROC proc) {
98   // The reason we don't return the SetwindowLongPtr() value is that it returns
99   // the orignal window procedure and not the current one. I don't know if it is
100   // a bug or an intended feature.
101   WNDPROC oldwindow_proc =
102       reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC));
103   SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(proc));
104   return oldwindow_proc;
105 }
106
107 void* SetWindowUserData(HWND hwnd, void* user_data) {
108   return
109       reinterpret_cast<void*>(SetWindowLongPtr(hwnd, GWLP_USERDATA,
110           reinterpret_cast<LONG_PTR>(user_data)));
111 }
112
113 void* GetWindowUserData(HWND hwnd) {
114   DWORD process_id = 0;
115   GetWindowThreadProcessId(hwnd, &process_id);
116   // A window outside the current process needs to be ignored.
117   if (process_id != ::GetCurrentProcessId())
118     return NULL;
119   return reinterpret_cast<void*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
120 }
121
122 #pragma warning(pop)
123
124 bool DoesWindowBelongToActiveWindow(HWND window) {
125   DCHECK(window);
126   HWND top_window = ::GetAncestor(window, GA_ROOT);
127   if (!top_window)
128     return false;
129
130   HWND active_top_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT);
131   return (top_window == active_top_window);
132 }
133
134 void CenterAndSizeWindow(HWND parent,
135                          HWND window,
136                          const Size& pref) {
137   DCHECK(window && pref.width() > 0 && pref.height() > 0);
138
139   // Calculate the ideal bounds.
140   RECT window_bounds;
141   RECT center_bounds = {0};
142   if (parent) {
143     // If there is a parent, center over the parents bounds.
144     ::GetWindowRect(parent, &center_bounds);
145   }
146
147   if (::IsRectEmpty(&center_bounds)) {
148     // No parent or no parent rect. Center over the monitor the window is on.
149     HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST);
150     if (monitor) {
151       MONITORINFO mi = {0};
152       mi.cbSize = sizeof(mi);
153       GetMonitorInfo(monitor, &mi);
154       center_bounds = mi.rcWork;
155     } else {
156       NOTREACHED() << "Unable to get default monitor";
157     }
158   }
159
160   window_bounds.left = center_bounds.left;
161   if (pref.width() < (center_bounds.right - center_bounds.left)) {
162     window_bounds.left +=
163         (center_bounds.right - center_bounds.left - pref.width()) / 2;
164   }
165   window_bounds.right = window_bounds.left + pref.width();
166
167   window_bounds.top = center_bounds.top;
168   if (pref.height() < (center_bounds.bottom - center_bounds.top)) {
169     window_bounds.top +=
170         (center_bounds.bottom - center_bounds.top - pref.height()) / 2;
171   }
172   window_bounds.bottom = window_bounds.top + pref.height();
173
174   // If we're centering a child window, we are positioning in client
175   // coordinates, and as such we need to offset the target rectangle by the
176   // position of the parent window.
177   if (::GetWindowLong(window, GWL_STYLE) & WS_CHILD) {
178     DCHECK(parent && ::GetParent(window) == parent);
179     POINT topleft = { window_bounds.left, window_bounds.top };
180     ::MapWindowPoints(HWND_DESKTOP, parent, &topleft, 1);
181     window_bounds.left = topleft.x;
182     window_bounds.top = topleft.y;
183     window_bounds.right = window_bounds.left + pref.width();
184     window_bounds.bottom = window_bounds.top + pref.height();
185   }
186
187   AdjustWindowToFit(window, window_bounds, !parent);
188 }
189
190 void CheckWindowCreated(HWND hwnd) {
191   if (!hwnd) {
192     switch (GetLastError()) {
193       case ERROR_NOT_ENOUGH_MEMORY:
194         CrashOutOfMemory();
195         break;
196       case ERROR_ACCESS_DENIED:
197         CrashAccessDenied();
198         break;
199       default:
200         CrashOther();
201         break;
202     }
203     PLOG(FATAL);
204   }
205 }
206
207 void ShowSystemMenu(HWND window) {
208   RECT rect;
209   GetWindowRect(window, &rect);
210   Point point = Point(base::i18n::IsRTL() ? rect.right : rect.left, rect.top);
211   static const int kSystemMenuOffset = 10;
212   point.Offset(base::i18n::IsRTL() ? -kSystemMenuOffset : kSystemMenuOffset,
213                kSystemMenuOffset);
214   ShowSystemMenuAtPoint(window, point);
215 }
216
217 void ShowSystemMenuAtPoint(HWND window, const Point& point) {
218   // In the Metro process, we never want to show the system menu.
219   if (base::win::IsMetroProcess())
220     return;
221   UINT flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD;
222   if (base::i18n::IsRTL())
223     flags |= TPM_RIGHTALIGN;
224   HMENU menu = GetSystemMenu(window, FALSE);
225   const int command =
226       TrackPopupMenu(menu, flags, point.x(), point.y(), 0, window, NULL);
227   if (command)
228     SendMessage(window, WM_SYSCOMMAND, command, 0);
229 }
230
231 extern "C" {
232   typedef HWND (*RootWindow)();
233 }
234
235 HWND GetWindowToParentTo(bool get_real_hwnd) {
236   HMODULE metro = base::win::GetMetroModule();
237   if (!metro)
238     return get_real_hwnd ? ::GetDesktopWindow() : HWND_DESKTOP;
239   // In windows 8 metro-mode the root window is not the desktop.
240   RootWindow root_window =
241       reinterpret_cast<RootWindow>(::GetProcAddress(metro, "GetRootWindow"));
242   return root_window();
243 }
244
245 }  // namespace gfx