diff options
Diffstat (limited to 'ui/views/win/hwnd_message_handler.cc')
-rw-r--r-- | ui/views/win/hwnd_message_handler.cc | 345 |
1 files changed, 1 insertions, 344 deletions
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index fa28e3c..5c8641c 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc @@ -5,26 +5,19 @@ #include "ui/views/win/hwnd_message_handler.h" #include <dwmapi.h> -#include <shellapi.h> -#include "base/bind.h" #include "base/system_monitor/system_monitor.h" #include "base/win/windows_version.h" -#include "ui/gfx/insets.h" #include "ui/gfx/path.h" #include "ui/base/event.h" -#include "ui/base/keycodes/keyboard_code_conversion_win.h" #include "ui/base/native_theme/native_theme_win.h" #include "ui/base/win/hwnd_util.h" #include "ui/base/win/mouse_wheel_util.h" #include "ui/base/win/shell.h" #include "ui/views/ime/input_method_win.h" -#include "ui/views/widget/monitor_win.h" #include "ui/views/widget/native_widget_win.h" #include "ui/views/widget/widget_hwnd_utils.h" -#include "ui/views/win/fullscreen_handler.h" #include "ui/views/win/hwnd_message_handler_delegate.h" -#include "ui/views/win/scoped_fullscreen_visibility.h" #if !defined(USE_AURA) #include "base/command_line.h" @@ -45,31 +38,10 @@ BOOL CALLBACK EnumChildWindowsForRedraw(HWND hwnd, LPARAM lparam) { return TRUE; } -bool GetMonitorAndRects(const RECT& rect, - HMONITOR* monitor, - gfx::Rect* monitor_rect, - gfx::Rect* work_area) { - DCHECK(monitor); - DCHECK(monitor_rect); - DCHECK(work_area); - *monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL); - if (!*monitor) - return false; - MONITORINFO monitor_info = { 0 }; - monitor_info.cbSize = sizeof(monitor_info); - GetMonitorInfo(*monitor, &monitor_info); - *monitor_rect = monitor_info.rcMonitor; - *work_area = monitor_info.rcWork; - return true; -} - // A custom MSAA object id used to determine if a screen reader is actively // listening for MSAA events. const int kCustomObjectID = 1; -// The thickness of an auto-hide taskbar in pixels. -const int kAutoHideTaskbarThicknessPx = 2; - } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -77,16 +49,11 @@ const int kAutoHideTaskbarThicknessPx = 2; HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate) : delegate_(delegate), - ALLOW_THIS_IN_INITIALIZER_LIST(fullscreen_handler_(new FullscreenHandler( - delegate->AsNativeWidgetWin()->GetWidget()))), remove_standard_frame_(false), active_mouse_tracking_flags_(0), is_right_mouse_pressed_on_caption_(false), lock_updates_count_(0), - destroyed_(NULL), - ignore_window_pos_changes_(false), - ALLOW_THIS_IN_INITIALIZER_LIST(ignore_pos_changes_factory_(this)), - last_monitor_(NULL) { + destroyed_(NULL) { } HWNDMessageHandler::~HWNDMessageHandler() { @@ -94,53 +61,6 @@ HWNDMessageHandler::~HWNDMessageHandler() { *destroyed_ = true; } -void HWNDMessageHandler::Init(const gfx::Rect& bounds) { - GetMonitorAndRects(bounds.ToRECT(), &last_monitor_, &last_monitor_rect_, - &last_work_area_); -} - -gfx::Rect HWNDMessageHandler::GetRestoredBounds() const { - // If we're in fullscreen mode, we've changed the normal bounds to the monitor - // rect, so return the saved bounds instead. - if (fullscreen_handler_->fullscreen()) - return fullscreen_handler_->GetRestoreBounds(); - - gfx::Rect bounds; - GetWindowPlacement(&bounds, NULL); - return bounds; -} - -void HWNDMessageHandler::GetWindowPlacement( - gfx::Rect* bounds, - ui::WindowShowState* show_state) const { - WINDOWPLACEMENT wp; - wp.length = sizeof(wp); - const bool succeeded = !!::GetWindowPlacement(hwnd(), &wp); - DCHECK(succeeded); - - if (bounds != NULL) { - MONITORINFO mi; - mi.cbSize = sizeof(mi); - const bool succeeded = !!GetMonitorInfo( - MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST), &mi); - DCHECK(succeeded); - *bounds = gfx::Rect(wp.rcNormalPosition); - // Convert normal position from workarea coordinates to screen coordinates. - bounds->Offset(mi.rcWork.left - mi.rcMonitor.left, - mi.rcWork.top - mi.rcMonitor.top); - } - - if (show_state) { - if (wp.showCmd == SW_SHOWMAXIMIZED) - *show_state = ui::SHOW_STATE_MAXIMIZED; - else if (wp.showCmd == SW_SHOWMINIMIZED) - *show_state = ui::SHOW_STATE_MINIMIZED; - else - *show_state = ui::SHOW_STATE_NORMAL; - } -} - - bool HWNDMessageHandler::IsVisible() const { return !!::IsWindowVisible(hwnd()); } @@ -599,89 +519,6 @@ LRESULT HWNDMessageHandler::OnNCActivate(BOOL active) { WM_NCACTIVATE, inactive_rendering_disabled || active, 0); } -LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) { - // We only override the default handling if we need to specify a custom - // non-client edge width. Note that in most cases "no insets" means no - // custom width, but in fullscreen mode or when the NonClientFrameView - // requests it, we want a custom width of 0. - gfx::Insets insets = GetClientAreaInsets(); - if (insets.empty() && !fullscreen_handler_->fullscreen() && - !(mode && remove_standard_frame_)) { - SetMsgHandled(FALSE); - return 0; - } - - RECT* client_rect = mode ? - &(reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0]) : - reinterpret_cast<RECT*>(l_param); - client_rect->left += insets.left(); - client_rect->top += insets.top(); - client_rect->bottom -= insets.bottom(); - client_rect->right -= insets.right(); - if (IsMaximized()) { - // Find all auto-hide taskbars along the screen edges and adjust in by the - // thickness of the auto-hide taskbar on each such edge, so the window isn't - // treated as a "fullscreen app", which would cause the taskbars to - // disappear. - HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONULL); - if (!monitor) { - // We might end up here if the window was previously minimized and the - // user clicks on the taskbar button to restore it in the previously - // maximized position. In that case WM_NCCALCSIZE is sent before the - // window coordinates are restored to their previous values, so our - // (left,top) would probably be (-32000,-32000) like all minimized - // windows. So the above MonitorFromWindow call fails, but if we check - // the window rect given with WM_NCCALCSIZE (which is our previous - // restored window position) we will get the correct monitor handle. - monitor = MonitorFromRect(client_rect, MONITOR_DEFAULTTONULL); - if (!monitor) { - // This is probably an extreme case that we won't hit, but if we don't - // intersect any monitor, let us not adjust the client rect since our - // window will not be visible anyway. - return 0; - } - } - if (GetTopmostAutoHideTaskbarForEdge(ABE_LEFT, monitor)) - client_rect->left += kAutoHideTaskbarThicknessPx; - if (GetTopmostAutoHideTaskbarForEdge(ABE_TOP, monitor)) { - if (!delegate_->IsUsingCustomFrame()) { - // Tricky bit. Due to a bug in DwmDefWindowProc()'s handling of - // WM_NCHITTEST, having any nonclient area atop the window causes the - // caption buttons to draw onscreen but not respond to mouse - // hover/clicks. - // So for a taskbar at the screen top, we can't push the - // client_rect->top down; instead, we move the bottom up by one pixel, - // which is the smallest change we can make and still get a client area - // less than the screen size. This is visibly ugly, but there seems to - // be no better solution. - --client_rect->bottom; - } else { - client_rect->top += kAutoHideTaskbarThicknessPx; - } - } - if (GetTopmostAutoHideTaskbarForEdge(ABE_RIGHT, monitor)) - client_rect->right -= kAutoHideTaskbarThicknessPx; - if (GetTopmostAutoHideTaskbarForEdge(ABE_BOTTOM, monitor)) - client_rect->bottom -= kAutoHideTaskbarThicknessPx; - - // We cannot return WVR_REDRAW when there is nonclient area, or Windows - // exhibits bugs where client pixels and child HWNDs are mispositioned by - // the width/height of the upper-left nonclient area. - return 0; - } - - // If the window bounds change, we're going to relayout and repaint anyway. - // Returning WVR_REDRAW avoids an extra paint before that of the old client - // pixels in the (now wrong) location, and thus makes actions like resizing a - // window from the left edge look slightly less broken. - // We special case when left or top insets are 0, since these conditions - // actually require another repaint to correct the layout after glass gets - // turned on and off. - if (insets.left() == 0 || insets.top() == 0) - return 0; - return mode ? WVR_REDRAW : 0; -} - LRESULT HWNDMessageHandler::OnNCHitTest(const CPoint& point) { if (!delegate_->IsWidgetWindow()) { SetMsgHandled(FALSE); @@ -804,59 +641,6 @@ void HWNDMessageHandler::OnSize(UINT param, const CSize& size) { ResetWindowRegion(false); } -void HWNDMessageHandler::OnSysCommand(UINT notification_code, - const CPoint& point) { - if (!delegate_->IsWidgetWindow()) - return; - - // Windows uses the 4 lower order bits of |notification_code| for type- - // specific information so we must exclude this when comparing. - static const int sc_mask = 0xFFF0; - // Ignore size/move/maximize in fullscreen mode. - if (fullscreen_handler_->fullscreen() && - (((notification_code & sc_mask) == SC_SIZE) || - ((notification_code & sc_mask) == SC_MOVE) || - ((notification_code & sc_mask) == SC_MAXIMIZE))) - return; - if (delegate_->IsUsingCustomFrame()) { - if ((notification_code & sc_mask) == SC_MINIMIZE || - (notification_code & sc_mask) == SC_MAXIMIZE || - (notification_code & sc_mask) == SC_RESTORE) { - delegate_->ResetWindowControls(); - } else if ((notification_code & sc_mask) == SC_MOVE || - (notification_code & sc_mask) == SC_SIZE) { - if (!IsVisible()) { - // Circumvent ScopedRedrawLocks and force visibility before entering a - // resize or move modal loop to get continuous sizing/moving feedback. - SetWindowLong(hwnd(), GWL_STYLE, - GetWindowLong(hwnd(), GWL_STYLE) | WS_VISIBLE); - } - } - } - - // Handle SC_KEYMENU, which means that the user has pressed the ALT - // key and released it, so we should focus the menu bar. - if ((notification_code & sc_mask) == SC_KEYMENU && point.x == 0) { - int modifiers = ui::EF_NONE; - if (base::win::IsShiftPressed()) - modifiers |= ui::EF_SHIFT_DOWN; - if (base::win::IsCtrlPressed()) - modifiers |= ui::EF_CONTROL_DOWN; - // Retrieve the status of shift and control keys to prevent consuming - // shift+alt keys, which are used by Windows to change input languages. - ui::Accelerator accelerator(ui::KeyboardCodeForWindowsKeyCode(VK_MENU), - modifiers); - delegate_->HandleAccelerator(accelerator); - return; - } - - // If the delegate can't handle it, the system implementation will be called. - if (!delegate_->HandleCommand(notification_code)) { - DefWindowProc(hwnd(), WM_SYSCOMMAND, notification_code, - MAKELPARAM(point.x, point.y)); - } -} - void HWNDMessageHandler::OnThemeChanged() { ui::NativeThemeWin::instance()->CloseHandles(); } @@ -886,94 +670,6 @@ void HWNDMessageHandler::OnVScroll(int scroll_type, SetMsgHandled(FALSE); } -void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) { - if (ignore_window_pos_changes_) { - // If somebody's trying to toggle our visibility, change the nonclient area, - // change our Z-order, or activate us, we should probably let it go through. - if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) | - SWP_FRAMECHANGED)) && - (window_pos->flags & (SWP_NOZORDER | SWP_NOACTIVATE))) { - // Just sizing/moving the window; ignore. - window_pos->flags |= SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW; - window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW); - } - } else if (!GetParent(hwnd())) { - CRect window_rect; - HMONITOR monitor; - gfx::Rect monitor_rect, work_area; - if (GetWindowRect(hwnd(), &window_rect) && - GetMonitorAndRects(window_rect, &monitor, &monitor_rect, &work_area)) { - bool work_area_changed = (monitor_rect == last_monitor_rect_) && - (work_area != last_work_area_); - if (monitor && (monitor == last_monitor_) && - ((fullscreen_handler_->fullscreen() && - !fullscreen_handler_->metro_snap()) || - work_area_changed)) { - // A rect for the monitor we're on changed. Normally Windows notifies - // us about this (and thus we're reaching here due to the SetWindowPos() - // call in OnSettingChange() above), but with some software (e.g. - // nVidia's nView desktop manager) the work area can change asynchronous - // to any notification, and we're just sent a SetWindowPos() call with a - // new (frequently incorrect) position/size. In either case, the best - // response is to throw away the existing position/size information in - // |window_pos| and recalculate it based on the new work rect. - gfx::Rect new_window_rect; - if (fullscreen_handler_->fullscreen()) { - new_window_rect = monitor_rect; - } else if (IsMaximized()) { - new_window_rect = work_area; - int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME); - new_window_rect.Inset(-border_thickness, -border_thickness); - } else { - new_window_rect = gfx::Rect(window_rect).AdjustToFit(work_area); - } - window_pos->x = new_window_rect.x(); - window_pos->y = new_window_rect.y(); - window_pos->cx = new_window_rect.width(); - window_pos->cy = new_window_rect.height(); - // WARNING! Don't set SWP_FRAMECHANGED here, it breaks moving the child - // HWNDs for some reason. - window_pos->flags &= ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW); - window_pos->flags |= SWP_NOCOPYBITS; - - // Now ignore all immediately-following SetWindowPos() changes. Windows - // likes to (incorrectly) recalculate what our position/size should be - // and send us further updates. - ignore_window_pos_changes_ = true; - DCHECK(!ignore_pos_changes_factory_.HasWeakPtrs()); - MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&HWNDMessageHandler::StopIgnoringPosChanges, - ignore_pos_changes_factory_.GetWeakPtr())); - } - last_monitor_ = monitor; - last_monitor_rect_ = monitor_rect; - last_work_area_ = work_area; - } - } - - if (ScopedFullscreenVisibility::IsHiddenForFullscreen(hwnd())) { - // Prevent the window from being made visible if we've been asked to do so. - // See comment in header as to why we might want this. - window_pos->flags &= ~SWP_SHOWWINDOW; - } - - // When WM_WINDOWPOSCHANGING message is handled by DefWindowProc, it will - // enforce (cx, cy) not to be smaller than (6, 6) for any non-popup window. - // We work around this by changing cy back to our intended value. - if (!GetParent(hwnd()) && !(window_pos->flags & SWP_NOSIZE) && - window_pos->cy < 6) { - LONG old_cy = window_pos->cy; - DefWindowProc(hwnd(), WM_WINDOWPOSCHANGING, 0, - reinterpret_cast<LPARAM>(window_pos)); - window_pos->cy = old_cy; - SetMsgHandled(TRUE); - return; - } - - SetMsgHandled(FALSE); -} - void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) { if (DidClientAreaSizeChange(window_pos)) ClientAreaSizeChanged(); @@ -1080,45 +776,6 @@ void HWNDMessageHandler::ClientAreaSizeChanged() { delegate_->HandleClientSizeChanged(s); } -gfx::Insets HWNDMessageHandler::GetClientAreaInsets() const { - gfx::Insets insets; - if (delegate_->GetClientAreaInsets(&insets)) - return insets; - DCHECK(insets.empty()); - - // Returning an empty Insets object causes the default handling in - // NativeWidgetWin::OnNCCalcSize() to be invoked. - if (!delegate_->IsWidgetWindow() || - (!delegate_->IsUsingCustomFrame() && !remove_standard_frame_)) { - return insets; - } - - if (IsMaximized()) { - // Windows automatically adds a standard width border to all sides when a - // window is maximized. - int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME); - return gfx::Insets(border_thickness, border_thickness, border_thickness, - border_thickness); - } - - // The hack below doesn't seem to be necessary when the standard frame is - // removed. - if (remove_standard_frame_) - return insets; - // This is weird, but highly essential. If we don't offset the bottom edge - // of the client rect, the window client area and window area will match, - // and when returning to glass rendering mode from non-glass, the client - // area will not paint black as transparent. This is because (and I don't - // know why) the client area goes from matching the window rect to being - // something else. If the client area is not the window rect in both - // modes, the blackness doesn't occur. Because of this, we need to tell - // the RootView to lay out to fit the window rect, rather than the client - // rect when using the opaque frame. - // Note: this is only required for non-fullscreen windows. Note that - // fullscreen windows are in restored state, not maximized. - return gfx::Insets(0, 0, fullscreen_handler_->fullscreen() ? 0 : 1, 0); -} - // A scoping class that prevents a window from being able to redraw in response // to invalidations that may occur within it for the lifetime of the object. // |