Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "chrome/views/widget/widget_win.h" | 5 #include "chrome/views/widget/widget_win.h" |
| 6 | 6 |
| 7 #include "base/gfx/native_theme.h" | 7 #include "base/gfx/native_theme.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "base/win_util.h" | 9 #include "base/win_util.h" |
| 10 #include "chrome/app/chrome_dll_resource.h" | 10 #include "chrome/app/chrome_dll_resource.h" |
| 11 #include "chrome/common/gfx/chrome_canvas.h" | 11 #include "chrome/common/gfx/chrome_canvas.h" |
| 12 #include "chrome/common/notification_service.h" | 12 #include "chrome/common/notification_service.h" |
| 13 #include "chrome/common/win_util.h" | 13 #include "chrome/common/win_util.h" |
| 14 #include "chrome/views/accessibility/view_accessibility.h" | 14 #include "chrome/views/accessibility/view_accessibility.h" |
| 15 #include "chrome/views/controls/native_control_win.h" | 15 #include "chrome/views/controls/native_control_win.h" |
| 16 #include "chrome/views/fill_layout.h" | 16 #include "chrome/views/fill_layout.h" |
| 17 #include "chrome/views/focus/focus_util_win.h" | 17 #include "chrome/views/focus/focus_util_win.h" |
| 18 #include "chrome/views/widget/aero_tooltip_manager.h" | 18 #include "chrome/views/widget/aero_tooltip_manager.h" |
| 19 #include "chrome/views/widget/hwnd_notification_source.h" | 19 #include "chrome/views/widget/hwnd_notification_source.h" |
| 20 #include "chrome/views/widget/root_view.h" | 20 #include "chrome/views/widget/root_view.h" |
| 21 | 21 |
| 22 namespace { | |
| 23 | |
| 24 bool GetMonitorAndWorkAreaForRect(const RECT& rect, | |
| 25 HMONITOR* monitor, | |
| 26 gfx::Rect* work_area) { | |
| 27 DCHECK(monitor); | |
| 28 DCHECK(work_area); | |
| 29 *monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST); | |
| 30 if (!*monitor) | |
| 31 return false; | |
| 32 MONITORINFO monitor_info = { 0 }; | |
| 33 monitor_info.cbSize = sizeof(monitor_info); | |
| 34 GetMonitorInfo(*monitor, &monitor_info); | |
| 35 *work_area = monitor_info.rcWork; | |
| 36 return true; | |
| 37 } | |
| 38 | |
| 39 } // namespace | |
| 40 | |
| 22 namespace views { | 41 namespace views { |
| 23 | 42 |
| 24 static const DWORD kWindowDefaultChildStyle = | 43 static const DWORD kWindowDefaultChildStyle = |
| 25 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; | 44 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; |
| 26 static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW; | 45 static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW; |
| 27 static const DWORD kWindowDefaultExStyle = 0; | 46 static const DWORD kWindowDefaultExStyle = 0; |
| 28 | 47 |
| 29 // Property used to link the HWND to its RootView. | 48 // Property used to link the HWND to its RootView. |
| 30 static const wchar_t* const kRootViewWindowProperty = L"__ROOT_VIEW__"; | 49 static const wchar_t* const kRootViewWindowProperty = L"__ROOT_VIEW__"; |
| 31 | 50 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 typedef std::list<RegisteredClass> RegisteredClasses; | 113 typedef std::list<RegisteredClass> RegisteredClasses; |
| 95 | 114 |
| 96 // The list of registered classes. | 115 // The list of registered classes. |
| 97 static RegisteredClasses* registered_classes = NULL; | 116 static RegisteredClasses* registered_classes = NULL; |
| 98 | 117 |
| 99 | 118 |
| 100 /////////////////////////////////////////////////////////////////////////////// | 119 /////////////////////////////////////////////////////////////////////////////// |
| 101 // WidgetWin, public | 120 // WidgetWin, public |
| 102 | 121 |
| 103 WidgetWin::WidgetWin() | 122 WidgetWin::WidgetWin() |
| 104 : active_mouse_tracking_flags_(0), | 123 : close_widget_factory_(this), |
| 124 ignore_pos_changes_factory_(this), | |
| 125 active_mouse_tracking_flags_(0), | |
| 105 has_capture_(false), | 126 has_capture_(false), |
| 106 current_action_(FA_NONE), | 127 current_action_(FA_NONE), |
| 107 toplevel_(false), | 128 toplevel_(false), |
| 108 window_style_(0), | 129 window_style_(0), |
| 109 window_ex_style_(kWindowDefaultExStyle), | 130 window_ex_style_(kWindowDefaultExStyle), |
| 110 use_layered_buffer_(true), | 131 use_layered_buffer_(true), |
| 111 layered_alpha_(255), | 132 layered_alpha_(255), |
| 112 delete_on_destroy_(true), | 133 delete_on_destroy_(true), |
| 113 can_update_layered_window_(true), | 134 can_update_layered_window_(true), |
| 114 last_mouse_event_was_move_(false), | 135 last_mouse_event_was_move_(false), |
| 115 is_mouse_down_(false), | 136 is_mouse_down_(false), |
| 116 class_style_(CS_DBLCLKS), | 137 class_style_(CS_DBLCLKS), |
| 117 hwnd_(NULL), | 138 hwnd_(NULL), |
| 118 close_widget_factory_(this) { | 139 last_monitor_(NULL), |
| 140 ignore_window_pos_changes_(false) { | |
| 119 } | 141 } |
| 120 | 142 |
| 121 WidgetWin::~WidgetWin() { | 143 WidgetWin::~WidgetWin() { |
| 122 MessageLoopForUI::current()->RemoveObserver(this); | 144 MessageLoopForUI::current()->RemoveObserver(this); |
| 123 } | 145 } |
| 124 | 146 |
| 125 void WidgetWin::Init(HWND parent, const gfx::Rect& bounds, | 147 void WidgetWin::Init(HWND parent, const gfx::Rect& bounds, |
| 126 bool has_own_focus_manager) { | 148 bool has_own_focus_manager) { |
| 127 toplevel_ = parent == NULL; | 149 toplevel_ = parent == NULL; |
| 128 | 150 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 144 parent = NULL; | 166 parent = NULL; |
| 145 } | 167 } |
| 146 | 168 |
| 147 hwnd_ = CreateWindowEx(window_ex_style_, GetWindowClassName().c_str(), L"", | 169 hwnd_ = CreateWindowEx(window_ex_style_, GetWindowClassName().c_str(), L"", |
| 148 window_style_, bounds.x(), bounds.y(), bounds.width(), | 170 window_style_, bounds.x(), bounds.y(), bounds.width(), |
| 149 bounds.height(), parent, NULL, NULL, this); | 171 bounds.height(), parent, NULL, NULL, this); |
| 150 DCHECK(hwnd_); | 172 DCHECK(hwnd_); |
| 151 TRACK_HWND_CREATION(hwnd_); | 173 TRACK_HWND_CREATION(hwnd_); |
| 152 SetWindowSupportsRerouteMouseWheel(hwnd_); | 174 SetWindowSupportsRerouteMouseWheel(hwnd_); |
| 153 | 175 |
| 176 GetMonitorAndWorkAreaForRect(bounds.ToRECT(), &last_monitor_, | |
| 177 &last_work_area_); | |
| 178 | |
| 154 // The window procedure should have set the data for us. | 179 // The window procedure should have set the data for us. |
| 155 DCHECK(win_util::GetWindowUserData(hwnd_) == this); | 180 DCHECK(win_util::GetWindowUserData(hwnd_) == this); |
| 156 | 181 |
| 157 root_view_->OnWidgetCreated(); | 182 root_view_->OnWidgetCreated(); |
| 158 | 183 |
| 159 if (has_own_focus_manager) { | 184 if (has_own_focus_manager) { |
| 160 FocusManager::CreateFocusManager(hwnd_, GetRootView()); | 185 FocusManager::CreateFocusManager(hwnd_, GetRootView()); |
| 161 } else { | 186 } else { |
| 162 // Subclass the window so we get the tab key messages when a view with no | 187 // Subclass the window so we get the tab key messages when a view with no |
| 163 // associated native window is focused. | 188 // associated native window is focused. |
| (...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 659 void WidgetWin::OnRButtonUp(UINT flags, const CPoint& point) { | 684 void WidgetWin::OnRButtonUp(UINT flags, const CPoint& point) { |
| 660 ProcessMouseReleased(point, flags | MK_RBUTTON); | 685 ProcessMouseReleased(point, flags | MK_RBUTTON); |
| 661 } | 686 } |
| 662 | 687 |
| 663 void WidgetWin::OnRButtonDblClk(UINT flags, const CPoint& point) { | 688 void WidgetWin::OnRButtonDblClk(UINT flags, const CPoint& point) { |
| 664 ProcessMousePressed(point, flags | MK_RBUTTON, true, false); | 689 ProcessMousePressed(point, flags | MK_RBUTTON, true, false); |
| 665 } | 690 } |
| 666 | 691 |
| 667 void WidgetWin::OnSettingChange(UINT flags, const wchar_t* section) { | 692 void WidgetWin::OnSettingChange(UINT flags, const wchar_t* section) { |
| 668 if (toplevel_ && (flags == SPI_SETWORKAREA)) { | 693 if (toplevel_ && (flags == SPI_SETWORKAREA)) { |
| 669 AdjustWindowToFitScreenSize(); | 694 // Fire a dummy SetWindowPos() call, so we'll trip the code in |
| 695 // OnWindowPosChanging() below that notices work area changes. | |
| 696 ::SetWindowPos(GetNativeView(), 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | | |
| 697 SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_NOOWNERZORDER); | |
| 670 SetMsgHandled(TRUE); | 698 SetMsgHandled(TRUE); |
| 671 } | 699 } |
| 672 } | 700 } |
| 673 | 701 |
| 674 void WidgetWin::OnSize(UINT param, const CSize& size) { | 702 void WidgetWin::OnSize(UINT param, const CSize& size) { |
| 675 ChangeSize(param, size); | 703 ChangeSize(param, size); |
| 676 } | 704 } |
| 677 | 705 |
| 678 void WidgetWin::OnThemeChanged() { | 706 void WidgetWin::OnThemeChanged() { |
| 679 // Notify NativeTheme. | 707 // Notify NativeTheme. |
| 680 gfx::NativeTheme::instance()->CloseHandles(); | 708 gfx::NativeTheme::instance()->CloseHandles(); |
| 681 } | 709 } |
| 682 | 710 |
| 711 void WidgetWin::OnWindowPosChanging(WINDOWPOS* window_pos) { | |
| 712 if (ignore_window_pos_changes_) { | |
| 713 // If somebody's trying to toggle our visibility, change the nonclient area, | |
| 714 // change our Z-order, or activate us, we should probably let it go through. | |
| 715 if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) | | |
| 716 SWP_FRAMECHANGED)) && | |
| 717 (window_pos->flags & (SWP_NOZORDER | SWP_NOACTIVATE))) { | |
| 718 // Just sizing/moving the window; ignore. | |
| 719 window_pos->flags |= SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW; | |
| 720 window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW); | |
| 721 } | |
| 722 } else if (toplevel_) { | |
|
Ben Goodger (Google)
2009/04/10 19:59:03
Can you just use !GetParent() here instead? I want
Peter Kasting
2009/04/10 20:05:02
Yep, and I can just remove toplevel_ entirely, goi
| |
| 723 CRect window_rect; | |
| 724 HMONITOR monitor; | |
| 725 gfx::Rect work_area; | |
| 726 if (GetWindowRect(&window_rect) && | |
| 727 GetMonitorAndWorkAreaForRect(window_rect, &monitor, &work_area)) { | |
| 728 if ((monitor == last_monitor_) && (work_area != last_work_area_)) { | |
| 729 // The work area for the monitor we're on changed. Normally Windows | |
| 730 // notifies us about this (and thus we're reaching here due to the | |
| 731 // SetWindowPos() call in OnSettingChange() above), but with some | |
| 732 // software (e.g. nVidia's nView desktop manager) the work area can | |
| 733 // change asynchronous to any notification, and we're just sent a | |
| 734 // SetWindowPos() call with a new (frequently incorrect) position/size. | |
| 735 // In either case, the best response is to throw away the existing | |
| 736 // position/size information in |window_pos| and recalculate it based on | |
| 737 // the old window coordinates, adjusted for the change in the work area. | |
| 738 if (IsZoomed()) { | |
| 739 window_pos->x = window_rect.left + work_area.x() - last_work_area_.x() ; | |
| 740 window_pos->y = window_rect.top + work_area.y() - last_work_area_.y(); | |
| 741 window_pos->cx = window_rect.Width() + work_area.width() - | |
| 742 last_work_area_.width(); | |
| 743 window_pos->cy = window_rect.Height() + work_area.height() - | |
| 744 last_work_area_.height(); | |
| 745 } else { | |
| 746 gfx::Rect window_gfx_rect(window_rect); | |
| 747 gfx::Rect new_window_rect = window_gfx_rect.AdjustToFit(work_area); | |
| 748 window_pos->x = new_window_rect.x(); | |
| 749 window_pos->y = new_window_rect.y(); | |
| 750 window_pos->cx = new_window_rect.width(); | |
| 751 window_pos->cy = new_window_rect.height(); | |
| 752 } | |
| 753 // WARNING! Don't set SWP_FRAMECHANGED here, it breaks moving the child | |
| 754 // HWNDs for some reason. | |
| 755 window_pos->flags &= ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW); | |
| 756 window_pos->flags |= SWP_NOCOPYBITS; | |
| 757 | |
| 758 // Now ignore all immediately-following SetWindowPos() changes. Windows | |
| 759 // likes to (incorrectly) recalculate what our position/size should be | |
| 760 // and send us further updates. | |
| 761 ignore_window_pos_changes_ = true; | |
| 762 DCHECK(ignore_pos_changes_factory_.empty()); | |
| 763 MessageLoop::current()->PostTask(FROM_HERE, | |
| 764 ignore_pos_changes_factory_.NewRunnableMethod( | |
| 765 &WidgetWin::StopIgnoringPosChanges)); | |
| 766 } | |
| 767 last_monitor_ = monitor; | |
| 768 last_work_area_ = work_area; | |
| 769 } | |
| 770 } | |
| 771 | |
| 772 SetMsgHandled(FALSE); | |
| 773 } | |
| 774 | |
| 683 void WidgetWin::OnFinalMessage(HWND window) { | 775 void WidgetWin::OnFinalMessage(HWND window) { |
| 684 if (delete_on_destroy_) | 776 if (delete_on_destroy_) |
| 685 delete this; | 777 delete this; |
| 686 } | 778 } |
| 687 | 779 |
| 688 /////////////////////////////////////////////////////////////////////////////// | 780 /////////////////////////////////////////////////////////////////////////////// |
| 689 // WidgetWin, protected: | 781 // WidgetWin, protected: |
| 690 | 782 |
| 691 void WidgetWin::TrackMouseEvents(DWORD mouse_tracking_flags) { | 783 void WidgetWin::TrackMouseEvents(DWORD mouse_tracking_flags) { |
| 692 // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE | 784 // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 795 } | 887 } |
| 796 | 888 |
| 797 void WidgetWin::ProcessMouseExited() { | 889 void WidgetWin::ProcessMouseExited() { |
| 798 last_mouse_event_was_move_ = false; | 890 last_mouse_event_was_move_ = false; |
| 799 root_view_->ProcessOnMouseExited(); | 891 root_view_->ProcessOnMouseExited(); |
| 800 // Reset our tracking flag so that future mouse movement over this WidgetWin | 892 // Reset our tracking flag so that future mouse movement over this WidgetWin |
| 801 // results in a new tracking session. | 893 // results in a new tracking session. |
| 802 active_mouse_tracking_flags_ = 0; | 894 active_mouse_tracking_flags_ = 0; |
| 803 } | 895 } |
| 804 | 896 |
| 805 void WidgetWin::AdjustWindowToFitScreenSize() { | |
| 806 // Desktop size has changed. Make sure we're still on screen. | |
| 807 CRect wr; | |
| 808 GetWindowRect(&wr); | |
| 809 HMONITOR hmon = MonitorFromRect(&wr, MONITOR_DEFAULTTONEAREST); | |
| 810 if (!hmon) { | |
| 811 // No monitor available. | |
| 812 return; | |
| 813 } | |
| 814 | |
| 815 MONITORINFO mi; | |
| 816 mi.cbSize = sizeof(mi); | |
| 817 GetMonitorInfo(hmon, &mi); | |
| 818 gfx::Rect window_rect(wr); | |
| 819 gfx::Rect monitor_rect(mi.rcWork); | |
| 820 gfx::Rect new_window_rect = window_rect.AdjustToFit(monitor_rect); | |
| 821 if (!new_window_rect.Equals(window_rect)) { | |
| 822 // New position differs from last, resize window. | |
| 823 ::SetWindowPos(GetNativeView(), | |
| 824 0, | |
| 825 new_window_rect.x(), | |
| 826 new_window_rect.y(), | |
| 827 new_window_rect.width(), | |
| 828 new_window_rect.height(), | |
| 829 SWP_NOACTIVATE | SWP_NOZORDER); | |
| 830 } | |
| 831 } | |
| 832 | |
| 833 void WidgetWin::ChangeSize(UINT size_param, const CSize& size) { | 897 void WidgetWin::ChangeSize(UINT size_param, const CSize& size) { |
| 834 CRect rect; | 898 CRect rect; |
| 835 if (use_layered_buffer_) { | 899 if (use_layered_buffer_) { |
| 836 GetWindowRect(&rect); | 900 GetWindowRect(&rect); |
| 837 SizeContents(rect); | 901 SizeContents(rect); |
| 838 } else { | 902 } else { |
| 839 GetClientRect(&rect); | 903 GetClientRect(&rect); |
| 840 } | 904 } |
| 841 | 905 |
| 842 // Resizing changes the size of the view hierarchy and thus forces a | 906 // Resizing changes the size of the view hierarchy and thus forces a |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1000 result = DefWindowProc(window, message, w_param, l_param); | 1064 result = DefWindowProc(window, message, w_param, l_param); |
| 1001 if (message == WM_NCDESTROY) { | 1065 if (message == WM_NCDESTROY) { |
| 1002 TRACK_HWND_DESTRUCTION(window); | 1066 TRACK_HWND_DESTRUCTION(window); |
| 1003 widget->hwnd_ = NULL; | 1067 widget->hwnd_ = NULL; |
| 1004 widget->OnFinalMessage(window); | 1068 widget->OnFinalMessage(window); |
| 1005 } | 1069 } |
| 1006 return result; | 1070 return result; |
| 1007 } | 1071 } |
| 1008 | 1072 |
| 1009 } // namespace views | 1073 } // namespace views |
| OLD | NEW |