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/window/native_window_win.h" | 5 #include "views/window/native_window_win.h" |
6 | 6 |
7 #include <dwmapi.h> | 7 #include <dwmapi.h> |
8 #include <shellapi.h> | 8 #include <shellapi.h> |
9 | 9 |
10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 &taskbar_data)); | 59 &taskbar_data)); |
60 return ::IsWindow(taskbar) && (monitor != NULL) && | 60 return ::IsWindow(taskbar) && (monitor != NULL) && |
61 (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) && | 61 (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) && |
62 (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST); | 62 (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST); |
63 } | 63 } |
64 | 64 |
65 HWND GetOwner(HWND window) { | 65 HWND GetOwner(HWND window) { |
66 return ::GetWindow(window, GW_OWNER); | 66 return ::GetWindow(window, GW_OWNER); |
67 } | 67 } |
68 | 68 |
69 // Tells the window its frame (non-client area) has changed. | |
70 void SendFrameChanged(HWND window) { | |
71 SetWindowPos(window, NULL, 0, 0, 0, 0, | |
72 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS | | |
73 SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREPOSITION | | |
74 SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER); | |
75 } | |
76 | |
77 // Enables or disables the menu item for the specified command and menu. | |
78 void EnableMenuItem(HMENU menu, UINT command, bool enabled) { | |
79 UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED); | |
80 EnableMenuItem(menu, command, flags); | |
81 } | |
82 | |
83 } // namespace | 69 } // namespace |
84 | 70 |
85 namespace internal { | 71 namespace internal { |
86 | 72 |
87 void EnsureRectIsVisibleInRect(const gfx::Rect& parent_rect, | 73 void EnsureRectIsVisibleInRect(const gfx::Rect& parent_rect, |
88 gfx::Rect* child_rect, | 74 gfx::Rect* child_rect, |
89 int padding) { | 75 int padding) { |
90 DCHECK(child_rect); | 76 DCHECK(child_rect); |
91 | 77 |
92 // We use padding here because it allows some of the original web page to | 78 // We use padding here because it allows some of the original web page to |
(...skipping 23 matching lines...) Expand all Loading... |
116 // LAST, nudge the window back up into the client area if its x,y position is | 102 // LAST, nudge the window back up into the client area if its x,y position is |
117 // within the parent bounds but its width/height place it off-screen. | 103 // within the parent bounds but its width/height place it off-screen. |
118 if (child_rect->bottom() > parent_rect.bottom()) | 104 if (child_rect->bottom() > parent_rect.bottom()) |
119 child_rect->set_y(parent_rect.bottom() - child_rect->height() - padding); | 105 child_rect->set_y(parent_rect.bottom() - child_rect->height() - padding); |
120 if (child_rect->right() > parent_rect.right()) | 106 if (child_rect->right() > parent_rect.right()) |
121 child_rect->set_x(parent_rect.right() - child_rect->width() - padding); | 107 child_rect->set_x(parent_rect.right() - child_rect->width() - padding); |
122 } | 108 } |
123 | 109 |
124 } // namespace internal | 110 } // namespace internal |
125 | 111 |
126 // A scoping class that prevents a window from being able to redraw in response | |
127 // to invalidations that may occur within it for the lifetime of the object. | |
128 // | |
129 // Why would we want such a thing? Well, it turns out Windows has some | |
130 // "unorthodox" behavior when it comes to painting its non-client areas. | |
131 // Occasionally, Windows will paint portions of the default non-client area | |
132 // right over the top of the custom frame. This is not simply fixed by handling | |
133 // WM_NCPAINT/WM_PAINT, with some investigation it turns out that this | |
134 // rendering is being done *inside* the default implementation of some message | |
135 // handlers and functions: | |
136 // . WM_SETTEXT | |
137 // . WM_SETICON | |
138 // . WM_NCLBUTTONDOWN | |
139 // . EnableMenuItem, called from our WM_INITMENU handler | |
140 // The solution is to handle these messages and call DefWindowProc ourselves, | |
141 // but prevent the window from being able to update itself for the duration of | |
142 // the call. We do this with this class, which automatically calls its | |
143 // associated Window's lock and unlock functions as it is created and destroyed. | |
144 // See documentation in those methods for the technique used. | |
145 // | |
146 // IMPORTANT: Do not use this scoping object for large scopes or periods of | |
147 // time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh). | |
148 // | |
149 // I would love to hear Raymond Chen's explanation for all this. And maybe a | |
150 // list of other messages that this applies to ;-) | |
151 class NativeWindowWin::ScopedRedrawLock { | |
152 public: | |
153 explicit ScopedRedrawLock(NativeWindowWin* window) : window_(window) { | |
154 window_->LockUpdates(); | |
155 } | |
156 | |
157 ~ScopedRedrawLock() { | |
158 window_->UnlockUpdates(); | |
159 } | |
160 | |
161 private: | |
162 // The window having its style changed. | |
163 NativeWindowWin* window_; | |
164 }; | |
165 | |
166 //////////////////////////////////////////////////////////////////////////////// | 112 //////////////////////////////////////////////////////////////////////////////// |
167 // NativeWindowWin, public: | 113 // NativeWindowWin, public: |
168 | 114 |
169 NativeWindowWin::NativeWindowWin(internal::NativeWindowDelegate* delegate) | 115 NativeWindowWin::NativeWindowWin(internal::NativeWindowDelegate* delegate) |
170 : NativeWidgetWin(delegate->AsNativeWidgetDelegate()), | 116 : NativeWidgetWin(delegate->AsNativeWidgetDelegate()), |
171 delegate_(delegate), | 117 delegate_(delegate), |
172 restored_enabled_(false), | 118 restored_enabled_(false), |
173 is_active_(false), | |
174 lock_updates_(false), | |
175 saved_window_style_(0), | |
176 ignore_window_pos_changes_(false), | 119 ignore_window_pos_changes_(false), |
177 ignore_pos_changes_factory_(this), | 120 ignore_pos_changes_factory_(this), |
178 is_right_mouse_pressed_on_caption_(false), | 121 is_right_mouse_pressed_on_caption_(false), |
179 last_monitor_(NULL) { | 122 last_monitor_(NULL) { |
180 is_window_ = true; | 123 is_window_ = true; |
181 // Initialize these values to 0 so that subclasses can override the default | 124 // Initialize these values to 0 so that subclasses can override the default |
182 // behavior before calling Init. | 125 // behavior before calling Init. |
183 set_window_style(0); | 126 set_window_style(0); |
184 set_window_ex_style(0); | 127 set_window_ex_style(0); |
185 } | 128 } |
186 | 129 |
187 NativeWindowWin::~NativeWindowWin() { | 130 NativeWindowWin::~NativeWindowWin() { |
188 } | 131 } |
189 | 132 |
190 void NativeWindowWin::Show(int show_state) { | |
191 ShowWindow(show_state); | |
192 // When launched from certain programs like bash and Windows Live Messenger, | |
193 // show_state is set to SW_HIDE, so we need to correct that condition. We | |
194 // don't just change show_state to SW_SHOWNORMAL because MSDN says we must | |
195 // always first call ShowWindow with the specified value from STARTUPINFO, | |
196 // otherwise all future ShowWindow calls will be ignored (!!#@@#!). Instead, | |
197 // we call ShowWindow again in this case. | |
198 if (show_state == SW_HIDE) { | |
199 show_state = SW_SHOWNORMAL; | |
200 ShowWindow(show_state); | |
201 } | |
202 | |
203 // We need to explicitly activate the window if we've been shown with a state | |
204 // that should activate, because if we're opened from a desktop shortcut while | |
205 // an existing window is already running it doesn't seem to be enough to use | |
206 // one of these flags to activate the window. | |
207 if (show_state == SW_SHOWNORMAL || show_state == SW_SHOWMAXIMIZED) | |
208 Activate(); | |
209 | |
210 SetInitialFocus(); | |
211 } | |
212 | |
213 // static | 133 // static |
214 gfx::Font NativeWindowWin::GetWindowTitleFont() { | 134 gfx::Font NativeWindowWin::GetWindowTitleFont() { |
215 NONCLIENTMETRICS ncm; | 135 NONCLIENTMETRICS ncm; |
216 base::win::GetNonClientMetrics(&ncm); | 136 base::win::GetNonClientMetrics(&ncm); |
217 l10n_util::AdjustUIFont(&(ncm.lfCaptionFont)); | 137 l10n_util::AdjustUIFont(&(ncm.lfCaptionFont)); |
218 base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont))); | 138 base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont))); |
219 return gfx::Font(caption_font); | 139 return gfx::Font(caption_font); |
220 } | 140 } |
221 | 141 |
222 /////////////////////////////////////////////////////////////////////////////// | 142 /////////////////////////////////////////////////////////////////////////////// |
223 // NativeWindowWin, protected: | |
224 | |
225 gfx::Insets NativeWindowWin::GetClientAreaInsets() const { | |
226 // Returning an empty Insets object causes the default handling in | |
227 // NativeWidgetWin::OnNCCalcSize() to be invoked. | |
228 if (GetWindow()->ShouldUseNativeFrame()) | |
229 return gfx::Insets(); | |
230 | |
231 if (IsMaximized()) { | |
232 // Windows automatically adds a standard width border to all sides when a | |
233 // window is maximized. | |
234 int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME); | |
235 return gfx::Insets(border_thickness, border_thickness, border_thickness, | |
236 border_thickness); | |
237 } | |
238 // This is weird, but highly essential. If we don't offset the bottom edge | |
239 // of the client rect, the window client area and window area will match, | |
240 // and when returning to glass rendering mode from non-glass, the client | |
241 // area will not paint black as transparent. This is because (and I don't | |
242 // know why) the client area goes from matching the window rect to being | |
243 // something else. If the client area is not the window rect in both | |
244 // modes, the blackness doesn't occur. Because of this, we need to tell | |
245 // the RootView to lay out to fit the window rect, rather than the client | |
246 // rect when using the opaque frame. | |
247 // Note: this is only required for non-fullscreen windows. Note that | |
248 // fullscreen windows are in restored state, not maximized. | |
249 return gfx::Insets(0, 0, IsFullscreen() ? 0 : 1, 0); | |
250 } | |
251 | |
252 int NativeWindowWin::GetShowState() const { | |
253 return SW_SHOWNORMAL; | |
254 } | |
255 | |
256 /////////////////////////////////////////////////////////////////////////////// | |
257 // NativeWindowWin, NativeWidgetWin overrides: | 143 // NativeWindowWin, NativeWidgetWin overrides: |
258 | 144 |
259 void NativeWindowWin::InitNativeWidget(const Widget::InitParams& params) { | 145 void NativeWindowWin::InitNativeWidget(const Widget::InitParams& params) { |
260 if (window_style() == 0) | 146 if (window_style() == 0) |
261 set_window_style(CalculateWindowStyle()); | 147 set_window_style(CalculateWindowStyle()); |
262 if (window_ex_style() == 0) | 148 if (window_ex_style() == 0) |
263 set_window_ex_style(CalculateWindowExStyle()); | 149 set_window_ex_style(CalculateWindowExStyle()); |
264 | 150 |
265 GetMonitorAndRects(params.bounds.ToRECT(), &last_monitor_, | 151 GetMonitorAndRects(params.bounds.ToRECT(), &last_monitor_, |
266 &last_monitor_rect_, &last_work_area_); | 152 &last_monitor_rect_, &last_work_area_); |
267 | 153 |
268 NativeWidgetWin::InitNativeWidget(params); | 154 NativeWidgetWin::InitNativeWidget(params); |
269 } | 155 } |
270 | 156 |
271 void NativeWindowWin::OnActivateApp(BOOL active, DWORD thread_id) { | |
272 if (!active && thread_id != GetCurrentThreadId()) { | |
273 // Another application was activated, we should reset any state that | |
274 // disables inactive rendering now. | |
275 delegate_->EnableInactiveRendering(); | |
276 // Update the native frame too, since it could be rendering the non-client | |
277 // area. | |
278 CallDefaultNCActivateHandler(FALSE); | |
279 } | |
280 } | |
281 | |
282 void NativeWindowWin::OnDestroy() { | 157 void NativeWindowWin::OnDestroy() { |
283 delegate_->OnNativeWindowDestroying(); | |
284 RestoreEnabledIfNecessary(); | 158 RestoreEnabledIfNecessary(); |
285 NativeWidgetWin::OnDestroy(); | 159 NativeWidgetWin::OnDestroy(); |
286 } | 160 } |
287 | 161 |
288 LRESULT NativeWindowWin::OnDwmCompositionChanged(UINT msg, | |
289 WPARAM w_param, | |
290 LPARAM l_param) { | |
291 // For some reason, we need to hide the window while we're changing the frame | |
292 // type only when we're changing it in response to WM_DWMCOMPOSITIONCHANGED. | |
293 // If we don't, the client area will be filled with black. I'm suspecting | |
294 // something skia-ey. | |
295 // Frame type toggling caused by the user (e.g. switching theme) doesn't seem | |
296 // to have this requirement. | |
297 FrameTypeChanged(); | |
298 return 0; | |
299 } | |
300 | |
301 void NativeWindowWin::OnEnterSizeMove() { | |
302 NativeWidgetWin::OnEnterSizeMove(); | |
303 delegate_->OnNativeWindowBeginUserBoundsChange(); | |
304 } | |
305 | |
306 void NativeWindowWin::OnExitSizeMove() { | |
307 NativeWidgetWin::OnExitSizeMove(); | |
308 delegate_->OnNativeWindowEndUserBoundsChange(); | |
309 } | |
310 | |
311 void NativeWindowWin::OnGetMinMaxInfo(MINMAXINFO* minmax_info) { | |
312 gfx::Size min_window_size(delegate_->GetMinimumSize()); | |
313 minmax_info->ptMinTrackSize.x = min_window_size.width(); | |
314 minmax_info->ptMinTrackSize.y = min_window_size.height(); | |
315 NativeWidgetWin::OnGetMinMaxInfo(minmax_info); | |
316 } | |
317 | |
318 void NativeWindowWin::OnInitMenu(HMENU menu) { | |
319 // We only need to manually enable the system menu if we're not using a native | |
320 // frame. | |
321 if (GetWindow()->ShouldUseNativeFrame()) | |
322 NativeWidgetWin::OnInitMenu(menu); | |
323 | |
324 bool is_fullscreen = IsFullscreen(); | |
325 bool is_minimized = IsMinimized(); | |
326 bool is_maximized = IsMaximized(); | |
327 bool is_restored = !is_fullscreen && !is_minimized && !is_maximized; | |
328 | |
329 ScopedRedrawLock lock(this); | |
330 EnableMenuItem(menu, SC_RESTORE, is_minimized || is_maximized); | |
331 EnableMenuItem(menu, SC_MOVE, is_restored); | |
332 EnableMenuItem(menu, SC_SIZE, | |
333 GetWindow()->window_delegate()->CanResize() && is_restored); | |
334 EnableMenuItem(menu, SC_MAXIMIZE, | |
335 GetWindow()->window_delegate()->CanMaximize() && | |
336 !is_fullscreen && !is_maximized); | |
337 EnableMenuItem(menu, SC_MINIMIZE, | |
338 GetWindow()->window_delegate()->CanMaximize() && | |
339 !is_minimized); | |
340 } | |
341 | |
342 LRESULT NativeWindowWin::OnMouseActivate(UINT message, | |
343 WPARAM w_param, | |
344 LPARAM l_param) { | |
345 return delegate_->CanActivate() ? MA_ACTIVATE : MA_NOACTIVATEANDEAT; | |
346 } | |
347 | |
348 LRESULT NativeWindowWin::OnMouseRange(UINT message, | 162 LRESULT NativeWindowWin::OnMouseRange(UINT message, |
349 WPARAM w_param, | 163 WPARAM w_param, |
350 LPARAM l_param) { | 164 LPARAM l_param) { |
351 if (message == WM_RBUTTONUP && is_right_mouse_pressed_on_caption_) { | 165 if (message == WM_RBUTTONUP && is_right_mouse_pressed_on_caption_) { |
352 is_right_mouse_pressed_on_caption_ = false; | 166 is_right_mouse_pressed_on_caption_ = false; |
353 ReleaseCapture(); | 167 ReleaseCapture(); |
354 // |point| is in window coordinates, but WM_NCHITTEST and TrackPopupMenu() | 168 // |point| is in window coordinates, but WM_NCHITTEST and TrackPopupMenu() |
355 // expect screen coordinates. | 169 // expect screen coordinates. |
356 CPoint screen_point(l_param); | 170 CPoint screen_point(l_param); |
357 MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_point, 1); | 171 MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_point, 1); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 NativeWidgetWin::OnMouseRange(message, w_param, l_param); | 228 NativeWidgetWin::OnMouseRange(message, w_param, l_param); |
415 DefWindowProc(GetNativeView(), WM_NCLBUTTONDOWN, w_param, l_param); | 229 DefWindowProc(GetNativeView(), WM_NCLBUTTONDOWN, w_param, l_param); |
416 SetMsgHandled(TRUE); | 230 SetMsgHandled(TRUE); |
417 } | 231 } |
418 */ | 232 */ |
419 | 233 |
420 NativeWidgetWin::OnMouseRange(message, w_param, l_param); | 234 NativeWidgetWin::OnMouseRange(message, w_param, l_param); |
421 return 0; | 235 return 0; |
422 } | 236 } |
423 | 237 |
424 namespace { | |
425 BOOL CALLBACK EnumChildWindowsForRedraw(HWND hwnd, LPARAM lparam) { | |
426 DWORD process_id; | |
427 GetWindowThreadProcessId(hwnd, &process_id); | |
428 int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME; | |
429 if (process_id == GetCurrentProcessId()) | |
430 flags |= RDW_UPDATENOW; | |
431 RedrawWindow(hwnd, NULL, NULL, flags); | |
432 return TRUE; | |
433 } | |
434 } // namespace | |
435 | |
436 LRESULT NativeWindowWin::OnNCActivate(BOOL active) { | |
437 if (!delegate_->CanActivate()) | |
438 return TRUE; | |
439 | |
440 is_active_ = !!active; | |
441 delegate_->OnNativeWindowActivationChanged(is_active_); | |
442 | |
443 // The frame may need to redraw as a result of the activation change. | |
444 // We can get WM_NCACTIVATE before we're actually visible. If we're not | |
445 // visible, no need to paint. | |
446 if (IsVisible()) | |
447 GetWindow()->non_client_view()->SchedulePaint(); | |
448 | |
449 if (!GetWindow()->ShouldUseNativeFrame()) { | |
450 // TODO(beng, et al): Hack to redraw this window and child windows | |
451 // synchronously upon activation. Not all child windows are redrawing | |
452 // themselves leading to issues like http://crbug.com/74604 | |
453 // We redraw out-of-process HWNDs asynchronously to avoid hanging the | |
454 // whole app if a child HWND belonging to a hung plugin is encountered. | |
455 RedrawWindow(GetNativeView(), NULL, NULL, | |
456 RDW_NOCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW); | |
457 EnumChildWindows(GetNativeView(), EnumChildWindowsForRedraw, NULL); | |
458 } | |
459 | |
460 // If we're active again, we should be allowed to render as inactive, so | |
461 // tell the non-client view. | |
462 bool inactive_rendering_disabled = delegate_->IsInactiveRenderingDisabled(); | |
463 if (IsActive()) | |
464 delegate_->EnableInactiveRendering(); | |
465 | |
466 return CallDefaultNCActivateHandler(inactive_rendering_disabled || active); | |
467 } | |
468 | |
469 LRESULT NativeWindowWin::OnNCCalcSize(BOOL mode, LPARAM l_param) { | 238 LRESULT NativeWindowWin::OnNCCalcSize(BOOL mode, LPARAM l_param) { |
470 // We only override the default handling if we need to specify a custom | 239 // We only override the default handling if we need to specify a custom |
471 // non-client edge width. Note that in most cases "no insets" means no | 240 // non-client edge width. Note that in most cases "no insets" means no |
472 // custom width, but in fullscreen mode we want a custom width of 0. | 241 // custom width, but in fullscreen mode we want a custom width of 0. |
473 gfx::Insets insets = GetClientAreaInsets(); | 242 gfx::Insets insets = GetClientAreaInsets(); |
474 if (insets.empty() && !IsFullscreen()) | 243 if (insets.empty() && !IsFullscreen()) |
475 return NativeWidgetWin::OnNCCalcSize(mode, l_param); | 244 return NativeWidgetWin::OnNCCalcSize(mode, l_param); |
476 | 245 |
477 RECT* client_rect = mode ? | 246 RECT* client_rect = mode ? |
478 &reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0] : | 247 &reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0] : |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 // pixels in the (now wrong) location, and thus makes actions like resizing a | 308 // pixels in the (now wrong) location, and thus makes actions like resizing a |
540 // window from the left edge look slightly less broken. | 309 // window from the left edge look slightly less broken. |
541 // We special case when left or top insets are 0, since these conditions | 310 // We special case when left or top insets are 0, since these conditions |
542 // actually require another repaint to correct the layout after glass gets | 311 // actually require another repaint to correct the layout after glass gets |
543 // turned on and off. | 312 // turned on and off. |
544 if (insets.left() == 0 || insets.top() == 0) | 313 if (insets.left() == 0 || insets.top() == 0) |
545 return 0; | 314 return 0; |
546 return mode ? WVR_REDRAW : 0; | 315 return mode ? WVR_REDRAW : 0; |
547 } | 316 } |
548 | 317 |
549 LRESULT NativeWindowWin::OnNCHitTest(const CPoint& point) { | |
550 // If the DWM is rendering the window controls, we need to give the DWM's | |
551 // default window procedure first chance to handle hit testing. | |
552 if (GetWindow()->ShouldUseNativeFrame()) { | |
553 LRESULT result; | |
554 if (DwmDefWindowProc(GetNativeView(), WM_NCHITTEST, 0, | |
555 MAKELPARAM(point.x, point.y), &result)) { | |
556 return result; | |
557 } | |
558 } | |
559 | |
560 // First, give the NonClientView a chance to test the point to see if it | |
561 // provides any of the non-client area. | |
562 POINT temp = point; | |
563 MapWindowPoints(HWND_DESKTOP, GetNativeView(), &temp, 1); | |
564 int component = delegate_->GetNonClientComponent(gfx::Point(temp)); | |
565 if (component != HTNOWHERE) | |
566 return component; | |
567 | |
568 // Otherwise, we let Windows do all the native frame non-client handling for | |
569 // us. | |
570 return NativeWidgetWin::OnNCHitTest(point); | |
571 } | |
572 | |
573 namespace { | 318 namespace { |
574 struct ClipState { | 319 struct ClipState { |
575 // The window being painted. | 320 // The window being painted. |
576 HWND parent; | 321 HWND parent; |
577 | 322 |
578 // DC painting to. | 323 // DC painting to. |
579 HDC dc; | 324 HDC dc; |
580 | 325 |
581 // Origin of the window in terms of the screen. | 326 // Origin of the window in terms of the screen. |
582 int x; | 327 int x; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 dirty_region.Height()); | 419 dirty_region.Height()); |
675 delegate_->AsNativeWidgetDelegate()->OnNativeWidgetPaint(&canvas); | 420 delegate_->AsNativeWidgetDelegate()->OnNativeWidgetPaint(&canvas); |
676 } | 421 } |
677 | 422 |
678 ReleaseDC(GetNativeView(), dc); | 423 ReleaseDC(GetNativeView(), dc); |
679 // When using a custom frame, we want to avoid calling DefWindowProc() since | 424 // When using a custom frame, we want to avoid calling DefWindowProc() since |
680 // that may render artifacts. | 425 // that may render artifacts. |
681 SetMsgHandled(!GetWindow()->ShouldUseNativeFrame()); | 426 SetMsgHandled(!GetWindow()->ShouldUseNativeFrame()); |
682 } | 427 } |
683 | 428 |
684 LRESULT NativeWindowWin::OnNCUAHDrawCaption(UINT msg, | |
685 WPARAM w_param, | |
686 LPARAM l_param) { | |
687 // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for | |
688 // an explanation about why we need to handle this message. | |
689 SetMsgHandled(!GetWindow()->ShouldUseNativeFrame()); | |
690 return 0; | |
691 } | |
692 | |
693 LRESULT NativeWindowWin::OnNCUAHDrawFrame(UINT msg, | |
694 WPARAM w_param, | |
695 LPARAM l_param) { | |
696 // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for | |
697 // an explanation about why we need to handle this message. | |
698 SetMsgHandled(!GetWindow()->ShouldUseNativeFrame()); | |
699 return 0; | |
700 } | |
701 | |
702 LRESULT NativeWindowWin::OnSetCursor(UINT msg, | |
703 WPARAM w_param, | |
704 LPARAM l_param) { | |
705 // This shouldn't hurt even if we're using the native frame. | |
706 ScopedRedrawLock lock(this); | |
707 return DefWindowProc(GetNativeView(), msg, w_param, l_param); | |
708 } | |
709 | |
710 LRESULT NativeWindowWin::OnSetIcon(UINT size_type, HICON new_icon) { | |
711 // This shouldn't hurt even if we're using the native frame. | |
712 ScopedRedrawLock lock(this); | |
713 return DefWindowProc(GetNativeView(), WM_SETICON, size_type, | |
714 reinterpret_cast<LPARAM>(new_icon)); | |
715 } | |
716 | |
717 LRESULT NativeWindowWin::OnSetText(const wchar_t* text) { | |
718 // This shouldn't hurt even if we're using the native frame. | |
719 ScopedRedrawLock lock(this); | |
720 return DefWindowProc(GetNativeView(), WM_SETTEXT, NULL, | |
721 reinterpret_cast<LPARAM>(text)); | |
722 } | |
723 | |
724 void NativeWindowWin::OnSize(UINT size_param, const CSize& new_size) { | |
725 delegate_->OnNativeWindowBoundsChanged(); | |
726 RedrawWindow(GetNativeView(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); | |
727 NativeWidgetWin::OnSize(size_param, new_size); | |
728 } | |
729 | |
730 void NativeWindowWin::OnSysCommand(UINT notification_code, CPoint click) { | |
731 // Windows uses the 4 lower order bits of |notification_code| for type- | |
732 // specific information so we must exclude this when comparing. | |
733 static const int sc_mask = 0xFFF0; | |
734 // Ignore size/move/maximize in fullscreen mode. | |
735 if (IsFullscreen() && | |
736 (((notification_code & sc_mask) == SC_SIZE) || | |
737 ((notification_code & sc_mask) == SC_MOVE) || | |
738 ((notification_code & sc_mask) == SC_MAXIMIZE))) | |
739 return; | |
740 if (!GetWindow()->ShouldUseNativeFrame()) { | |
741 if ((notification_code & sc_mask) == SC_MINIMIZE || | |
742 (notification_code & sc_mask) == SC_MAXIMIZE || | |
743 (notification_code & sc_mask) == SC_RESTORE) { | |
744 GetWindow()->non_client_view()->ResetWindowControls(); | |
745 } else if ((notification_code & sc_mask) == SC_MOVE || | |
746 (notification_code & sc_mask) == SC_SIZE) { | |
747 if (lock_updates_) { | |
748 // We were locked, before entering a resize or move modal loop. Now that | |
749 // we've begun to move the window, we need to unlock updates so that the | |
750 // sizing/moving feedback can be continuous. | |
751 UnlockUpdates(); | |
752 } | |
753 } | |
754 } | |
755 | |
756 // Handle SC_KEYMENU, which means that the user has pressed the ALT | |
757 // key and released it, so we should focus the menu bar. | |
758 if ((notification_code & sc_mask) == SC_KEYMENU && click.x == 0) { | |
759 // Retrieve the status of shift and control keys to prevent consuming | |
760 // shift+alt keys, which are used by Windows to change input languages. | |
761 Accelerator accelerator(ui::KeyboardCodeForWindowsKeyCode(VK_MENU), | |
762 !!(GetKeyState(VK_SHIFT) & 0x8000), | |
763 !!(GetKeyState(VK_CONTROL) & 0x8000), | |
764 false); | |
765 AsNativeWidget()->GetWidget()->GetFocusManager()-> | |
766 ProcessAccelerator(accelerator); | |
767 return; | |
768 } | |
769 | |
770 // If the delegate can't handle it, the system implementation will be called. | |
771 if (!delegate_->ExecuteCommand(notification_code)) { | |
772 DefWindowProc(GetNativeView(), WM_SYSCOMMAND, notification_code, | |
773 MAKELPARAM(click.x, click.y)); | |
774 } | |
775 } | |
776 | |
777 void NativeWindowWin::OnWindowPosChanging(WINDOWPOS* window_pos) { | 429 void NativeWindowWin::OnWindowPosChanging(WINDOWPOS* window_pos) { |
778 if (ignore_window_pos_changes_) { | 430 if (ignore_window_pos_changes_) { |
779 // If somebody's trying to toggle our visibility, change the nonclient area, | 431 // If somebody's trying to toggle our visibility, change the nonclient area, |
780 // change our Z-order, or activate us, we should probably let it go through. | 432 // change our Z-order, or activate us, we should probably let it go through. |
781 if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) | | 433 if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) | |
782 SWP_FRAMECHANGED)) && | 434 SWP_FRAMECHANGED)) && |
783 (window_pos->flags & (SWP_NOZORDER | SWP_NOACTIVATE))) { | 435 (window_pos->flags & (SWP_NOZORDER | SWP_NOACTIVATE))) { |
784 // Just sizing/moving the window; ignore. | 436 // Just sizing/moving the window; ignore. |
785 window_pos->flags |= SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW; | 437 window_pos->flags |= SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW; |
786 window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW); | 438 window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 } | 503 } |
852 | 504 |
853 NativeWidget* NativeWindowWin::AsNativeWidget() { | 505 NativeWidget* NativeWindowWin::AsNativeWidget() { |
854 return this; | 506 return this; |
855 } | 507 } |
856 | 508 |
857 const NativeWidget* NativeWindowWin::AsNativeWidget() const { | 509 const NativeWidget* NativeWindowWin::AsNativeWidget() const { |
858 return this; | 510 return this; |
859 } | 511 } |
860 | 512 |
861 gfx::Rect NativeWindowWin::GetRestoredBounds() const { | |
862 // If we're in fullscreen mode, we've changed the normal bounds to the monitor | |
863 // rect, so return the saved bounds instead. | |
864 if (IsFullscreen()) | |
865 return gfx::Rect(saved_window_info_.window_rect); | |
866 | |
867 gfx::Rect bounds; | |
868 GetWindowBoundsAndMaximizedState(&bounds, NULL); | |
869 return bounds; | |
870 } | |
871 | |
872 void NativeWindowWin::ShowNativeWindow(ShowState state) { | |
873 DWORD native_show_state; | |
874 switch (state) { | |
875 case SHOW_INACTIVE: | |
876 native_show_state = SW_SHOWNOACTIVATE; | |
877 break; | |
878 case SHOW_MAXIMIZED: | |
879 native_show_state = SW_SHOWMAXIMIZED; | |
880 break; | |
881 default: | |
882 native_show_state = GetShowState(); | |
883 break; | |
884 } | |
885 Show(native_show_state); | |
886 } | |
887 | |
888 void NativeWindowWin::BecomeModal() { | 513 void NativeWindowWin::BecomeModal() { |
889 // We implement modality by crawling up the hierarchy of windows starting | 514 // We implement modality by crawling up the hierarchy of windows starting |
890 // at the owner, disabling all of them so that they don't receive input | 515 // at the owner, disabling all of them so that they don't receive input |
891 // messages. | 516 // messages. |
892 HWND start = GetOwner(GetNativeView()); | 517 HWND start = GetOwner(GetNativeView()); |
893 while (start) { | 518 while (start) { |
894 ::EnableWindow(start, FALSE); | 519 ::EnableWindow(start, FALSE); |
895 start = ::GetParent(start); | 520 start = ::GetParent(start); |
896 } | 521 } |
897 } | 522 } |
898 | 523 |
899 void NativeWindowWin::EnableClose(bool enable) { | |
900 // Disable the native frame's close button regardless of whether or not the | |
901 // native frame is in use, since this also affects the system menu. | |
902 EnableMenuItem(GetSystemMenu(GetNativeView(), false), SC_CLOSE, enable); | |
903 SendFrameChanged(GetNativeView()); | |
904 } | |
905 | |
906 //////////////////////////////////////////////////////////////////////////////// | |
907 // NativeWindowWin, NativeWidgetWin overrides: | |
908 | |
909 bool NativeWindowWin::IsActive() const { | |
910 // TODO(beng): evaluate whether or not this is needed. NativeWidgetWin checks | |
911 // active-state with the OS using GetWindowInfo(). | |
912 return is_active_; | |
913 } | |
914 | |
915 //////////////////////////////////////////////////////////////////////////////// | 524 //////////////////////////////////////////////////////////////////////////////// |
916 // NativeWindowWin, private: | 525 // NativeWindowWin, private: |
917 | 526 |
918 void NativeWindowWin::RestoreEnabledIfNecessary() { | 527 void NativeWindowWin::RestoreEnabledIfNecessary() { |
919 if (delegate_->IsModal() && !restored_enabled_) { | 528 if (delegate_->IsModal() && !restored_enabled_) { |
920 restored_enabled_ = true; | 529 restored_enabled_ = true; |
921 // If we were run modally, we need to undo the disabled-ness we inflicted on | 530 // If we were run modally, we need to undo the disabled-ness we inflicted on |
922 // the owner's parent hierarchy. | 531 // the owner's parent hierarchy. |
923 HWND start = GetOwner(GetNativeView()); | 532 HWND start = GetOwner(GetNativeView()); |
924 while (start) { | 533 while (start) { |
(...skipping 21 matching lines...) Expand all Loading... |
946 // menu to get the close button to appear properly. | 555 // menu to get the close button to appear properly. |
947 // window_styles &= ~WS_SYSMENU; | 556 // window_styles &= ~WS_SYSMENU; |
948 } | 557 } |
949 return window_styles; | 558 return window_styles; |
950 } | 559 } |
951 | 560 |
952 DWORD NativeWindowWin::CalculateWindowExStyle() { | 561 DWORD NativeWindowWin::CalculateWindowExStyle() { |
953 return delegate_->IsDialogBox() ? WS_EX_DLGMODALFRAME : 0; | 562 return delegate_->IsDialogBox() ? WS_EX_DLGMODALFRAME : 0; |
954 } | 563 } |
955 | 564 |
956 void NativeWindowWin::LockUpdates() { | |
957 lock_updates_ = true; | |
958 saved_window_style_ = GetWindowLong(GWL_STYLE); | |
959 SetWindowLong(GWL_STYLE, saved_window_style_ & ~WS_VISIBLE); | |
960 } | |
961 | |
962 void NativeWindowWin::UnlockUpdates() { | |
963 SetWindowLong(GWL_STYLE, saved_window_style_); | |
964 lock_updates_ = false; | |
965 } | |
966 | |
967 LRESULT NativeWindowWin::CallDefaultNCActivateHandler(BOOL active) { | |
968 // The DefWindowProc handling for WM_NCACTIVATE renders the classic-look | |
969 // window title bar directly, so we need to use a redraw lock here to prevent | |
970 // it from doing so. | |
971 ScopedRedrawLock lock(this); | |
972 return DefWindowProc(GetNativeView(), WM_NCACTIVATE, active, 0); | |
973 } | |
974 | |
975 //////////////////////////////////////////////////////////////////////////////// | 565 //////////////////////////////////////////////////////////////////////////////// |
976 // NativeWindow, public: | 566 // NativeWindow, public: |
977 | 567 |
978 // static | 568 // static |
979 NativeWindow* NativeWindow::CreateNativeWindow( | 569 NativeWindow* NativeWindow::CreateNativeWindow( |
980 internal::NativeWindowDelegate* delegate) { | 570 internal::NativeWindowDelegate* delegate) { |
981 return new NativeWindowWin(delegate); | 571 return new NativeWindowWin(delegate); |
982 } | 572 } |
983 | 573 |
984 } // namespace views | 574 } // namespace views |
OLD | NEW |