| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "ui/views/win/hwnd_message_handler.h" | 5 #include "ui/views/win/hwnd_message_handler.h" |
| 6 | 6 |
| 7 #include <dwmapi.h> | 7 #include <dwmapi.h> |
| 8 #include <shellapi.h> | 8 #include <shellapi.h> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 BOOL CALLBACK FindOwnedWindowsCallback(HWND hwnd, LPARAM param) { | 71 BOOL CALLBACK FindOwnedWindowsCallback(HWND hwnd, LPARAM param) { |
| 72 FindOwnedWindowsData* data = reinterpret_cast<FindOwnedWindowsData*>(param); | 72 FindOwnedWindowsData* data = reinterpret_cast<FindOwnedWindowsData*>(param); |
| 73 if (GetWindow(hwnd, GW_OWNER) == data->window) { | 73 if (GetWindow(hwnd, GW_OWNER) == data->window) { |
| 74 Widget* widget = Widget::GetWidgetForNativeView(hwnd); | 74 Widget* widget = Widget::GetWidgetForNativeView(hwnd); |
| 75 if (widget) | 75 if (widget) |
| 76 data->owned_widgets.push_back(widget); | 76 data->owned_widgets.push_back(widget); |
| 77 } | 77 } |
| 78 return TRUE; | 78 return TRUE; |
| 79 } | 79 } |
| 80 | 80 |
| 81 // Enables or disables the menu item for the specified command and menu. |
| 82 void EnableMenuItemByCommand(HMENU menu, UINT command, bool enabled) { |
| 83 UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED); |
| 84 EnableMenuItem(menu, command, flags); |
| 85 } |
| 86 |
| 81 // A custom MSAA object id used to determine if a screen reader is actively | 87 // A custom MSAA object id used to determine if a screen reader is actively |
| 82 // listening for MSAA events. | 88 // listening for MSAA events. |
| 83 const int kCustomObjectID = 1; | 89 const int kCustomObjectID = 1; |
| 84 | 90 |
| 85 // The thickness of an auto-hide taskbar in pixels. | 91 // The thickness of an auto-hide taskbar in pixels. |
| 86 const int kAutoHideTaskbarThicknessPx = 2; | 92 const int kAutoHideTaskbarThicknessPx = 2; |
| 87 | 93 |
| 88 } // namespace | 94 } // namespace |
| 89 | 95 |
| 96 // A scoping class that prevents a window from being able to redraw in response |
| 97 // to invalidations that may occur within it for the lifetime of the object. |
| 98 // |
| 99 // Why would we want such a thing? Well, it turns out Windows has some |
| 100 // "unorthodox" behavior when it comes to painting its non-client areas. |
| 101 // Occasionally, Windows will paint portions of the default non-client area |
| 102 // right over the top of the custom frame. This is not simply fixed by handling |
| 103 // WM_NCPAINT/WM_PAINT, with some investigation it turns out that this |
| 104 // rendering is being done *inside* the default implementation of some message |
| 105 // handlers and functions: |
| 106 // . WM_SETTEXT |
| 107 // . WM_SETICON |
| 108 // . WM_NCLBUTTONDOWN |
| 109 // . EnableMenuItem, called from our WM_INITMENU handler |
| 110 // The solution is to handle these messages and call DefWindowProc ourselves, |
| 111 // but prevent the window from being able to update itself for the duration of |
| 112 // the call. We do this with this class, which automatically calls its |
| 113 // associated Window's lock and unlock functions as it is created and destroyed. |
| 114 // See documentation in those methods for the technique used. |
| 115 // |
| 116 // The lock only has an effect if the window was visible upon lock creation, as |
| 117 // it doesn't guard against direct visiblility changes, and multiple locks may |
| 118 // exist simultaneously to handle certain nested Windows messages. |
| 119 // |
| 120 // IMPORTANT: Do not use this scoping object for large scopes or periods of |
| 121 // time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh). |
| 122 // |
| 123 // I would love to hear Raymond Chen's explanation for all this. And maybe a |
| 124 // list of other messages that this applies to ;-) |
| 125 class HWNDMessageHandler::ScopedRedrawLock { |
| 126 public: |
| 127 explicit ScopedRedrawLock(HWNDMessageHandler* owner) |
| 128 : owner_(owner), |
| 129 hwnd_(owner_->hwnd()), |
| 130 was_visible_(owner_->IsVisible()), |
| 131 cancel_unlock_(false), |
| 132 force_(!(GetWindowLong(hwnd_, GWL_STYLE) & WS_CAPTION)) { |
| 133 if (was_visible_ && ::IsWindow(hwnd_)) |
| 134 owner_->LockUpdates(force_); |
| 135 } |
| 136 |
| 137 ~ScopedRedrawLock() { |
| 138 if (!cancel_unlock_ && was_visible_ && ::IsWindow(hwnd_)) |
| 139 owner_->UnlockUpdates(force_); |
| 140 } |
| 141 |
| 142 // Cancel the unlock operation, call this if the Widget is being destroyed. |
| 143 void CancelUnlockOperation() { cancel_unlock_ = true; } |
| 144 |
| 145 private: |
| 146 // The owner having its style changed. |
| 147 HWNDMessageHandler* owner_; |
| 148 // The owner's HWND, cached to avoid action after window destruction. |
| 149 HWND hwnd_; |
| 150 // Records the HWND visibility at the time of creation. |
| 151 bool was_visible_; |
| 152 // A flag indicating that the unlock operation was canceled. |
| 153 bool cancel_unlock_; |
| 154 // If true, perform the redraw lock regardless of Aero state. |
| 155 bool force_; |
| 156 |
| 157 DISALLOW_COPY_AND_ASSIGN(ScopedRedrawLock); |
| 158 }; |
| 159 |
| 90 //////////////////////////////////////////////////////////////////////////////// | 160 //////////////////////////////////////////////////////////////////////////////// |
| 91 // HWNDMessageHandler, public: | 161 // HWNDMessageHandler, public: |
| 92 | 162 |
| 93 HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate) | 163 HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate) |
| 94 : delegate_(delegate), | 164 : delegate_(delegate), |
| 95 ALLOW_THIS_IN_INITIALIZER_LIST(fullscreen_handler_(new FullscreenHandler( | 165 ALLOW_THIS_IN_INITIALIZER_LIST(fullscreen_handler_(new FullscreenHandler( |
| 96 delegate->AsNativeWidgetWin()->GetWidget()))), | 166 delegate->AsNativeWidgetWin()->GetWidget()))), |
| 97 remove_standard_frame_(false), | 167 remove_standard_frame_(false), |
| 98 active_mouse_tracking_flags_(0), | 168 active_mouse_tracking_flags_(0), |
| 99 is_right_mouse_pressed_on_caption_(false), | 169 is_right_mouse_pressed_on_caption_(false), |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 SetMsgHandled(handled); | 626 SetMsgHandled(handled); |
| 557 return result; | 627 return result; |
| 558 } | 628 } |
| 559 | 629 |
| 560 void HWNDMessageHandler::OnInitMenu(HMENU menu) { | 630 void HWNDMessageHandler::OnInitMenu(HMENU menu) { |
| 561 bool is_fullscreen = delegate_->AsNativeWidgetWin()->IsFullscreen(); | 631 bool is_fullscreen = delegate_->AsNativeWidgetWin()->IsFullscreen(); |
| 562 bool is_minimized = IsMinimized(); | 632 bool is_minimized = IsMinimized(); |
| 563 bool is_maximized = IsMaximized(); | 633 bool is_maximized = IsMaximized(); |
| 564 bool is_restored = !is_fullscreen && !is_minimized && !is_maximized; | 634 bool is_restored = !is_fullscreen && !is_minimized && !is_maximized; |
| 565 | 635 |
| 566 EnableMenuItem(menu, SC_RESTORE, is_minimized || is_maximized); | 636 ScopedRedrawLock lock(this); |
| 567 EnableMenuItem(menu, SC_MOVE, is_restored); | 637 EnableMenuItemByCommand(menu, SC_RESTORE, is_minimized || is_maximized); |
| 568 EnableMenuItem(menu, SC_SIZE, delegate_->CanResize() && is_restored); | 638 EnableMenuItemByCommand(menu, SC_MOVE, is_restored); |
| 569 EnableMenuItem(menu, SC_MAXIMIZE, delegate_->CanMaximize() && | 639 EnableMenuItemByCommand(menu, SC_SIZE, delegate_->CanResize() && is_restored); |
| 570 !is_fullscreen && !is_maximized); | 640 EnableMenuItemByCommand(menu, SC_MAXIMIZE, delegate_->CanMaximize() && |
| 571 EnableMenuItem(menu, SC_MINIMIZE, delegate_->CanMaximize() && !is_minimized); | 641 !is_fullscreen && !is_maximized); |
| 642 EnableMenuItemByCommand(menu, SC_MINIMIZE, delegate_->CanMaximize() && |
| 643 !is_minimized); |
| 572 } | 644 } |
| 573 | 645 |
| 574 void HWNDMessageHandler::OnInitMenuPopup() { | 646 void HWNDMessageHandler::OnInitMenuPopup() { |
| 575 SetMsgHandled(FALSE); | 647 SetMsgHandled(FALSE); |
| 576 } | 648 } |
| 577 | 649 |
| 578 void HWNDMessageHandler::OnInputLangChange(DWORD character_set, | 650 void HWNDMessageHandler::OnInputLangChange(DWORD character_set, |
| 579 HKL input_language_id) { | 651 HKL input_language_id) { |
| 580 InputMethod* input_method = delegate_->GetInputMethod(); | 652 InputMethod* input_method = delegate_->GetInputMethod(); |
| 581 if (input_method && !input_method->IsMock()) { | 653 if (input_method && !input_method->IsMock()) { |
| (...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1281 // know why) the client area goes from matching the window rect to being | 1353 // know why) the client area goes from matching the window rect to being |
| 1282 // something else. If the client area is not the window rect in both | 1354 // something else. If the client area is not the window rect in both |
| 1283 // modes, the blackness doesn't occur. Because of this, we need to tell | 1355 // modes, the blackness doesn't occur. Because of this, we need to tell |
| 1284 // the RootView to lay out to fit the window rect, rather than the client | 1356 // the RootView to lay out to fit the window rect, rather than the client |
| 1285 // rect when using the opaque frame. | 1357 // rect when using the opaque frame. |
| 1286 // Note: this is only required for non-fullscreen windows. Note that | 1358 // Note: this is only required for non-fullscreen windows. Note that |
| 1287 // fullscreen windows are in restored state, not maximized. | 1359 // fullscreen windows are in restored state, not maximized. |
| 1288 return gfx::Insets(0, 0, fullscreen_handler_->fullscreen() ? 0 : 1, 0); | 1360 return gfx::Insets(0, 0, fullscreen_handler_->fullscreen() ? 0 : 1, 0); |
| 1289 } | 1361 } |
| 1290 | 1362 |
| 1291 // A scoping class that prevents a window from being able to redraw in response | |
| 1292 // to invalidations that may occur within it for the lifetime of the object. | |
| 1293 // | |
| 1294 // Why would we want such a thing? Well, it turns out Windows has some | |
| 1295 // "unorthodox" behavior when it comes to painting its non-client areas. | |
| 1296 // Occasionally, Windows will paint portions of the default non-client area | |
| 1297 // right over the top of the custom frame. This is not simply fixed by handling | |
| 1298 // WM_NCPAINT/WM_PAINT, with some investigation it turns out that this | |
| 1299 // rendering is being done *inside* the default implementation of some message | |
| 1300 // handlers and functions: | |
| 1301 // . WM_SETTEXT | |
| 1302 // . WM_SETICON | |
| 1303 // . WM_NCLBUTTONDOWN | |
| 1304 // . EnableMenuItem, called from our WM_INITMENU handler | |
| 1305 // The solution is to handle these messages and call DefWindowProc ourselves, | |
| 1306 // but prevent the window from being able to update itself for the duration of | |
| 1307 // the call. We do this with this class, which automatically calls its | |
| 1308 // associated Window's lock and unlock functions as it is created and destroyed. | |
| 1309 // See documentation in those methods for the technique used. | |
| 1310 // | |
| 1311 // The lock only has an effect if the window was visible upon lock creation, as | |
| 1312 // it doesn't guard against direct visiblility changes, and multiple locks may | |
| 1313 // exist simultaneously to handle certain nested Windows messages. | |
| 1314 // | |
| 1315 // IMPORTANT: Do not use this scoping object for large scopes or periods of | |
| 1316 // time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh). | |
| 1317 // | |
| 1318 // I would love to hear Raymond Chen's explanation for all this. And maybe a | |
| 1319 // list of other messages that this applies to ;-) | |
| 1320 class HWNDMessageHandler::ScopedRedrawLock { | |
| 1321 public: | |
| 1322 explicit ScopedRedrawLock(HWNDMessageHandler* owner) | |
| 1323 : owner_(owner), | |
| 1324 hwnd_(owner_->hwnd()), | |
| 1325 was_visible_(owner_->IsVisible()), | |
| 1326 cancel_unlock_(false), | |
| 1327 force_(!(GetWindowLong(hwnd_, GWL_STYLE) & WS_CAPTION)) { | |
| 1328 if (was_visible_ && ::IsWindow(hwnd_)) | |
| 1329 owner_->LockUpdates(force_); | |
| 1330 } | |
| 1331 | |
| 1332 ~ScopedRedrawLock() { | |
| 1333 if (!cancel_unlock_ && was_visible_ && ::IsWindow(hwnd_)) | |
| 1334 owner_->UnlockUpdates(force_); | |
| 1335 } | |
| 1336 | |
| 1337 // Cancel the unlock operation, call this if the Widget is being destroyed. | |
| 1338 void CancelUnlockOperation() { cancel_unlock_ = true; } | |
| 1339 | |
| 1340 private: | |
| 1341 // The owner having its style changed. | |
| 1342 HWNDMessageHandler* owner_; | |
| 1343 // The owner's HWND, cached to avoid action after window destruction. | |
| 1344 HWND hwnd_; | |
| 1345 // Records the HWND visibility at the time of creation. | |
| 1346 bool was_visible_; | |
| 1347 // A flag indicating that the unlock operation was canceled. | |
| 1348 bool cancel_unlock_; | |
| 1349 // If true, perform the redraw lock regardless of Aero state. | |
| 1350 bool force_; | |
| 1351 | |
| 1352 DISALLOW_COPY_AND_ASSIGN(ScopedRedrawLock); | |
| 1353 }; | |
| 1354 | |
| 1355 LRESULT HWNDMessageHandler::DefWindowProcWithRedrawLock(UINT message, | 1363 LRESULT HWNDMessageHandler::DefWindowProcWithRedrawLock(UINT message, |
| 1356 WPARAM w_param, | 1364 WPARAM w_param, |
| 1357 LPARAM l_param) { | 1365 LPARAM l_param) { |
| 1358 ScopedRedrawLock lock(this); | 1366 ScopedRedrawLock lock(this); |
| 1359 // The Widget and HWND can be destroyed in the call to DefWindowProc, so use | 1367 // The Widget and HWND can be destroyed in the call to DefWindowProc, so use |
| 1360 // the |destroyed_| flag to avoid unlocking (and crashing) after destruction. | 1368 // the |destroyed_| flag to avoid unlocking (and crashing) after destruction. |
| 1361 bool destroyed = false; | 1369 bool destroyed = false; |
| 1362 destroyed_ = &destroyed; | 1370 destroyed_ = &destroyed; |
| 1363 LRESULT result = DefWindowProc(hwnd(), message, w_param, l_param); | 1371 LRESULT result = DefWindowProc(hwnd(), message, w_param, l_param); |
| 1364 if (destroyed) | 1372 if (destroyed) |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1404 | 1412 |
| 1405 HWND HWNDMessageHandler::hwnd() const { | 1413 HWND HWNDMessageHandler::hwnd() const { |
| 1406 return delegate_->AsNativeWidgetWin()->hwnd(); | 1414 return delegate_->AsNativeWidgetWin()->hwnd(); |
| 1407 } | 1415 } |
| 1408 | 1416 |
| 1409 void HWNDMessageHandler::SetMsgHandled(BOOL handled) { | 1417 void HWNDMessageHandler::SetMsgHandled(BOOL handled) { |
| 1410 delegate_->AsNativeWidgetWin()->SetMsgHandled(handled); | 1418 delegate_->AsNativeWidgetWin()->SetMsgHandled(handled); |
| 1411 } | 1419 } |
| 1412 | 1420 |
| 1413 } // namespace views | 1421 } // namespace views |
| OLD | NEW |