OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "views/widget/native_widget_win.h" | 5 #include "views/widget/native_widget_win.h" |
6 | 6 |
7 #include <dwmapi.h> | 7 #include <dwmapi.h> |
8 #include <shellapi.h> | 8 #include <shellapi.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 #include "views/widget/root_view.h" | 48 #include "views/widget/root_view.h" |
49 #include "views/widget/widget_delegate.h" | 49 #include "views/widget/widget_delegate.h" |
50 #include "views/window/native_frame_view.h" | 50 #include "views/window/native_frame_view.h" |
51 | 51 |
52 #pragma comment(lib, "dwmapi.lib") | 52 #pragma comment(lib, "dwmapi.lib") |
53 | 53 |
54 using ui::ViewProp; | 54 using ui::ViewProp; |
55 | 55 |
56 namespace views { | 56 namespace views { |
57 | 57 |
58 namespace internal { | |
59 | |
60 void EnsureRectIsVisibleInRect(const gfx::Rect& parent_rect, | |
61 gfx::Rect* child_rect, | |
62 int padding) { | |
63 DCHECK(child_rect); | |
64 | |
65 // We use padding here because it allows some of the original web page to | |
66 // bleed through around the edges. | |
67 int twice_padding = padding * 2; | |
68 | |
69 // FIRST, clamp width and height so we don't open child windows larger than | |
70 // the containing parent. | |
71 if (child_rect->width() > (parent_rect.width() + twice_padding)) | |
72 child_rect->set_width(std::max(0, parent_rect.width() - twice_padding)); | |
73 if (child_rect->height() > parent_rect.height() + twice_padding) | |
74 child_rect->set_height(std::max(0, parent_rect.height() - twice_padding)); | |
75 | |
76 // SECOND, clamp x,y position to padding,padding so we don't position child | |
77 // windows in hyperspace. | |
78 // TODO(mpcomplete): I don't see what the second check in each 'if' does that | |
79 // isn't handled by the LAST set of 'ifs'. Maybe we can remove it. | |
80 if (child_rect->x() < parent_rect.x() || | |
81 child_rect->x() > parent_rect.right()) { | |
82 child_rect->set_x(parent_rect.x() + padding); | |
83 } | |
84 if (child_rect->y() < parent_rect.y() || | |
85 child_rect->y() > parent_rect.bottom()) { | |
86 child_rect->set_y(parent_rect.y() + padding); | |
87 } | |
88 | |
89 // LAST, nudge the window back up into the client area if its x,y position is | |
90 // within the parent bounds but its width/height place it off-screen. | |
91 if (child_rect->bottom() > parent_rect.bottom()) | |
92 child_rect->set_y(parent_rect.bottom() - child_rect->height() - padding); | |
93 if (child_rect->right() > parent_rect.right()) | |
94 child_rect->set_x(parent_rect.right() - child_rect->width() - padding); | |
95 } | |
96 | |
97 } // namespace internal | |
98 | |
99 namespace { | 58 namespace { |
100 | 59 |
101 // Get the source HWND of the specified message. Depending on the message, the | 60 // Get the source HWND of the specified message. Depending on the message, the |
102 // source HWND is encoded in either the WPARAM or the LPARAM value. | 61 // source HWND is encoded in either the WPARAM or the LPARAM value. |
103 HWND GetControlHWNDForMessage(UINT message, WPARAM w_param, LPARAM l_param) { | 62 HWND GetControlHWNDForMessage(UINT message, WPARAM w_param, LPARAM l_param) { |
104 // Each of the following messages can be sent by a child HWND and must be | 63 // Each of the following messages can be sent by a child HWND and must be |
105 // forwarded to its associated NativeControlWin for handling. | 64 // forwarded to its associated NativeControlWin for handling. |
106 switch (message) { | 65 switch (message) { |
107 case WM_NOTIFY: | 66 case WM_NOTIFY: |
108 return reinterpret_cast<NMHDR*>(l_param)->hwndFrom; | 67 return reinterpret_cast<NMHDR*>(l_param)->hwndFrom; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 } | 113 } |
155 | 114 |
156 // Returns true if the WINDOWPOS data provided indicates the client area of | 115 // Returns true if the WINDOWPOS data provided indicates the client area of |
157 // the window may have changed size. This can be caused by the window being | 116 // the window may have changed size. This can be caused by the window being |
158 // resized or its frame changing. | 117 // resized or its frame changing. |
159 bool DidClientAreaSizeChange(const WINDOWPOS* window_pos) { | 118 bool DidClientAreaSizeChange(const WINDOWPOS* window_pos) { |
160 return !(window_pos->flags & SWP_NOSIZE) || | 119 return !(window_pos->flags & SWP_NOSIZE) || |
161 window_pos->flags & SWP_FRAMECHANGED; | 120 window_pos->flags & SWP_FRAMECHANGED; |
162 } | 121 } |
163 | 122 |
164 // Ensures that the child window stays within the boundaries of the parent | |
165 // before setting its bounds. If |parent_window| is NULL, the bounds of the | |
166 // parent are assumed to be the bounds of the monitor that |child_window| is | |
167 // nearest to. If |child_window| isn't visible yet and |insert_after_window| | |
168 // is non-NULL and visible, the monitor |insert_after_window| is on is used | |
169 // as the parent bounds instead. | |
170 // TODO(beng): This function could easily not be so windowsy, deal with Widgets | |
171 // instead of HWNDs, and move to Widget instead of NativeWidget and | |
172 // then miraculously also work on Linux. | |
173 void SetChildBounds(HWND child_window, | |
174 HWND parent_window, | |
175 HWND insert_after_window, | |
176 const gfx::Rect& bounds, | |
177 int padding, | |
178 unsigned long flags) { | |
179 DCHECK(IsWindow(child_window)); | |
180 | |
181 // First figure out the bounds of the parent. | |
182 RECT parent_rect = {0}; | |
183 if (parent_window) { | |
184 GetClientRect(parent_window, &parent_rect); | |
185 } else { | |
186 // If there is no parent, we consider the bounds of the monitor the window | |
187 // is on to be the parent bounds. | |
188 | |
189 // If the child_window isn't visible yet and we've been given a valid, | |
190 // visible insert after window, use that window to locate the correct | |
191 // monitor instead. | |
192 HWND window = child_window; | |
193 if (!IsWindowVisible(window) && IsWindow(insert_after_window) && | |
194 IsWindowVisible(insert_after_window)) | |
195 window = insert_after_window; | |
196 | |
197 gfx::Rect work_area = | |
198 gfx::Screen::GetMonitorWorkAreaNearestPoint(bounds.origin()); | |
199 if (!work_area.IsEmpty()) | |
200 parent_rect = work_area.ToRECT(); | |
201 } | |
202 | |
203 gfx::Rect actual_bounds = bounds; | |
204 internal::EnsureRectIsVisibleInRect(gfx::Rect(parent_rect), &actual_bounds, | |
205 padding); | |
206 | |
207 SetWindowPos(child_window, insert_after_window, actual_bounds.x(), | |
208 actual_bounds.y(), actual_bounds.width(), | |
209 actual_bounds.height(), flags); | |
210 } | |
211 | |
212 // Callback used to notify child windows that the top level window received a | 123 // Callback used to notify child windows that the top level window received a |
213 // DWMCompositionChanged message. | 124 // DWMCompositionChanged message. |
214 BOOL CALLBACK SendDwmCompositionChanged(HWND window, LPARAM param) { | 125 BOOL CALLBACK SendDwmCompositionChanged(HWND window, LPARAM param) { |
215 SendMessage(window, WM_DWMCOMPOSITIONCHANGED, 0, 0); | 126 SendMessage(window, WM_DWMCOMPOSITIONCHANGED, 0, 0); |
216 return TRUE; | 127 return TRUE; |
217 } | 128 } |
218 | 129 |
219 // Tells the window its frame (non-client area) has changed. | 130 // Tells the window its frame (non-client area) has changed. |
220 void SendFrameChanged(HWND window) { | 131 void SendFrameChanged(HWND window) { |
221 SetWindowPos(window, NULL, 0, 0, 0, 0, | 132 SetWindowPos(window, NULL, 0, 0, 0, 0, |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 return true; | 200 return true; |
290 } | 201 } |
291 | 202 |
292 // Links the HWND to its NativeWidget. | 203 // Links the HWND to its NativeWidget. |
293 const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__"; | 204 const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__"; |
294 | 205 |
295 // A custom MSAA object id used to determine if a screen reader is actively | 206 // A custom MSAA object id used to determine if a screen reader is actively |
296 // listening for MSAA events. | 207 // listening for MSAA events. |
297 const int kCustomObjectID = 1; | 208 const int kCustomObjectID = 1; |
298 | 209 |
299 // If the hung renderer warning doesn't fit on screen, the amount of padding to | |
300 // be left between the edge of the window and the edge of the nearest monitor, | |
301 // after the window is nudged back on screen. Pixels. | |
302 const int kMonitorEdgePadding = 10; | |
303 | |
304 const int kDragFrameWindowAlpha = 200; | 210 const int kDragFrameWindowAlpha = 200; |
305 | 211 |
306 } // namespace | 212 } // namespace |
307 | 213 |
308 // static | 214 // static |
309 bool NativeWidgetWin::screen_reader_active_ = false; | 215 bool NativeWidgetWin::screen_reader_active_ = false; |
310 | 216 |
311 // A scoping class that prevents a window from being able to redraw in response | 217 // A scoping class that prevents a window from being able to redraw in response |
312 // to invalidations that may occur within it for the lifetime of the object. | 218 // to invalidations that may occur within it for the lifetime of the object. |
313 // | 219 // |
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 SetWindowLong(GWL_STYLE, style & ~WS_MAXIMIZE); | 705 SetWindowLong(GWL_STYLE, style & ~WS_MAXIMIZE); |
800 SetWindowPos(NULL, bounds.x(), bounds.y(), bounds.width(), bounds.height(), | 706 SetWindowPos(NULL, bounds.x(), bounds.y(), bounds.width(), bounds.height(), |
801 SWP_NOACTIVATE | SWP_NOZORDER); | 707 SWP_NOACTIVATE | SWP_NOZORDER); |
802 } | 708 } |
803 | 709 |
804 void NativeWidgetWin::SetSize(const gfx::Size& size) { | 710 void NativeWidgetWin::SetSize(const gfx::Size& size) { |
805 SetWindowPos(NULL, 0, 0, size.width(), size.height(), | 711 SetWindowPos(NULL, 0, 0, size.width(), size.height(), |
806 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); | 712 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); |
807 } | 713 } |
808 | 714 |
809 void NativeWidgetWin::SetBoundsConstrained(const gfx::Rect& bounds, | |
810 Widget* other_widget) { | |
811 SetChildBounds(GetNativeView(), GetParent(), | |
812 other_widget ? other_widget->GetNativeView() : NULL, | |
813 bounds, kMonitorEdgePadding, 0); | |
814 } | |
815 | |
816 void NativeWidgetWin::MoveAbove(gfx::NativeView native_view) { | 715 void NativeWidgetWin::MoveAbove(gfx::NativeView native_view) { |
817 SetWindowPos(native_view, 0, 0, 0, 0, | 716 SetWindowPos(native_view, 0, 0, 0, 0, |
818 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); | 717 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); |
819 } | 718 } |
820 | 719 |
821 void NativeWidgetWin::MoveToTop() { | 720 void NativeWidgetWin::MoveToTop() { |
822 NOTIMPLEMENTED(); | 721 NOTIMPLEMENTED(); |
823 } | 722 } |
824 | 723 |
825 void NativeWidgetWin::SetShape(gfx::NativeRegion region) { | 724 void NativeWidgetWin::SetShape(gfx::NativeRegion region) { |
(...skipping 1798 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2624 return (GetKeyState(VK_LBUTTON) & 0x80) || | 2523 return (GetKeyState(VK_LBUTTON) & 0x80) || |
2625 (GetKeyState(VK_RBUTTON) & 0x80) || | 2524 (GetKeyState(VK_RBUTTON) & 0x80) || |
2626 (GetKeyState(VK_MBUTTON) & 0x80) || | 2525 (GetKeyState(VK_MBUTTON) & 0x80) || |
2627 (GetKeyState(VK_XBUTTON1) & 0x80) || | 2526 (GetKeyState(VK_XBUTTON1) & 0x80) || |
2628 (GetKeyState(VK_XBUTTON2) & 0x80); | 2527 (GetKeyState(VK_XBUTTON2) & 0x80); |
2629 } | 2528 } |
2630 | 2529 |
2631 } // namespace internal | 2530 } // namespace internal |
2632 | 2531 |
2633 } // namespace views | 2532 } // namespace views |
OLD | NEW |