Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: ui/views/win/hwnd_message_handler.cc

Issue 10870104: Fix max/min window menu items by calling the correct version of EnableMenuItem. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698