summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/ui/views/frame/browser_frame_win.cc7
-rw-r--r--chrome/browser/ui/views/frame/browser_frame_win.h2
-rw-r--r--ui/views/widget/native_widget_win.cc343
-rw-r--r--ui/views/widget/native_widget_win.h41
-rw-r--r--ui/views/win/DEPS1
-rw-r--r--ui/views/win/hwnd_message_handler.cc345
-rw-r--r--ui/views/win/hwnd_message_handler.h49
-rw-r--r--ui/views/win/hwnd_message_handler_delegate.h11
8 files changed, 448 insertions, 351 deletions
diff --git a/chrome/browser/ui/views/frame/browser_frame_win.cc b/chrome/browser/ui/views/frame/browser_frame_win.cc
index e6c3e58..a7034e1 100644
--- a/chrome/browser/ui/views/frame/browser_frame_win.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_win.cc
@@ -169,12 +169,12 @@ int BrowserFrameWin::GetShowState() const {
return si.wShowWindow;
}
-gfx::Insets BrowserFrameWin::GetClientAreaInsets() const {
+bool BrowserFrameWin::GetClientAreaInsets(gfx::Insets* insets) const {
// Use the default client insets for an opaque frame or a glass popup/app
// frame.
if (!GetWidget()->ShouldUseNativeFrame() ||
!browser_view_->IsBrowserTypeNormal()) {
- return NativeWidgetWin::GetClientAreaInsets();
+ return false;
}
int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
@@ -184,7 +184,8 @@ gfx::Insets BrowserFrameWin::GetClientAreaInsets() const {
border_thickness = 0;
else if (!IsMaximized())
border_thickness -= kClientEdgeThickness;
- return gfx::Insets(0, border_thickness, border_thickness, border_thickness);
+ insets->Set(0, border_thickness, border_thickness, border_thickness);
+ return true;
}
void BrowserFrameWin::UpdateFrameAfterFrameChange() {
diff --git a/chrome/browser/ui/views/frame/browser_frame_win.h b/chrome/browser/ui/views/frame/browser_frame_win.h
index 99975ac..fc8fbc0 100644
--- a/chrome/browser/ui/views/frame/browser_frame_win.h
+++ b/chrome/browser/ui/views/frame/browser_frame_win.h
@@ -45,7 +45,7 @@ class BrowserFrameWin : public views::NativeWidgetWin,
protected:
// Overridden from views::NativeWidgetWin:
virtual int GetShowState() const OVERRIDE;
- virtual gfx::Insets GetClientAreaInsets() const OVERRIDE;
+ virtual bool GetClientAreaInsets(gfx::Insets* insets) const OVERRIDE;
virtual void UpdateFrameAfterFrameChange() OVERRIDE;
virtual void OnEndSession(BOOL ending, UINT logoff) OVERRIDE;
virtual void OnInitMenuPopup(HMENU menu,
diff --git a/ui/views/widget/native_widget_win.cc b/ui/views/widget/native_widget_win.cc
index a9acca5..2f54273 100644
--- a/ui/views/widget/native_widget_win.cc
+++ b/ui/views/widget/native_widget_win.cc
@@ -51,7 +51,6 @@
#include "ui/views/widget/widget_hwnd_utils.h"
#include "ui/views/win/fullscreen_handler.h"
#include "ui/views/win/hwnd_message_handler.h"
-#include "ui/views/win/scoped_fullscreen_visibility.h"
#include "ui/views/window/native_frame_view.h"
#if !defined(USE_AURA)
@@ -275,27 +274,6 @@ static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) {
return TRUE;
}
-// The thickness of an auto-hide taskbar in pixels.
-static const int kAutoHideTaskbarThicknessPx = 2;
-
-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;
-}
-
// Links the HWND to its NativeWidget.
const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__";
@@ -336,15 +314,10 @@ NativeWidgetWin::NativeWidgetWin(internal::NativeWidgetDelegate* delegate)
accessibility_view_events_index_(-1),
accessibility_view_events_(kMaxAccessibilityViewEvents),
previous_cursor_(NULL),
- ignore_window_pos_changes_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(ignore_pos_changes_factory_(this)),
- last_monitor_(NULL),
restored_enabled_(false),
has_non_client_view_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(
- message_handler_(new HWNDMessageHandler(this))),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- fullscreen_handler_(new FullscreenHandler(GetWidget()))) {
+ message_handler_(new HWNDMessageHandler(this))) {
}
NativeWidgetWin::~NativeWidgetWin() {
@@ -420,8 +393,7 @@ void NativeWidgetWin::ClearAccessibilityViewEvent(View* view) {
void NativeWidgetWin::InitNativeWidget(const Widget::InitParams& params) {
SetInitParams(params);
- GetMonitorAndRects(params.bounds.ToRECT(), &last_monitor_,
- &last_monitor_rect_, &last_work_area_);
+ message_handler_->Init(params.bounds);
// Create the window.
WindowImpl::Init(params.GetParent(), params.bounds);
@@ -579,31 +551,7 @@ void NativeWidgetWin::CenterWindow(const gfx::Size& size) {
void NativeWidgetWin::GetWindowPlacement(
gfx::Rect* bounds,
ui::WindowShowState* show_state) const {
- WINDOWPLACEMENT wp;
- wp.length = sizeof(wp);
- const bool succeeded = !!::GetWindowPlacement(GetNativeView(), &wp);
- DCHECK(succeeded);
-
- if (bounds != NULL) {
- MONITORINFO mi;
- mi.cbSize = sizeof(mi);
- const bool succeeded = !!GetMonitorInfo(
- MonitorFromWindow(GetNativeView(), 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 != NULL) {
- 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;
- }
+ message_handler_->GetWindowPlacement(bounds, show_state);
}
void NativeWidgetWin::SetWindowTitle(const string16& title) {
@@ -701,14 +649,7 @@ gfx::Rect NativeWidgetWin::GetClientAreaBoundsInScreen() const {
}
gfx::Rect NativeWidgetWin::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 (IsFullscreen())
- return fullscreen_handler_->GetRestoreBounds();
-
- gfx::Rect bounds;
- GetWindowPlacement(&bounds, NULL);
- return bounds;
+ return message_handler_->GetRestoredBounds();
}
void NativeWidgetWin::SetBounds(const gfx::Rect& bounds) {
@@ -875,19 +816,19 @@ void NativeWidgetWin::Restore() {
}
void NativeWidgetWin::SetFullscreen(bool fullscreen) {
- fullscreen_handler_->SetFullscreen(fullscreen);
+ message_handler_->fullscreen_handler()->SetFullscreen(fullscreen);
}
void NativeWidgetWin::SetMetroSnapFullscreen(bool metro_snap) {
- fullscreen_handler_->SetMetroSnap(metro_snap);
+ message_handler_->fullscreen_handler()->SetMetroSnap(metro_snap);
}
bool NativeWidgetWin::IsFullscreen() const {
- return fullscreen_handler_->fullscreen();
+ return message_handler_->fullscreen_handler()->fullscreen();
}
bool NativeWidgetWin::IsInMetroSnapMode() const {
- return fullscreen_handler_->metro_snap();
+ return message_handler_->fullscreen_handler()->metro_snap();
}
void NativeWidgetWin::SetOpacity(unsigned char opacity) {
@@ -1217,87 +1158,7 @@ LRESULT NativeWidgetWin::OnNCActivate(BOOL active) {
}
LRESULT NativeWidgetWin::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() && !IsFullscreen() &&
- !(mode && message_handler_->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(GetNativeView(),
- 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 (GetWidget()->ShouldUseNativeFrame()) {
- // 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;
+ return message_handler_->OnNCCalcSize(mode, l_param);
}
LRESULT NativeWidgetWin::OnNCHitTest(const CPoint& point) {
@@ -1459,54 +1320,7 @@ void NativeWidgetWin::OnSize(UINT param, const CSize& size) {
}
void NativeWidgetWin::OnSysCommand(UINT notification_code, CPoint click) {
- if (!GetWidget()->non_client_view())
- 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 (IsFullscreen() &&
- (((notification_code & sc_mask) == SC_SIZE) ||
- ((notification_code & sc_mask) == SC_MOVE) ||
- ((notification_code & sc_mask) == SC_MAXIMIZE)))
- return;
- if (!GetWidget()->ShouldUseNativeFrame()) {
- if ((notification_code & sc_mask) == SC_MINIMIZE ||
- (notification_code & sc_mask) == SC_MAXIMIZE ||
- (notification_code & sc_mask) == SC_RESTORE) {
- GetWidget()->non_client_view()->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(GWL_STYLE, GetWindowLong(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 && click.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);
- GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
- return;
- }
-
- // If the delegate can't handle it, the system implementation will be called.
- if (!delegate_->ExecuteCommand(notification_code)) {
- DefWindowProc(GetNativeView(), WM_SYSCOMMAND, notification_code,
- MAKELPARAM(click.x, click.y));
- }
+ message_handler_->OnSysCommand(notification_code, click);
}
void NativeWidgetWin::OnThemeChanged() {
@@ -1526,89 +1340,7 @@ void NativeWidgetWin::OnVScroll(int scroll_type,
}
void NativeWidgetWin::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()) {
- CRect window_rect;
- HMONITOR monitor;
- gfx::Rect monitor_rect, work_area;
- if (GetWindowRect(&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_) &&
- ((IsFullscreen() && !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 (IsFullscreen()) {
- new_window_rect = monitor_rect;
- } else if (IsZoomed()) {
- 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(&NativeWidgetWin::StopIgnoringPosChanges,
- ignore_pos_changes_factory_.GetWeakPtr()));
- }
- last_monitor_ = monitor;
- last_monitor_rect_ = monitor_rect;
- last_work_area_ = work_area;
- }
- }
-
- if (ScopedFullscreenVisibility::IsHiddenForFullscreen(GetNativeView())) {
- // 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() && !(window_pos->flags & SWP_NOSIZE) && window_pos->cy < 6) {
- LONG old_cy = window_pos->cy;
- DefWindowProc(GetNativeView(), WM_WINDOWPOSCHANGING, 0,
- reinterpret_cast<LPARAM>(window_pos));
- window_pos->cy = old_cy;
- SetMsgHandled(TRUE);
- return;
- }
-
- SetMsgHandled(FALSE);
+ message_handler_->OnWindowPosChanging(window_pos);
}
void NativeWidgetWin::OnWindowPosChanged(WINDOWPOS* window_pos) {
@@ -1631,40 +1363,6 @@ int NativeWidgetWin::GetShowState() const {
return SW_SHOWNORMAL;
}
-gfx::Insets NativeWidgetWin::GetClientAreaInsets() const {
- // Returning an empty Insets object causes the default handling in
- // NativeWidgetWin::OnNCCalcSize() to be invoked.
- if (!has_non_client_view_ ||
- (GetWidget()->ShouldUseNativeFrame() &&
- !message_handler_->remove_standard_frame()))
- return gfx::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 (message_handler_->remove_standard_frame())
- return gfx::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, IsFullscreen() ? 0 : 1, 0);
-}
-
void NativeWidgetWin::OnScreenReaderDetected() {
screen_reader_active_ = true;
}
@@ -1687,7 +1385,9 @@ void NativeWidgetWin::ExecuteSystemMenuCommand(int command) {
// NativeWidgetWin, HWNDMessageHandlerDelegate implementation:
bool NativeWidgetWin::IsWidgetWindow() const {
- return !!GetWidget()->non_client_view();
+ // We don't NULL check GetWidget()->non_client_view() here because this
+ // function can be called before the widget is fully constructed.
+ return has_non_client_view_;
}
bool NativeWidgetWin::IsUsingCustomFrame() const {
@@ -1727,7 +1427,12 @@ int NativeWidgetWin::GetNonClientComponent(const gfx::Point& point) const {
}
void NativeWidgetWin::GetWindowMask(const gfx::Size& size, gfx::Path* path) {
- GetWidget()->non_client_view()->GetWindowMask(size, path);
+ if (GetWidget()->non_client_view())
+ GetWidget()->non_client_view()->GetWindowMask(size, path);
+}
+
+bool NativeWidgetWin::GetClientAreaInsets(gfx::Insets* insets) const {
+ return false;
}
void NativeWidgetWin::GetMinMaxSize(gfx::Size* min_size,
@@ -1736,6 +1441,10 @@ void NativeWidgetWin::GetMinMaxSize(gfx::Size* min_size,
*max_size = delegate_->GetMaximumSize();
}
+void NativeWidgetWin::ResetWindowControls() {
+ GetWidget()->non_client_view()->ResetWindowControls();
+}
+
InputMethod* NativeWidgetWin::GetInputMethod() {
return GetWidget()->GetInputMethodDirect();
}
@@ -1773,6 +1482,10 @@ bool NativeWidgetWin::HandleCommand(int command) {
return GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
}
+void NativeWidgetWin::HandleAccelerator(const ui::Accelerator& accelerator) {
+ GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
+}
+
void NativeWidgetWin::HandleCreate() {
// TODO(beng): much of this could/should maybe move to HWNDMessageHandler.
diff --git a/ui/views/widget/native_widget_win.h b/ui/views/widget/native_widget_win.h
index 926540a..a728a2c 100644
--- a/ui/views/widget/native_widget_win.h
+++ b/ui/views/widget/native_widget_win.h
@@ -41,7 +41,6 @@ class Rect;
namespace views {
class DropTargetWin;
-class FullscreenHandler;
class HWNDMessageHandler;
class InputMethodDelegate;
class RootView;
@@ -435,11 +434,6 @@ class VIEWS_EXPORT NativeWidgetWin : public ui::WindowImpl,
// show state from the shortcut starutp info).
virtual int GetShowState() const;
- // Returns the insets of the client area relative to the non-client area of
- // the window. Override this function instead of OnNCCalcSize, which is
- // crazily complicated.
- virtual gfx::Insets GetClientAreaInsets() const;
-
// Called when a MSAA screen reader client is detected.
virtual void OnScreenReaderDetected();
@@ -456,13 +450,6 @@ class VIEWS_EXPORT NativeWidgetWin : public ui::WindowImpl,
const gfx::Rect& invalid_rect() const { return invalid_rect_; }
- private:
- typedef ScopedVector<ui::ViewProp> ViewProps;
-
- // TODO(beng): This friendship can be removed once all methods relating to
- // this object being a WindowImpl are moved to HWNDMessageHandler.
- friend HWNDMessageHandler;
-
// Overridden from HWNDMessageHandlerDelegate:
virtual bool IsWidgetWindow() const OVERRIDE;
virtual bool IsUsingCustomFrame() const OVERRIDE;
@@ -475,8 +462,10 @@ class VIEWS_EXPORT NativeWidgetWin : public ui::WindowImpl,
virtual bool WillProcessWorkAreaChange() const OVERRIDE;
virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
virtual void GetWindowMask(const gfx::Size& size, gfx::Path* path) OVERRIDE;
+ virtual bool GetClientAreaInsets(gfx::Insets* insets) const OVERRIDE;
virtual void GetMinMaxSize(gfx::Size* min_size,
gfx::Size* max_size) const OVERRIDE;
+ virtual void ResetWindowControls() OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
virtual InputMethod* GetInputMethod() OVERRIDE;
virtual void HandleAppDeactivated() OVERRIDE;
@@ -485,6 +474,7 @@ class VIEWS_EXPORT NativeWidgetWin : public ui::WindowImpl,
virtual void HandleCaptureLost() OVERRIDE;
virtual void HandleClose() OVERRIDE;
virtual bool HandleCommand(int command) OVERRIDE;
+ virtual void HandleAccelerator(const ui::Accelerator& accelerator) OVERRIDE;
virtual void HandleCreate() OVERRIDE;
virtual void HandleDestroy() OVERRIDE;
virtual void HandleDisplayChange() OVERRIDE;
@@ -508,6 +498,13 @@ class VIEWS_EXPORT NativeWidgetWin : public ui::WindowImpl,
LPARAM l_param) OVERRIDE;
virtual NativeWidgetWin* AsNativeWidgetWin() OVERRIDE;
+ private:
+ typedef ScopedVector<ui::ViewProp> ViewProps;
+
+ // TODO(beng): This friendship can be removed once all methods relating to
+ // this object being a WindowImpl are moved to HWNDMessageHandler.
+ friend HWNDMessageHandler;
+
// Called after the WM_ACTIVATE message has been processed by the default
// windows procedure.
static void PostProcessActivateMessage(NativeWidgetWin* widget,
@@ -525,9 +522,6 @@ class VIEWS_EXPORT NativeWidgetWin : public ui::WindowImpl,
// Determines whether the delegate expects the client size or the window size.
bool WidgetSizeIsClientSize() const;
- // Stops ignoring SetWindowPos() requests (see below).
- void StopIgnoringPosChanges() { ignore_window_pos_changes_ = false; }
-
void RestoreEnabledIfNecessary();
void SetInitialFocus();
@@ -612,20 +606,6 @@ class VIEWS_EXPORT NativeWidgetWin : public ui::WindowImpl,
DWORD drag_frame_saved_window_style_;
DWORD drag_frame_saved_window_ex_style_;
- // When true, this flag makes us discard incoming SetWindowPos() requests that
- // only change our position/size. (We still allow changes to Z-order,
- // activation, etc.)
- bool ignore_window_pos_changes_;
-
- // The following factory is used to ignore SetWindowPos() calls for short time
- // periods.
- base::WeakPtrFactory<NativeWidgetWin> ignore_pos_changes_factory_;
-
- // The last-seen monitor containing us, and its rect and work area. These are
- // used to catch updates to the rect and work area and react accordingly.
- HMONITOR last_monitor_;
- gfx::Rect last_monitor_rect_, last_work_area_;
-
// Whether all ancestors have been enabled. This is only used if is_modal_ is
// true.
bool restored_enabled_;
@@ -636,7 +616,6 @@ class VIEWS_EXPORT NativeWidgetWin : public ui::WindowImpl,
bool has_non_client_view_;
scoped_ptr<HWNDMessageHandler> message_handler_;
- scoped_ptr<FullscreenHandler> fullscreen_handler_;
DISALLOW_COPY_AND_ASSIGN(NativeWidgetWin);
};
diff --git a/ui/views/win/DEPS b/ui/views/win/DEPS
index 43eb3f0..de31b8c 100644
--- a/ui/views/win/DEPS
+++ b/ui/views/win/DEPS
@@ -9,6 +9,7 @@ include_rules = [
"+ui/views/ime/input_method_delegate.h",
"+ui/views/ime/input_method_win.h",
"+ui/views/views_export.h",
+ "+ui/views/widget/monitor_win.h",
"+ui/views/widget/native_widget_win.h",
# temporary until fullscreen moves to hwnd_message_handler.
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 5c8641c..fa28e3c 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -5,19 +5,26 @@
#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"
@@ -38,10 +45,31 @@ 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
////////////////////////////////////////////////////////////////////////////////
@@ -49,11 +77,16 @@ const int kCustomObjectID = 1;
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) {
+ destroyed_(NULL),
+ ignore_window_pos_changes_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(ignore_pos_changes_factory_(this)),
+ last_monitor_(NULL) {
}
HWNDMessageHandler::~HWNDMessageHandler() {
@@ -61,6 +94,53 @@ 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());
}
@@ -519,6 +599,89 @@ 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);
@@ -641,6 +804,59 @@ 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();
}
@@ -670,6 +886,94 @@ 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();
@@ -776,6 +1080,45 @@ 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.
//
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h
index f7f8652..5bf9728 100644
--- a/ui/views/win/hwnd_message_handler.h
+++ b/ui/views/win/hwnd_message_handler.h
@@ -14,11 +14,20 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/gfx/rect.h"
#include "ui/views/ime/input_method_delegate.h"
#include "ui/views/views_export.h"
+namespace gfx {
+class Insets;
+}
+
namespace views {
+class FullscreenHandler;
class HWNDMessageHandlerDelegate;
class InputMethod;
@@ -35,6 +44,12 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
explicit HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate);
~HWNDMessageHandler();
+ void Init(const gfx::Rect& bounds);
+
+ gfx::Rect GetRestoredBounds() const;
+ void GetWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const;
+
bool IsVisible() const;
bool IsActive() const;
bool IsMinimized() const;
@@ -47,6 +62,8 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
void ReleaseCapture();
bool HasCapture() const;
+ FullscreenHandler* fullscreen_handler() { return fullscreen_handler_.get(); }
+
InputMethod* CreateInputMethod();
// Message Handlers.
@@ -84,6 +101,7 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
void OnMove(const CPoint& point);
void OnMoving(UINT param, const RECT* new_bounds);
LRESULT OnNCActivate(BOOL active);
+ LRESULT OnNCCalcSize(BOOL mode, LPARAM l_param);
LRESULT OnNCHitTest(const CPoint& point);
LRESULT OnNCUAHDrawCaption(UINT message, WPARAM w_param, LPARAM l_param);
LRESULT OnNCUAHDrawFrame(UINT message, WPARAM w_param, LPARAM l_param);
@@ -96,9 +114,11 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
LRESULT OnSetText(const wchar_t* text);
void OnSettingChange(UINT flags, const wchar_t* section);
void OnSize(UINT param, const CSize& size);
+ void OnSysCommand(UINT notification_code, const CPoint& point);
void OnThemeChanged();
LRESULT OnTouchEvent(UINT message, WPARAM w_param, LPARAM l_param);
void OnVScroll(int scroll_type, short position, HWND scrollbar);
+ void OnWindowPosChanging(WINDOWPOS* window_pos);
void OnWindowPosChanged(WINDOWPOS* window_pos);
// TODO(beng): Can be removed once this object becomes the WindowImpl.
@@ -129,6 +149,10 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
// or subsequently.
void ClientAreaSizeChanged();
+ // Returns the insets of the client area relative to the non-client area of
+ // the window.
+ gfx::Insets GetClientAreaInsets() const;
+
// Calls DefWindowProc, safely wrapping the call in a ScopedRedrawLock to
// prevent frame flicker. DefWindowProc handling can otherwise render the
// classic-look window title bar directly.
@@ -142,6 +166,9 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
void LockUpdates(bool force);
void UnlockUpdates(bool force);
+ // Stops ignoring SetWindowPos() requests (see below).
+ void StopIgnoringPosChanges() { ignore_window_pos_changes_ = false; }
+
// TODO(beng): This won't be a style violation once this object becomes the
// WindowImpl.
HWND hwnd();
@@ -152,8 +179,12 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
HWNDMessageHandlerDelegate* delegate_;
+ scoped_ptr<FullscreenHandler> fullscreen_handler_;
+
bool remove_standard_frame_;
+ // Event handling ------------------------------------------------------------
+
// The flags currently being used with TrackMouseEvent to track mouse
// messages. 0 if there is no active tracking. The value of this member is
// used when tracking is canceled.
@@ -166,6 +197,8 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
// The set of touch devices currently down.
TouchIDs touch_ids_;
+ // ScopedRedrawLock ----------------------------------------------------------
+
// Represents the number of ScopedRedrawLocks active against this widget.
// If this is greater than zero, the widget should be locked against updates.
int lock_updates_count_;
@@ -175,6 +208,22 @@ class VIEWS_EXPORT HWNDMessageHandler : public internal::InputMethodDelegate {
// Window with a ScopedRedrawLock) after destruction.
bool* destroyed_;
+ // Window resizing -----------------------------------------------------------
+
+ // When true, this flag makes us discard incoming SetWindowPos() requests that
+ // only change our position/size. (We still allow changes to Z-order,
+ // activation, etc.)
+ bool ignore_window_pos_changes_;
+
+ // The following factory is used to ignore SetWindowPos() calls for short time
+ // periods.
+ base::WeakPtrFactory<HWNDMessageHandler> ignore_pos_changes_factory_;
+
+ // The last-seen monitor containing us, and its rect and work area. These are
+ // used to catch updates to the rect and work area and react accordingly.
+ HMONITOR last_monitor_;
+ gfx::Rect last_monitor_rect_, last_work_area_;
+
DISALLOW_COPY_AND_ASSIGN(HWNDMessageHandler);
};
diff --git a/ui/views/win/hwnd_message_handler_delegate.h b/ui/views/win/hwnd_message_handler_delegate.h
index 60ec2e1..c8699d5 100644
--- a/ui/views/win/hwnd_message_handler_delegate.h
+++ b/ui/views/win/hwnd_message_handler_delegate.h
@@ -8,6 +8,7 @@
#include "ui/views/views_export.h"
namespace gfx {
+class Insets;
class Path;
class Point;
class Size;
@@ -41,11 +42,18 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
virtual int GetNonClientComponent(const gfx::Point& point) const = 0;
virtual void GetWindowMask(const gfx::Size& size, gfx::Path* mask) = 0;
+ // Returns true if the delegate modifies |insets| to define a custom client
+ // area for the window, false if the default client area should be used. If
+ // false is returned, |insets| is not modified.
+ virtual bool GetClientAreaInsets(gfx::Insets* insets) const = 0;
+
// Returns the minimum and maximum size the window can be resized to by the
// user.
virtual void GetMinMaxSize(gfx::Size* min_size,
gfx::Size* max_size) const = 0;
+ virtual void ResetWindowControls() = 0;
+
virtual InputMethod* GetInputMethod() = 0;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
@@ -74,6 +82,9 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// true if the command was handled.
virtual bool HandleCommand(int command) = 0;
+ // Called when an accelerator is invoked.
+ virtual void HandleAccelerator(const ui::Accelerator& accelerator) = 0;
+
// Called when the HWND is created.
virtual void HandleCreate() = 0;