| 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 |