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

Unified Diff: ui/views/widget/widget_message_filter.cc

Issue 10662037: basic nc paint, moving, resizing for views_examples_exe on win (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: GetHwnd->hwnd Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/views/widget/widget_message_filter.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/views/widget/widget_message_filter.cc
diff --git a/ui/views/widget/widget_message_filter.cc b/ui/views/widget/widget_message_filter.cc
index f86ab2bac8002bf5ed9de5316cc9dc620d5c382d..559fc8e83dcd809f402b8e795c54d5c3b1da680b 100644
--- a/ui/views/widget/widget_message_filter.cc
+++ b/ui/views/widget/widget_message_filter.cc
@@ -1,131 +1,310 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/widget_message_filter.h"
-
-#include <windowsx.h>
-
-#include "ui/aura/root_window.h"
-#include "ui/gfx/canvas_skia_paint.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/path.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_hwnd_utils.h"
-#include "ui/views/window/non_client_view.h"
-
-namespace views {
-
-WidgetMessageFilter::WidgetMessageFilter(aura::RootWindow* root_window,
- Widget* widget)
- : root_window_(root_window),
- widget_(widget) {
- hwnd_ = root_window_->GetAcceleratedWidget();
- ClientAreaSizeChanged();
-}
-
-WidgetMessageFilter::~WidgetMessageFilter() {
-}
-
-bool WidgetMessageFilter::FilterMessage(HWND hwnd,
- UINT message,
- WPARAM w_param,
- LPARAM l_param,
- LRESULT* l_result) {
- switch (message) {
- case WM_NCCALCSIZE:
- return OnNCCalcSize(w_param, l_param, l_result);
- case WM_NCHITTEST:
- return OnNCHitTest(GET_X_LPARAM(l_param),
- GET_Y_LPARAM(l_param),
- l_result);
- case WM_NCPAINT:
- return OnNCPaint(reinterpret_cast<HRGN>(w_param));
- case WM_SIZE:
- OnSize();
- return false;
- case WM_WINDOWPOSCHANGED:
- OnWindowPosChanged(reinterpret_cast<WINDOWPOS*>(l_param));
- return false;
- }
- return false;
-}
-
-bool WidgetMessageFilter::OnNCCalcSize(WPARAM w_param,
- LPARAM l_param,
- LRESULT* l_result) {
- gfx::Insets insets = GetClientAreaInsets();
- if (insets.empty()) {
- *l_result = 0;
- return false;
- }
-
- RECT* client_rect = w_param ?
- &(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 (insets.left() == 0 || insets.top() == 0)
- *l_result = 0;
- else
- *l_result = w_param ? WVR_REDRAW : 0;
- return true;
-}
-
-bool WidgetMessageFilter::OnNCHitTest(int x, int y, LRESULT* l_result) {
- POINT temp = { x, y };
- MapWindowPoints(HWND_DESKTOP, hwnd_, &temp, 1);
- int component = widget_->GetNonClientComponent(gfx::Point(temp));
- if (component != HTNOWHERE) {
- *l_result = component;
- return true;
- }
- return false;
-}
-
-bool WidgetMessageFilter::OnNCPaint(HRGN update_region) {
- NOTIMPLEMENTED();
- return true;
-}
-
-void WidgetMessageFilter::OnSize() {
- // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
- // invoked OnSize we ensure the RootView has been laid out.
- ResetWindowRegion(false);
-}
-
-void WidgetMessageFilter::OnWindowPosChanged(WINDOWPOS* window_pos) {
- if (DidClientAreaSizeChange(window_pos))
- ClientAreaSizeChanged();
-}
-
-gfx::Insets WidgetMessageFilter::GetClientAreaInsets() const {
- // TODO(beng): native frame
- return gfx::Insets(0, 0, 1, 0);
-}
-
-bool WidgetMessageFilter::WidgetSizeIsClientSize() const {
- // TODO(beng):
- return false;
-}
-
-void WidgetMessageFilter::ClientAreaSizeChanged() {
- RECT r;
- if (WidgetSizeIsClientSize())
- GetClientRect(hwnd_, &r);
- else
- GetWindowRect(hwnd_, &r);
- gfx::Size s(std::max(0, static_cast<int>(r.right - r.left)),
- std::max(0, static_cast<int>(r.bottom - r.top)));
- widget_->OnNativeWidgetSizeChanged(s);
-}
-
-void WidgetMessageFilter::ResetWindowRegion(bool force) {
- NOTIMPLEMENTED();
-}
-
-
-} // namespace views
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/widget_message_filter.h"
+
+#include "base/event_types.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "ui/aura/event.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/gfx/canvas_skia_paint.h"
+#include "ui/gfx/gdi_util.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/path.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_hwnd_utils.h"
+#include "ui/views/window/non_client_view.h"
+
+#include <atltypes.h>
+#include <dwmapi.h>
+#include <shellapi.h>
+#include <windowsx.h>
+
+#pragma comment(lib, "dwmapi.lib")
+
+namespace views {
+
+// The thickness of an auto-hide taskbar in pixels.
+static const int kAutoHideTaskbarThicknessPx = 2;
+HWND GetTopmostAutoHideTaskbarForEdge(UINT edge, HMONITOR monitor) {
+ APPBARDATA taskbar_data = { sizeof(APPBARDATA), NULL, 0, edge };
+ HWND taskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAR,
+ &taskbar_data));
+ return (::IsWindow(taskbar) && (monitor != NULL) &&
+ (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) &&
+ (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST)) ?
+ taskbar : NULL;
+}
+
+WidgetMessageFilter::WidgetMessageFilter(aura::RootWindow* root_window,
+ Widget* widget)
+ : root_window_(root_window),
+ widget_(widget),
+ lock_updates_count_(0),
+ is_right_mouse_pressed_on_caption_(false),
+ destroyed_(NULL) {
+ hwnd_ = root_window_->GetAcceleratedWidget();
+ ClientAreaSizeChanged();
+}
+
+WidgetMessageFilter::~WidgetMessageFilter() {
+ if (destroyed_)
+ *destroyed_ = true;
+}
+
+bool WidgetMessageFilter::FilterMessage(HWND hwnd,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* l_result) {
+ switch (message) {
+ case WM_NCCALCSIZE:
+ return OnNCCalcSize(w_param, l_param, l_result);
+ case WM_NCHITTEST:
+ return OnNCHitTest(GET_X_LPARAM(l_param),
+ GET_Y_LPARAM(l_param),
+ l_result);
+ case WM_NCPAINT:
+ return OnNCPaint(reinterpret_cast<HRGN>(w_param));
+ case WM_NCACTIVATE:
+ return OnNCActivate(!!w_param, reinterpret_cast<HRGN>(l_param));
+ case WM_ERASEBKGND:
+ return true;
+ case WM_SIZE:
+ OnSize();
+ return false;
+ case WM_WINDOWPOSCHANGED:
+ OnWindowPosChanged(reinterpret_cast<WINDOWPOS*>(l_param));
+ return false;
+ }
+ return false;
+}
+
+bool WidgetMessageFilter::OnNCCalcSize(WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* l_result) {
+ gfx::Insets insets;
+ if (!GetClientAreaInsets(&insets)) {
+ *l_result = 0;
+ return false;
+ }
+
+ RECT* client_rect = w_param ?
+ &(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 (IsZoomed(hwnd_)) {
+ // 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 (widget_->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.
+ *l_result = 0;
+ return true;
+ }
+
+
+ if (insets.left() == 0 || insets.top() == 0)
+ *l_result = 0;
+ else
+ *l_result = w_param ? WVR_REDRAW : 0;
+ return true;
+}
+
+bool WidgetMessageFilter::OnNCHitTest(int x, int y, LRESULT* l_result) {
+ POINT temp = { x, y };
+ MapWindowPoints(HWND_DESKTOP, hwnd_, &temp, 1);
+ int component = widget_->GetNonClientComponent(gfx::Point(temp));
+ if (component != HTNOWHERE) {
+ *l_result = component;
+ return true;
+ }
+ return false;
+}
+
+bool WidgetMessageFilter::OnNCPaint(HRGN update_region) {
+ CRect window_rect;
+ GetWindowRect(hwnd_, &window_rect);
+
+ CRect dirty_region;
+ // A value of 1 indicates paint all.
+ if (!update_region || update_region == reinterpret_cast<HRGN>(1)) {
+ dirty_region = CRect(0, 0, window_rect.Width(), window_rect.Height());
+ } else {
+ RECT rgn_bounding_box;
+ GetRgnBox(update_region, &rgn_bounding_box);
+ if (!IntersectRect(&dirty_region, &rgn_bounding_box, &window_rect))
+ return true;
+
+ // rgn_bounding_box is in screen coordinates. Map it to window coordinates.
+ OffsetRect(&dirty_region, -window_rect.left, -window_rect.top);
+ }
+
+ HDC dc = GetWindowDC(hwnd_);
+
+ widget_->SchedulePaintInRect(gfx::Rect(dirty_region));
+
+ // gfx::CanvasSkiaPaint's destructor does the actual painting. As such, wrap
+ // the following in a block to force paint to occur so that we can release
+ // the dc.
+ {
+ gfx::CanvasSkiaPaint canvas(dc, true, dirty_region.left,
+ dirty_region.top, dirty_region.Width(),
+ dirty_region.Height());
+ }
+
+ ReleaseDC(hwnd_, dc);
+ return true;
+}
+
+bool WidgetMessageFilter::OnNCActivate(bool active, HRGN update_region) {
+ if (!widget_->non_client_view())
+ return false;
+
+ if (!widget_->ShouldUseNativeFrame()) {
+ RedrawWindow(hwnd_, NULL, NULL,
+ RDW_NOCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW);
+ }
+
+ return true;
+}
+
+void WidgetMessageFilter::OnSize() {
+ RedrawWindow(hwnd_, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
+ // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
+ // invoked OnSize we ensure the RootView has been laid out.
+ ResetWindowRegion(false);
+}
+
+void WidgetMessageFilter::OnWindowPosChanged(WINDOWPOS* window_pos) {
+ if (DidClientAreaSizeChange(window_pos))
+ ClientAreaSizeChanged();
+}
+
+HWND WidgetMessageFilter::hwnd() const {
+ return hwnd_;
+}
+
+bool WidgetMessageFilter::IsVisible() const {
+ return !!::IsWindowVisible(hwnd_);
+}
+
+bool WidgetMessageFilter::HasCapture() const {
+ return ::GetCapture() == hwnd_;
+}
+
+bool WidgetMessageFilter::GetClientAreaInsets(gfx::Insets* insets) const {
+ // TODO(beng): native frame
+ *insets = gfx::Insets(0, 0, 0, 0);
+ return true;
+}
+
+bool WidgetMessageFilter::WidgetSizeIsClientSize() const {
+ return IsZoomed(hwnd_) || widget_->ShouldUseNativeFrame();
+}
+
+void WidgetMessageFilter::ClientAreaSizeChanged() {
+ RECT r;
+ if (WidgetSizeIsClientSize())
+ GetClientRect(hwnd_, &r);
+ else
+ GetWindowRect(hwnd_, &r);
+ gfx::Size s(std::max(0, static_cast<int>(r.right - r.left)),
+ std::max(0, static_cast<int>(r.bottom - r.top)));
+ widget_->OnNativeWidgetSizeChanged(s);
+}
+
+void WidgetMessageFilter::ResetWindowRegion(bool force) {
+ // A native frame uses the native window region, and we don't want to mess
+ // with it.
+ if (widget_->ShouldUseNativeFrame() || !widget_->non_client_view()) {
+ if (force)
+ SetWindowRgn(hwnd_, NULL, TRUE);
+ return;
+ }
+
+ // Changing the window region is going to force a paint. Only change the
+ // window region if the region really differs.
+ HRGN current_rgn = CreateRectRgn(0, 0, 0, 0);
+ int current_rgn_result = GetWindowRgn(hwnd_, current_rgn);
+
+ CRect window_rect;
+ GetWindowRect(hwnd_, &window_rect);
+ HRGN new_region;
+ if (IsZoomed(hwnd_)) {
+ HMONITOR monitor =
+ MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO mi;
+ mi.cbSize = sizeof mi;
+ GetMonitorInfo(monitor, &mi);
+ CRect work_rect = mi.rcWork;
+ work_rect.OffsetRect(-window_rect.left, -window_rect.top);
+ new_region = CreateRectRgnIndirect(&work_rect);
+ } else {
+ gfx::Path window_mask;
+ widget_->non_client_view()->GetWindowMask(
+ gfx::Size(window_rect.Width(), window_rect.Height()), &window_mask);
+ new_region = ConvertPathToHRGN(window_mask);
+ }
+
+ if (current_rgn_result == ERROR || !EqualRgn(current_rgn, new_region)) {
+ // SetWindowRgn takes ownership of the HRGN created by CreateNativeRegion.
+ SetWindowRgn(hwnd_, new_region, TRUE);
+ } else {
+ DeleteObject(new_region);
+ }
+
+ DeleteObject(current_rgn);
+}
+
+} // namespace views
« no previous file with comments | « ui/views/widget/widget_message_filter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698