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/hwnd_util.h"
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"
19 // Adjust the window to fit.
20 void AdjustWindowToFit(HWND hwnd
, const RECT
& bounds
, bool fit_to_monitor
) {
23 HMONITOR hmon
= MonitorFromRect(&bounds
, MONITOR_DEFAULTTONEAREST
);
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
);
41 NOTREACHED() << "Unable to find default monitor";
44 } // Else fall through.
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
);
53 // Turn off optimizations for these functions so they show up in crash reports.
54 MSVC_DISABLE_OPTIMIZE();
56 void CrashOutOfMemory() {
60 void CrashAccessDenied() {
64 // Crash isn't one of the ones we commonly see.
69 MSVC_ENABLE_OPTIMIZE();
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
;
82 GetClassNameW(window
, WriteInto(&output
, buffer_size
), buffer_size
);
85 if (size_ret
< (buffer_size
- 1)) {
86 output
.resize(size_ret
);
91 return std::wstring(); // error
95 #pragma warning(disable:4312 4244)
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
;
107 void* SetWindowUserData(HWND hwnd
, void* user_data
) {
109 reinterpret_cast<void*>(SetWindowLongPtr(hwnd
, GWLP_USERDATA
,
110 reinterpret_cast<LONG_PTR
>(user_data
)));
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())
119 return reinterpret_cast<void*>(GetWindowLongPtr(hwnd
, GWLP_USERDATA
));
124 bool DoesWindowBelongToActiveWindow(HWND window
) {
126 HWND top_window
= ::GetAncestor(window
, GA_ROOT
);
130 HWND active_top_window
= ::GetAncestor(::GetForegroundWindow(), GA_ROOT
);
131 return (top_window
== active_top_window
);
134 void CenterAndSizeWindow(HWND parent
,
137 DCHECK(window
&& pref
.width() > 0 && pref
.height() > 0);
139 // Calculate the ideal bounds.
141 RECT center_bounds
= {0};
143 // If there is a parent, center over the parents bounds.
144 ::GetWindowRect(parent
, ¢er_bounds
);
147 if (::IsRectEmpty(¢er_bounds
)) {
148 // No parent or no parent rect. Center over the monitor the window is on.
149 HMONITOR monitor
= MonitorFromWindow(window
, MONITOR_DEFAULTTONEAREST
);
151 MONITORINFO mi
= {0};
152 mi
.cbSize
= sizeof(mi
);
153 GetMonitorInfo(monitor
, &mi
);
154 center_bounds
= mi
.rcWork
;
156 NOTREACHED() << "Unable to get default monitor";
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;
165 window_bounds
.right
= window_bounds
.left
+ pref
.width();
167 window_bounds
.top
= center_bounds
.top
;
168 if (pref
.height() < (center_bounds
.bottom
- center_bounds
.top
)) {
170 (center_bounds
.bottom
- center_bounds
.top
- pref
.height()) / 2;
172 window_bounds
.bottom
= window_bounds
.top
+ pref
.height();
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();
187 AdjustWindowToFit(window
, window_bounds
, !parent
);
190 void CheckWindowCreated(HWND hwnd
) {
192 switch (GetLastError()) {
193 case ERROR_NOT_ENOUGH_MEMORY
:
196 case ERROR_ACCESS_DENIED
:
207 void ShowSystemMenu(HWND window
) {
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
,
214 ShowSystemMenuAtPoint(window
, point
);
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())
221 UINT flags
= TPM_LEFTBUTTON
| TPM_RIGHTBUTTON
| TPM_RETURNCMD
;
222 if (base::i18n::IsRTL())
223 flags
|= TPM_RIGHTALIGN
;
224 HMENU menu
= GetSystemMenu(window
, FALSE
);
226 TrackPopupMenu(menu
, flags
, point
.x(), point
.y(), 0, window
, NULL
);
228 SendMessage(window
, WM_SYSCOMMAND
, command
, 0);
232 typedef HWND (*RootWindow
)();
235 HWND
GetWindowToParentTo(bool get_real_hwnd
) {
236 HMODULE metro
= base::win::GetMetroModule();
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();