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 |