| 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 | 8 |
| 9 #include "base/system_monitor/system_monitor.h" | 9 #include "base/system_monitor/system_monitor.h" |
| 10 #include "base/win/windows_version.h" | 10 #include "base/win/windows_version.h" |
| 11 #include "ui/gfx/path.h" | 11 #include "ui/gfx/path.h" |
| 12 #include "ui/base/event.h" |
| 12 #include "ui/base/native_theme/native_theme_win.h" | 13 #include "ui/base/native_theme/native_theme_win.h" |
| 14 #include "ui/base/win/hwnd_util.h" |
| 15 #include "ui/base/win/mouse_wheel_util.h" |
| 16 #include "ui/base/win/shell.h" |
| 13 #include "ui/views/ime/input_method_win.h" | 17 #include "ui/views/ime/input_method_win.h" |
| 14 #include "ui/views/widget/native_widget_win.h" | 18 #include "ui/views/widget/native_widget_win.h" |
| 19 #include "ui/views/widget/widget_hwnd_utils.h" |
| 15 #include "ui/views/win/hwnd_message_handler_delegate.h" | 20 #include "ui/views/win/hwnd_message_handler_delegate.h" |
| 16 | 21 |
| 22 #if !defined(USE_AURA) |
| 23 #include "base/command_line.h" |
| 24 #include "ui/base/ui_base_switches.h" |
| 25 #endif |
| 26 |
| 17 namespace views { | 27 namespace views { |
| 18 namespace { | 28 namespace { |
| 19 | 29 |
| 20 // Called from OnNCActivate. | 30 // Called from OnNCActivate. |
| 21 BOOL CALLBACK EnumChildWindowsForRedraw(HWND hwnd, LPARAM lparam) { | 31 BOOL CALLBACK EnumChildWindowsForRedraw(HWND hwnd, LPARAM lparam) { |
| 22 DWORD process_id; | 32 DWORD process_id; |
| 23 GetWindowThreadProcessId(hwnd, &process_id); | 33 GetWindowThreadProcessId(hwnd, &process_id); |
| 24 int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME; | 34 int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME; |
| 25 if (process_id == GetCurrentProcessId()) | 35 if (process_id == GetCurrentProcessId()) |
| 26 flags |= RDW_UPDATENOW; | 36 flags |= RDW_UPDATENOW; |
| 27 RedrawWindow(hwnd, NULL, NULL, flags); | 37 RedrawWindow(hwnd, NULL, NULL, flags); |
| 28 return TRUE; | 38 return TRUE; |
| 29 } | 39 } |
| 30 | 40 |
| 31 // A custom MSAA object id used to determine if a screen reader is actively | 41 // A custom MSAA object id used to determine if a screen reader is actively |
| 32 // listening for MSAA events. | 42 // listening for MSAA events. |
| 33 const int kCustomObjectID = 1; | 43 const int kCustomObjectID = 1; |
| 34 | 44 |
| 35 } // namespace | 45 } // namespace |
| 36 | 46 |
| 37 //////////////////////////////////////////////////////////////////////////////// | 47 //////////////////////////////////////////////////////////////////////////////// |
| 38 // HWNDMessageHandler, public: | 48 // HWNDMessageHandler, public: |
| 39 | 49 |
| 40 HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate) | 50 HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate) |
| 41 : delegate_(delegate), | 51 : delegate_(delegate), |
| 42 remove_standard_frame_(false) { | 52 remove_standard_frame_(false), |
| 53 active_mouse_tracking_flags_(0), |
| 54 is_right_mouse_pressed_on_caption_(false), |
| 55 lock_updates_count_(0), |
| 56 destroyed_(NULL) { |
| 43 } | 57 } |
| 44 | 58 |
| 45 HWNDMessageHandler::~HWNDMessageHandler() { | 59 HWNDMessageHandler::~HWNDMessageHandler() { |
| 60 if (destroyed_ != NULL) |
| 61 *destroyed_ = true; |
| 62 } |
| 63 |
| 64 bool HWNDMessageHandler::IsVisible() const { |
| 65 return !!::IsWindowVisible(hwnd()); |
| 46 } | 66 } |
| 47 | 67 |
| 48 bool HWNDMessageHandler::IsActive() const { | 68 bool HWNDMessageHandler::IsActive() const { |
| 49 return GetActiveWindow() == hwnd(); | 69 return GetActiveWindow() == hwnd(); |
| 50 } | 70 } |
| 51 | 71 |
| 52 bool HWNDMessageHandler::IsVisible() const { | 72 bool HWNDMessageHandler::IsMinimized() const { |
| 53 return !!::IsWindowVisible(hwnd()); | 73 return !!::IsIconic(hwnd()); |
| 74 } |
| 75 |
| 76 bool HWNDMessageHandler::IsMaximized() const { |
| 77 return !!::IsZoomed(hwnd()); |
| 54 } | 78 } |
| 55 | 79 |
| 56 void HWNDMessageHandler::SendFrameChanged() { | 80 void HWNDMessageHandler::SendFrameChanged() { |
| 57 SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, | 81 SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, |
| 58 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS | | 82 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS | |
| 59 SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREPOSITION | | 83 SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREPOSITION | |
| 60 SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER); | 84 SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER); |
| 61 } | 85 } |
| 62 | 86 |
| 87 void HWNDMessageHandler::SetCapture() { |
| 88 DCHECK(!HasCapture()); |
| 89 ::SetCapture(hwnd()); |
| 90 } |
| 91 |
| 92 void HWNDMessageHandler::ReleaseCapture() { |
| 93 ::ReleaseCapture(); |
| 94 } |
| 95 |
| 96 bool HWNDMessageHandler::HasCapture() const { |
| 97 return ::GetCapture() == hwnd(); |
| 98 } |
| 99 |
| 100 InputMethod* HWNDMessageHandler::CreateInputMethod() { |
| 101 #if !defined(USE_AURA) |
| 102 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 103 if (!command_line->HasSwitch(switches::kEnableViewsTextfield)) |
| 104 return NULL; |
| 105 #endif |
| 106 return new InputMethodWin(this); |
| 107 } |
| 108 |
| 63 void HWNDMessageHandler::OnActivate(UINT action, BOOL minimized, HWND window) { | 109 void HWNDMessageHandler::OnActivate(UINT action, BOOL minimized, HWND window) { |
| 64 SetMsgHandled(FALSE); | 110 SetMsgHandled(FALSE); |
| 65 } | 111 } |
| 66 | 112 |
| 67 void HWNDMessageHandler::OnActivateApp(BOOL active, DWORD thread_id) { | 113 void HWNDMessageHandler::OnActivateApp(BOOL active, DWORD thread_id) { |
| 68 if (delegate_->IsWidgetWindow() && !active && | 114 if (delegate_->IsWidgetWindow() && !active && |
| 69 thread_id != GetCurrentThreadId()) { | 115 thread_id != GetCurrentThreadId()) { |
| 70 delegate_->HandleAppDeactivated(); | 116 delegate_->HandleAppDeactivated(); |
| 71 // Also update the native frame if it is rendering the non-client area. | 117 // Also update the native frame if it is rendering the non-client area. |
| 72 if (!remove_standard_frame_ && !delegate_->IsUsingCustomFrame()) | 118 if (!remove_standard_frame_ && !delegate_->IsUsingCustomFrame()) |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 GetWindowLong(hwnd(), GWL_STYLE) & ~WS_CAPTION); | 173 GetWindowLong(hwnd(), GWL_STYLE) & ~WS_CAPTION); |
| 128 SendFrameChanged(); | 174 SendFrameChanged(); |
| 129 } | 175 } |
| 130 | 176 |
| 131 // Get access to a modifiable copy of the system menu. | 177 // Get access to a modifiable copy of the system menu. |
| 132 GetSystemMenu(hwnd(), false); | 178 GetSystemMenu(hwnd(), false); |
| 133 | 179 |
| 134 if (base::win::GetVersion() >= base::win::VERSION_WIN7) | 180 if (base::win::GetVersion() >= base::win::VERSION_WIN7) |
| 135 RegisterTouchWindow(hwnd(), 0); | 181 RegisterTouchWindow(hwnd(), 0); |
| 136 | 182 |
| 183 // We need to allow the delegate to size its contents since the window may not |
| 184 // receive a size notification when its initial bounds are specified at window |
| 185 // creation time. |
| 186 ClientAreaSizeChanged(); |
| 187 |
| 137 delegate_->HandleCreate(); | 188 delegate_->HandleCreate(); |
| 138 | 189 |
| 139 // TODO(beng): move more of NWW::OnCreate here. | 190 // TODO(beng): move more of NWW::OnCreate here. |
| 140 return 0; | 191 return 0; |
| 141 } | 192 } |
| 142 | 193 |
| 143 void HWNDMessageHandler::OnDestroy() { | 194 void HWNDMessageHandler::OnDestroy() { |
| 144 delegate_->HandleDestroy(); | 195 delegate_->HandleDestroy(); |
| 145 } | 196 } |
| 146 | 197 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 | 308 |
| 258 InputMethodWin* ime_win = static_cast<InputMethodWin*>(input_method); | 309 InputMethodWin* ime_win = static_cast<InputMethodWin*>(input_method); |
| 259 BOOL handled = FALSE; | 310 BOOL handled = FALSE; |
| 260 LRESULT result = ime_win->OnImeMessages(message, w_param, l_param, &handled); | 311 LRESULT result = ime_win->OnImeMessages(message, w_param, l_param, &handled); |
| 261 SetMsgHandled(handled); | 312 SetMsgHandled(handled); |
| 262 return result; | 313 return result; |
| 263 } | 314 } |
| 264 | 315 |
| 265 void HWNDMessageHandler::OnInitMenu(HMENU menu) { | 316 void HWNDMessageHandler::OnInitMenu(HMENU menu) { |
| 266 bool is_fullscreen = delegate_->AsNativeWidgetWin()->IsFullscreen(); | 317 bool is_fullscreen = delegate_->AsNativeWidgetWin()->IsFullscreen(); |
| 267 bool is_minimized = delegate_->AsNativeWidgetWin()->IsMinimized(); | 318 bool is_minimized = IsMinimized(); |
| 268 bool is_maximized = delegate_->AsNativeWidgetWin()->IsMaximized(); | 319 bool is_maximized = IsMaximized(); |
| 269 bool is_restored = !is_fullscreen && !is_minimized && !is_maximized; | 320 bool is_restored = !is_fullscreen && !is_minimized && !is_maximized; |
| 270 | 321 |
| 271 EnableMenuItem(menu, SC_RESTORE, is_minimized || is_maximized); | 322 EnableMenuItem(menu, SC_RESTORE, is_minimized || is_maximized); |
| 272 EnableMenuItem(menu, SC_MOVE, is_restored); | 323 EnableMenuItem(menu, SC_MOVE, is_restored); |
| 273 EnableMenuItem(menu, SC_SIZE, delegate_->CanResize() && is_restored); | 324 EnableMenuItem(menu, SC_SIZE, delegate_->CanResize() && is_restored); |
| 274 EnableMenuItem(menu, SC_MAXIMIZE, delegate_->CanMaximize() && | 325 EnableMenuItem(menu, SC_MAXIMIZE, delegate_->CanMaximize() && |
| 275 !is_fullscreen && !is_maximized); | 326 !is_fullscreen && !is_maximized); |
| 276 EnableMenuItem(menu, SC_MINIMIZE, delegate_->CanMaximize() && !is_minimized); | 327 EnableMenuItem(menu, SC_MINIMIZE, delegate_->CanMaximize() && !is_minimized); |
| 277 } | 328 } |
| 278 | 329 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 291 | 342 |
| 292 LRESULT HWNDMessageHandler::OnKeyEvent(UINT message, | 343 LRESULT HWNDMessageHandler::OnKeyEvent(UINT message, |
| 293 WPARAM w_param, | 344 WPARAM w_param, |
| 294 LPARAM l_param) { | 345 LPARAM l_param) { |
| 295 MSG msg = { hwnd(), message, w_param, l_param }; | 346 MSG msg = { hwnd(), message, w_param, l_param }; |
| 296 ui::KeyEvent key(msg, message == WM_CHAR); | 347 ui::KeyEvent key(msg, message == WM_CHAR); |
| 297 InputMethod* input_method = delegate_->GetInputMethod(); | 348 InputMethod* input_method = delegate_->GetInputMethod(); |
| 298 if (input_method) | 349 if (input_method) |
| 299 input_method->DispatchKeyEvent(key); | 350 input_method->DispatchKeyEvent(key); |
| 300 else | 351 else |
| 301 delegate_->AsNativeWidgetWin()->DispatchKeyEventPostIME(key); | 352 DispatchKeyEventPostIME(key); |
| 302 return 0; | 353 return 0; |
| 303 } | 354 } |
| 304 | 355 |
| 305 void HWNDMessageHandler::OnKillFocus(HWND focused_window) { | 356 void HWNDMessageHandler::OnKillFocus(HWND focused_window) { |
| 306 delegate_->HandleNativeBlur(focused_window); | 357 delegate_->HandleNativeBlur(focused_window); |
| 307 | 358 |
| 308 InputMethod* input_method = delegate_->GetInputMethod(); | 359 InputMethod* input_method = delegate_->GetInputMethod(); |
| 309 if (input_method) | 360 if (input_method) |
| 310 input_method->OnBlur(); | 361 input_method->OnBlur(); |
| 311 SetMsgHandled(FALSE); | 362 SetMsgHandled(FALSE); |
| 312 } | 363 } |
| 313 | 364 |
| 314 LRESULT HWNDMessageHandler::OnMouseActivate(UINT message, | 365 LRESULT HWNDMessageHandler::OnMouseActivate(UINT message, |
| 315 WPARAM w_param, | 366 WPARAM w_param, |
| 316 LPARAM l_param) { | 367 LPARAM l_param) { |
| 317 // TODO(beng): resolve this with the GetWindowLong() check on the subsequent | 368 // TODO(beng): resolve this with the GetWindowLong() check on the subsequent |
| 318 // line. | 369 // line. |
| 319 if (delegate_->IsWidgetWindow()) | 370 if (delegate_->IsWidgetWindow()) |
| 320 return delegate_->CanActivate() ? MA_ACTIVATE : MA_NOACTIVATEANDEAT; | 371 return delegate_->CanActivate() ? MA_ACTIVATE : MA_NOACTIVATEANDEAT; |
| 321 if (GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_NOACTIVATE) | 372 if (GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_NOACTIVATE) |
| 322 return MA_NOACTIVATE; | 373 return MA_NOACTIVATE; |
| 323 SetMsgHandled(FALSE); | 374 SetMsgHandled(FALSE); |
| 324 return MA_ACTIVATE; | 375 return MA_ACTIVATE; |
| 325 } | 376 } |
| 326 | 377 |
| 378 LRESULT HWNDMessageHandler::OnMouseRange(UINT message, |
| 379 WPARAM w_param, |
| 380 LPARAM l_param) { |
| 381 if (message == WM_RBUTTONUP && is_right_mouse_pressed_on_caption_) { |
| 382 is_right_mouse_pressed_on_caption_ = false; |
| 383 ReleaseCapture(); |
| 384 // |point| is in window coordinates, but WM_NCHITTEST and TrackPopupMenu() |
| 385 // expect screen coordinates. |
| 386 CPoint screen_point(l_param); |
| 387 MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1); |
| 388 w_param = SendMessage(hwnd(), WM_NCHITTEST, 0, |
| 389 MAKELPARAM(screen_point.x, screen_point.y)); |
| 390 if (w_param == HTCAPTION || w_param == HTSYSMENU) { |
| 391 ui::ShowSystemMenu(hwnd(), screen_point.x, screen_point.y); |
| 392 return 0; |
| 393 } |
| 394 } else if (message == WM_NCLBUTTONDOWN && delegate_->IsUsingCustomFrame()) { |
| 395 switch (w_param) { |
| 396 case HTCLOSE: |
| 397 case HTMINBUTTON: |
| 398 case HTMAXBUTTON: { |
| 399 // When the mouse is pressed down in these specific non-client areas, |
| 400 // we need to tell the RootView to send the mouse pressed event (which |
| 401 // sets capture, allowing subsequent WM_LBUTTONUP (note, _not_ |
| 402 // WM_NCLBUTTONUP) to fire so that the appropriate WM_SYSCOMMAND can be |
| 403 // sent by the applicable button's ButtonListener. We _have_ to do this |
| 404 // way rather than letting Windows just send the syscommand itself (as |
| 405 // would happen if we never did this dance) because for some insane |
| 406 // reason DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed |
| 407 // window control button appearance, in the Windows classic style, over |
| 408 // our view! Ick! By handling this message we prevent Windows from |
| 409 // doing this undesirable thing, but that means we need to roll the |
| 410 // sys-command handling ourselves. |
| 411 // Combine |w_param| with common key state message flags. |
| 412 w_param |= base::win::IsCtrlPressed() ? MK_CONTROL : 0; |
| 413 w_param |= base::win::IsShiftPressed() ? MK_SHIFT : 0; |
| 414 } |
| 415 } |
| 416 } else if (message == WM_NCRBUTTONDOWN && |
| 417 (w_param == HTCAPTION || w_param == HTSYSMENU)) { |
| 418 is_right_mouse_pressed_on_caption_ = true; |
| 419 // We SetCapture() to ensure we only show the menu when the button |
| 420 // down and up are both on the caption. Note: this causes the button up to |
| 421 // be WM_RBUTTONUP instead of WM_NCRBUTTONUP. |
| 422 SetCapture(); |
| 423 } |
| 424 |
| 425 MSG msg = { hwnd(), message, w_param, l_param, 0, |
| 426 { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) } }; |
| 427 ui::MouseEvent event(msg); |
| 428 if (!touch_ids_.empty() || ui::IsMouseEventFromTouch(message)) |
| 429 event.set_flags(event.flags() | ui::EF_FROM_TOUCH); |
| 430 |
| 431 if (!(event.flags() & ui::EF_IS_NON_CLIENT)) |
| 432 delegate_->HandleTooltipMouseMove(message, w_param, l_param); |
| 433 |
| 434 if (event.type() == ui::ET_MOUSE_MOVED && !HasCapture()) { |
| 435 // Windows only fires WM_MOUSELEAVE events if the application begins |
| 436 // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events. |
| 437 // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE. |
| 438 TrackMouseEvents((message == WM_NCMOUSEMOVE) ? |
| 439 TME_NONCLIENT | TME_LEAVE : TME_LEAVE); |
| 440 } else if (event.type() == ui::ET_MOUSE_EXITED) { |
| 441 // Reset our tracking flags so future mouse movement over this |
| 442 // NativeWidgetWin results in a new tracking session. Fall through for |
| 443 // OnMouseEvent. |
| 444 active_mouse_tracking_flags_ = 0; |
| 445 } else if (event.type() == ui::ET_MOUSEWHEEL) { |
| 446 // Reroute the mouse wheel to the window under the pointer if applicable. |
| 447 return (ui::RerouteMouseWheel(hwnd(), w_param, l_param) || |
| 448 delegate_->HandleMouseEvent(ui::MouseWheelEvent(msg))) ? 0 : 1; |
| 449 } |
| 450 |
| 451 bool handled = delegate_->HandleMouseEvent(event); |
| 452 if (!handled && message == WM_NCLBUTTONDOWN && w_param != HTSYSMENU && |
| 453 delegate_->IsUsingCustomFrame()) { |
| 454 // TODO(msw): Eliminate undesired painting, or re-evaluate this workaround. |
| 455 // DefWindowProc for WM_NCLBUTTONDOWN does weird non-client painting, so we |
| 456 // need to call it inside a ScopedRedrawLock. This may cause other negative |
| 457 // side-effects (ex/ stifling non-client mouse releases). |
| 458 DefWindowProcWithRedrawLock(message, w_param, l_param); |
| 459 handled = true; |
| 460 } |
| 461 |
| 462 SetMsgHandled(handled); |
| 463 return 0; |
| 464 } |
| 465 |
| 327 void HWNDMessageHandler::OnMove(const CPoint& point) { | 466 void HWNDMessageHandler::OnMove(const CPoint& point) { |
| 328 delegate_->HandleMove(); | 467 delegate_->HandleMove(); |
| 329 SetMsgHandled(FALSE); | 468 SetMsgHandled(FALSE); |
| 330 } | 469 } |
| 331 | 470 |
| 332 void HWNDMessageHandler::OnMoving(UINT param, const RECT* new_bounds) { | 471 void HWNDMessageHandler::OnMoving(UINT param, const RECT* new_bounds) { |
| 333 delegate_->HandleMove(); | 472 delegate_->HandleMove(); |
| 334 } | 473 } |
| 335 | 474 |
| 336 LRESULT HWNDMessageHandler::OnNCActivate(BOOL active) { | 475 LRESULT HWNDMessageHandler::OnNCActivate(BOOL active) { |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 RedrawWindow(hwnd(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); | 638 RedrawWindow(hwnd(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); |
| 500 // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've | 639 // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've |
| 501 // invoked OnSize we ensure the RootView has been laid out. | 640 // invoked OnSize we ensure the RootView has been laid out. |
| 502 ResetWindowRegion(false); | 641 ResetWindowRegion(false); |
| 503 } | 642 } |
| 504 | 643 |
| 505 void HWNDMessageHandler::OnThemeChanged() { | 644 void HWNDMessageHandler::OnThemeChanged() { |
| 506 ui::NativeThemeWin::instance()->CloseHandles(); | 645 ui::NativeThemeWin::instance()->CloseHandles(); |
| 507 } | 646 } |
| 508 | 647 |
| 648 LRESULT HWNDMessageHandler::OnTouchEvent(UINT message, |
| 649 WPARAM w_param, |
| 650 LPARAM l_param) { |
| 651 int num_points = LOWORD(w_param); |
| 652 scoped_array<TOUCHINPUT> input(new TOUCHINPUT[num_points]); |
| 653 if (GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(l_param), |
| 654 num_points, input.get(), sizeof(TOUCHINPUT))) { |
| 655 for (int i = 0; i < num_points; ++i) { |
| 656 if (input[i].dwFlags & TOUCHEVENTF_DOWN) |
| 657 touch_ids_.insert(input[i].dwID); |
| 658 if (input[i].dwFlags & TOUCHEVENTF_UP) |
| 659 touch_ids_.erase(input[i].dwID); |
| 660 } |
| 661 } |
| 662 CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(l_param)); |
| 663 SetMsgHandled(FALSE); |
| 664 return 0; |
| 665 } |
| 666 |
| 509 void HWNDMessageHandler::OnVScroll(int scroll_type, | 667 void HWNDMessageHandler::OnVScroll(int scroll_type, |
| 510 short position, | 668 short position, |
| 511 HWND scrollbar) { | 669 HWND scrollbar) { |
| 512 SetMsgHandled(FALSE); | 670 SetMsgHandled(FALSE); |
| 513 } | 671 } |
| 514 | 672 |
| 673 void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) { |
| 674 if (DidClientAreaSizeChange(window_pos)) |
| 675 ClientAreaSizeChanged(); |
| 676 if (remove_standard_frame_ && window_pos->flags & SWP_FRAMECHANGED && |
| 677 ui::win::IsAeroGlassEnabled()) { |
| 678 MARGINS m = {10, 10, 10, 10}; |
| 679 DwmExtendFrameIntoClientArea(hwnd(), &m); |
| 680 } |
| 681 if (window_pos->flags & SWP_SHOWWINDOW) |
| 682 delegate_->HandleVisibilityChanged(true); |
| 683 else if (window_pos->flags & SWP_HIDEWINDOW) |
| 684 delegate_->HandleVisibilityChanged(false); |
| 685 SetMsgHandled(FALSE); |
| 686 } |
| 687 |
| 515 void HWNDMessageHandler::ResetWindowRegion(bool force) { | 688 void HWNDMessageHandler::ResetWindowRegion(bool force) { |
| 516 // A native frame uses the native window region, and we don't want to mess | 689 // A native frame uses the native window region, and we don't want to mess |
| 517 // with it. | 690 // with it. |
| 518 if (!delegate_->IsUsingCustomFrame() || !delegate_->IsWidgetWindow()) { | 691 if (!delegate_->IsUsingCustomFrame() || !delegate_->IsWidgetWindow()) { |
| 519 if (force) | 692 if (force) |
| 520 SetWindowRgn(hwnd(), NULL, TRUE); | 693 SetWindowRgn(hwnd(), NULL, TRUE); |
| 521 return; | 694 return; |
| 522 } | 695 } |
| 523 | 696 |
| 524 // Changing the window region is going to force a paint. Only change the | 697 // Changing the window region is going to force a paint. Only change the |
| 525 // window region if the region really differs. | 698 // window region if the region really differs. |
| 526 HRGN current_rgn = CreateRectRgn(0, 0, 0, 0); | 699 HRGN current_rgn = CreateRectRgn(0, 0, 0, 0); |
| 527 int current_rgn_result = GetWindowRgn(hwnd(), current_rgn); | 700 int current_rgn_result = GetWindowRgn(hwnd(), current_rgn); |
| 528 | 701 |
| 529 CRect window_rect; | 702 CRect window_rect; |
| 530 GetWindowRect(hwnd(), &window_rect); | 703 GetWindowRect(hwnd(), &window_rect); |
| 531 HRGN new_region; | 704 HRGN new_region; |
| 532 if (delegate_->AsNativeWidgetWin()->IsMaximized()) { | 705 if (IsMaximized()) { |
| 533 HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST); | 706 HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST); |
| 534 MONITORINFO mi; | 707 MONITORINFO mi; |
| 535 mi.cbSize = sizeof mi; | 708 mi.cbSize = sizeof mi; |
| 536 GetMonitorInfo(monitor, &mi); | 709 GetMonitorInfo(monitor, &mi); |
| 537 CRect work_rect = mi.rcWork; | 710 CRect work_rect = mi.rcWork; |
| 538 work_rect.OffsetRect(-window_rect.left, -window_rect.top); | 711 work_rect.OffsetRect(-window_rect.left, -window_rect.top); |
| 539 new_region = CreateRectRgnIndirect(&work_rect); | 712 new_region = CreateRectRgnIndirect(&work_rect); |
| 540 } else { | 713 } else { |
| 541 gfx::Path window_mask; | 714 gfx::Path window_mask; |
| 542 delegate_->GetWindowMask( | 715 delegate_->GetWindowMask( |
| 543 gfx::Size(window_rect.Width(), window_rect.Height()), &window_mask); | 716 gfx::Size(window_rect.Width(), window_rect.Height()), &window_mask); |
| 544 new_region = window_mask.CreateNativeRegion(); | 717 new_region = window_mask.CreateNativeRegion(); |
| 545 } | 718 } |
| 546 | 719 |
| 547 if (current_rgn_result == ERROR || !EqualRgn(current_rgn, new_region)) { | 720 if (current_rgn_result == ERROR || !EqualRgn(current_rgn, new_region)) { |
| 548 // SetWindowRgn takes ownership of the HRGN created by CreateNativeRegion. | 721 // SetWindowRgn takes ownership of the HRGN created by CreateNativeRegion. |
| 549 SetWindowRgn(hwnd(), new_region, TRUE); | 722 SetWindowRgn(hwnd(), new_region, TRUE); |
| 550 } else { | 723 } else { |
| 551 DeleteObject(new_region); | 724 DeleteObject(new_region); |
| 552 } | 725 } |
| 553 | 726 |
| 554 DeleteObject(current_rgn); | 727 DeleteObject(current_rgn); |
| 555 } | 728 } |
| 556 | 729 |
| 557 //////////////////////////////////////////////////////////////////////////////// | 730 //////////////////////////////////////////////////////////////////////////////// |
| 731 // HWNDMessageHandler, InputMethodDelegate implementation: |
| 732 |
| 733 void HWNDMessageHandler::DispatchKeyEventPostIME(const ui::KeyEvent& key) { |
| 734 SetMsgHandled(delegate_->HandleKeyEvent(key)); |
| 735 } |
| 736 |
| 737 //////////////////////////////////////////////////////////////////////////////// |
| 558 // HWNDMessageHandler, private: | 738 // HWNDMessageHandler, private: |
| 559 | 739 |
| 740 void HWNDMessageHandler::TrackMouseEvents(DWORD mouse_tracking_flags) { |
| 741 // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE |
| 742 // when the user moves the mouse outside this HWND's bounds. |
| 743 if (active_mouse_tracking_flags_ == 0 || mouse_tracking_flags & TME_CANCEL) { |
| 744 if (mouse_tracking_flags & TME_CANCEL) { |
| 745 // We're about to cancel active mouse tracking, so empty out the stored |
| 746 // state. |
| 747 active_mouse_tracking_flags_ = 0; |
| 748 } else { |
| 749 active_mouse_tracking_flags_ = mouse_tracking_flags; |
| 750 } |
| 751 |
| 752 TRACKMOUSEEVENT tme; |
| 753 tme.cbSize = sizeof(tme); |
| 754 tme.dwFlags = mouse_tracking_flags; |
| 755 tme.hwndTrack = hwnd(); |
| 756 tme.dwHoverTime = 0; |
| 757 TrackMouseEvent(&tme); |
| 758 } else if (mouse_tracking_flags != active_mouse_tracking_flags_) { |
| 759 TrackMouseEvents(active_mouse_tracking_flags_ | TME_CANCEL); |
| 760 TrackMouseEvents(mouse_tracking_flags); |
| 761 } |
| 762 } |
| 763 |
| 764 void HWNDMessageHandler::ClientAreaSizeChanged() { |
| 765 RECT r = {0, 0, 0, 0}; |
| 766 if (delegate_->AsNativeWidgetWin()->WidgetSizeIsClientSize()) { |
| 767 // TODO(beng): investigate whether this could be done |
| 768 // from other branch of if-else. |
| 769 if (!IsMinimized()) |
| 770 GetClientRect(hwnd(), &r); |
| 771 } else { |
| 772 GetWindowRect(hwnd(), &r); |
| 773 } |
| 774 gfx::Size s(std::max(0, static_cast<int>(r.right - r.left)), |
| 775 std::max(0, static_cast<int>(r.bottom - r.top))); |
| 776 delegate_->HandleClientSizeChanged(s); |
| 777 } |
| 778 |
| 779 // A scoping class that prevents a window from being able to redraw in response |
| 780 // to invalidations that may occur within it for the lifetime of the object. |
| 781 // |
| 782 // Why would we want such a thing? Well, it turns out Windows has some |
| 783 // "unorthodox" behavior when it comes to painting its non-client areas. |
| 784 // Occasionally, Windows will paint portions of the default non-client area |
| 785 // right over the top of the custom frame. This is not simply fixed by handling |
| 786 // WM_NCPAINT/WM_PAINT, with some investigation it turns out that this |
| 787 // rendering is being done *inside* the default implementation of some message |
| 788 // handlers and functions: |
| 789 // . WM_SETTEXT |
| 790 // . WM_SETICON |
| 791 // . WM_NCLBUTTONDOWN |
| 792 // . EnableMenuItem, called from our WM_INITMENU handler |
| 793 // The solution is to handle these messages and call DefWindowProc ourselves, |
| 794 // but prevent the window from being able to update itself for the duration of |
| 795 // the call. We do this with this class, which automatically calls its |
| 796 // associated Window's lock and unlock functions as it is created and destroyed. |
| 797 // See documentation in those methods for the technique used. |
| 798 // |
| 799 // The lock only has an effect if the window was visible upon lock creation, as |
| 800 // it doesn't guard against direct visiblility changes, and multiple locks may |
| 801 // exist simultaneously to handle certain nested Windows messages. |
| 802 // |
| 803 // IMPORTANT: Do not use this scoping object for large scopes or periods of |
| 804 // time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh). |
| 805 // |
| 806 // I would love to hear Raymond Chen's explanation for all this. And maybe a |
| 807 // list of other messages that this applies to ;-) |
| 808 class HWNDMessageHandler::ScopedRedrawLock { |
| 809 public: |
| 810 explicit ScopedRedrawLock(HWNDMessageHandler* owner) |
| 811 : owner_(owner), |
| 812 hwnd_(owner_->hwnd()), |
| 813 was_visible_(owner_->IsVisible()), |
| 814 cancel_unlock_(false), |
| 815 force_(!(GetWindowLong(hwnd_, GWL_STYLE) & WS_CAPTION)) { |
| 816 if (was_visible_ && ::IsWindow(hwnd_)) |
| 817 owner_->LockUpdates(force_); |
| 818 } |
| 819 |
| 820 ~ScopedRedrawLock() { |
| 821 if (!cancel_unlock_ && was_visible_ && ::IsWindow(hwnd_)) |
| 822 owner_->UnlockUpdates(force_); |
| 823 } |
| 824 |
| 825 // Cancel the unlock operation, call this if the Widget is being destroyed. |
| 826 void CancelUnlockOperation() { cancel_unlock_ = true; } |
| 827 |
| 828 private: |
| 829 // The owner having its style changed. |
| 830 HWNDMessageHandler* owner_; |
| 831 // The owner's HWND, cached to avoid action after window destruction. |
| 832 HWND hwnd_; |
| 833 // Records the HWND visibility at the time of creation. |
| 834 bool was_visible_; |
| 835 // A flag indicating that the unlock operation was canceled. |
| 836 bool cancel_unlock_; |
| 837 // If true, perform the redraw lock regardless of Aero state. |
| 838 bool force_; |
| 839 |
| 840 DISALLOW_COPY_AND_ASSIGN(ScopedRedrawLock); |
| 841 }; |
| 842 |
| 843 LRESULT HWNDMessageHandler::DefWindowProcWithRedrawLock(UINT message, |
| 844 WPARAM w_param, |
| 845 LPARAM l_param) { |
| 846 ScopedRedrawLock lock(this); |
| 847 // The Widget and HWND can be destroyed in the call to DefWindowProc, so use |
| 848 // the |destroyed_| flag to avoid unlocking (and crashing) after destruction. |
| 849 bool destroyed = false; |
| 850 destroyed_ = &destroyed; |
| 851 LRESULT result = DefWindowProc(hwnd(), message, w_param, l_param); |
| 852 if (destroyed) |
| 853 lock.CancelUnlockOperation(); |
| 854 else |
| 855 destroyed_ = NULL; |
| 856 return result; |
| 857 } |
| 858 |
| 859 void HWNDMessageHandler::LockUpdates(bool force) { |
| 860 // We skip locked updates when Aero is on for two reasons: |
| 861 // 1. Because it isn't necessary |
| 862 // 2. Because toggling the WS_VISIBLE flag may occur while the GPU process is |
| 863 // attempting to present a child window's backbuffer onscreen. When these |
| 864 // two actions race with one another, the child window will either flicker |
| 865 // or will simply stop updating entirely. |
| 866 if ((force || !ui::win::IsAeroGlassEnabled()) && ++lock_updates_count_ == 1) { |
| 867 SetWindowLong(hwnd(), GWL_STYLE, |
| 868 GetWindowLong(hwnd(), GWL_STYLE) & ~WS_VISIBLE); |
| 869 } |
| 870 } |
| 871 |
| 872 void HWNDMessageHandler::UnlockUpdates(bool force) { |
| 873 if ((force || !ui::win::IsAeroGlassEnabled()) && --lock_updates_count_ <= 0) { |
| 874 SetWindowLong(hwnd(), GWL_STYLE, |
| 875 GetWindowLong(hwnd(), GWL_STYLE) | WS_VISIBLE); |
| 876 lock_updates_count_ = 0; |
| 877 } |
| 878 } |
| 879 |
| 560 HWND HWNDMessageHandler::hwnd() { | 880 HWND HWNDMessageHandler::hwnd() { |
| 561 return delegate_->AsNativeWidgetWin()->hwnd(); | 881 return delegate_->AsNativeWidgetWin()->hwnd(); |
| 562 } | 882 } |
| 563 | 883 |
| 564 HWND HWNDMessageHandler::hwnd() const { | 884 HWND HWNDMessageHandler::hwnd() const { |
| 565 return delegate_->AsNativeWidgetWin()->hwnd(); | 885 return delegate_->AsNativeWidgetWin()->hwnd(); |
| 566 } | 886 } |
| 567 | 887 |
| 568 LRESULT HWNDMessageHandler::DefWindowProcWithRedrawLock(UINT message, | |
| 569 WPARAM w_param, | |
| 570 LPARAM l_param) { | |
| 571 return delegate_->AsNativeWidgetWin()->DefWindowProcWithRedrawLock(message, | |
| 572 w_param, | |
| 573 l_param); | |
| 574 } | |
| 575 | |
| 576 void HWNDMessageHandler::SetMsgHandled(BOOL handled) { | 888 void HWNDMessageHandler::SetMsgHandled(BOOL handled) { |
| 577 delegate_->AsNativeWidgetWin()->SetMsgHandled(handled); | 889 delegate_->AsNativeWidgetWin()->SetMsgHandled(handled); |
| 578 } | 890 } |
| 579 | 891 |
| 580 } // namespace views | 892 } // namespace views |
| 581 | |
| OLD | NEW |