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

Unified Diff: chrome/views/custom_frame_window.cc

Issue 27317: Support DWM switching.... (Closed) Base URL: svn://chrome-svn.corp.google.com/chrome/trunk/src/
Patch Set: '' Created 11 years, 10 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 | « chrome/views/custom_frame_window.h ('k') | chrome/views/default_non_client_view.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/views/custom_frame_window.cc
===================================================================
--- chrome/views/custom_frame_window.cc (revision 10688)
+++ chrome/views/custom_frame_window.cc (working copy)
@@ -1,506 +0,0 @@
-// Copyright (c) 2006-2008 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 "chrome/views/custom_frame_window.h"
-
-#include "base/gfx/point.h"
-#include "base/gfx/size.h"
-#include "chrome/common/gfx/chrome_canvas.h"
-#include "chrome/common/gfx/path.h"
-#include "chrome/common/l10n_util.h"
-#include "chrome/common/win_util.h"
-#include "chrome/views/client_view.h"
-#include "chrome/views/default_non_client_view.h"
-#include "chrome/views/root_view.h"
-#include "chrome/views/window_delegate.h"
-#include "grit/generated_resources.h"
-
-namespace views {
-
-// 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.
-//
-// Why would we want such a thing? Well, it turns out Windows has some
-// "unorthodox" behavior when it comes to painting its non-client areas.
-// Occasionally, Windows will paint portions of the default non-client area
-// right over the top of the custom frame. This is not simply fixed by handling
-// WM_NCPAINT/WM_PAINT, with some investigation it turns out that this
-// rendering is being done *inside* the default implementation of some message
-// handlers and functions:
-// . WM_SETTEXT
-// . WM_SETICON
-// . WM_NCLBUTTONDOWN
-// . EnableMenuItem, called from our WM_INITMENU handler
-// The solution is to handle these messages and call DefWindowProc ourselves,
-// but prevent the window from being able to update itself for the duration of
-// the call. We do this with this class, which automatically calls its
-// associated CustomFrameWindow's lock and unlock functions as it is created
-// and destroyed. See documentation in those methods for the technique used.
-//
-// IMPORTANT: Do not use this scoping object for large scopes or periods of
-// time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh).
-//
-// I would love to hear Raymond Chen's explanation for all this. And maybe a
-// list of other messages that this applies to ;-)
-class CustomFrameWindow::ScopedRedrawLock {
- public:
- explicit ScopedRedrawLock(CustomFrameWindow* window) : window_(window) {
- window_->LockUpdates();
- }
-
- ~ScopedRedrawLock() {
- window_->UnlockUpdates();
- }
-
- private:
- // The window having its style changed.
- CustomFrameWindow* window_;
-};
-
-HCURSOR CustomFrameWindow::resize_cursors_[6];
-
-///////////////////////////////////////////////////////////////////////////////
-// CustomFrameWindow, public:
-
-CustomFrameWindow::CustomFrameWindow(WindowDelegate* window_delegate)
- : Window(window_delegate),
- is_active_(false),
- lock_updates_(false),
- saved_window_style_(0) {
- InitClass();
- non_client_view_ = new DefaultNonClientView(this);
-}
-
-CustomFrameWindow::CustomFrameWindow(WindowDelegate* window_delegate,
- NonClientView* non_client_view)
- : Window(window_delegate) {
- InitClass();
- non_client_view_ = non_client_view;
-}
-
-CustomFrameWindow::~CustomFrameWindow() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CustomFrameWindow, Window overrides:
-
-void CustomFrameWindow::Init(HWND parent, const gfx::Rect& bounds) {
- // TODO(beng): (Cleanup) Right now, the only way to specify a different
- // non-client view is to subclass this object and provide one
- // by setting this member before calling Init.
- if (!non_client_view_)
- non_client_view_ = new DefaultNonClientView(this);
- Window::Init(parent, bounds);
-
- ResetWindowRegion();
-}
-
-void CustomFrameWindow::UpdateWindowTitle() {
- // Layout winds up causing the title to be re-validated during
- // string measurement.
- non_client_view_->Layout();
- // Must call the base class too so that places like the Task Bar get updated.
- Window::UpdateWindowTitle();
-}
-
-void CustomFrameWindow::UpdateWindowIcon() {
- // The icon will be re-validated during painting.
- non_client_view_->SchedulePaint();
- // Call the base class so that places like the Task Bar get updated.
- Window::UpdateWindowIcon();
-}
-
-void CustomFrameWindow::EnableClose(bool enable) {
- non_client_view_->EnableClose(enable);
- // Make sure the SysMenu changes to reflect this change as well.
- Window::EnableClose(enable);
-}
-
-void CustomFrameWindow::DisableInactiveRendering(bool disable) {
- Window::DisableInactiveRendering(disable);
- non_client_view_->set_paint_as_active(disable);
- if (!disable)
- non_client_view_->SchedulePaint();
-}
-
-void CustomFrameWindow::SizeWindowToDefault() {
- gfx::Size pref = client_view()->GetPreferredSize();
- DCHECK(pref.width() > 0 && pref.height() > 0);
- gfx::Size window_size =
- non_client_view_->CalculateWindowSizeForClientSize(pref.width(),
- pref.height());
- win_util::CenterAndSizeWindow(owning_window(), GetHWND(),
- window_size.ToSIZE(), false);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CustomFrameWindow, WidgetWin overrides:
-
-static void EnableMenuItem(HMENU menu, UINT command, bool enabled) {
- UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
- EnableMenuItem(menu, command, flags);
-}
-
-void CustomFrameWindow::OnInitMenu(HMENU menu) {
- bool is_minimized = IsMinimized();
- bool is_maximized = IsMaximized();
- bool is_restored = !is_minimized && !is_maximized;
-
- ScopedRedrawLock lock(this);
- EnableMenuItem(menu, SC_RESTORE, !is_restored);
- EnableMenuItem(menu, SC_MOVE, is_restored);
- EnableMenuItem(menu, SC_SIZE, window_delegate()->CanResize() && is_restored);
- EnableMenuItem(menu, SC_MAXIMIZE,
- window_delegate()->CanMaximize() && !is_maximized);
- EnableMenuItem(menu, SC_MINIMIZE,
- window_delegate()->CanMaximize() && !is_minimized);
-}
-
-void CustomFrameWindow::OnMouseLeave() {
- bool process_mouse_exited = true;
- POINT pt;
- if (GetCursorPos(&pt)) {
- LRESULT ht_component =
- ::SendMessage(GetHWND(), WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));
- if (ht_component != HTNOWHERE) {
- // If the mouse moved into a part of the window's non-client area, then
- // don't send a mouse exited event since the mouse is still within the
- // bounds of the ChromeView that's rendering the frame. Note that we do
- // _NOT_ do this for windows with native frames, since in that case the
- // mouse really will have left the bounds of the RootView.
- process_mouse_exited = false;
- }
- }
-
- if (process_mouse_exited)
- ProcessMouseExited();
-}
-
-LRESULT CustomFrameWindow::OnNCActivate(BOOL active) {
- is_active_ = !!active;
-
- // We can get WM_NCACTIVATE before we're actually visible. If we're not
- // visible, no need to paint.
- if (IsWindowVisible(GetHWND())) {
- non_client_view_->SchedulePaint();
- // We need to force a paint now, as a user dragging a window will block
- // painting operations while the move is in progress.
- PaintNow(root_view_->GetScheduledPaintRect());
- }
-
- // Defering to our parent as it is important that the NCActivate message gets
- // DefProc'ed or the task bar won't show our process as active.
- // See bug http://crbug.com/4513.
- return Window::OnNCActivate(active);
-}
-
-LRESULT CustomFrameWindow::OnNCCalcSize(BOOL mode, LPARAM l_param) {
- // We need to repaint all when the window bounds change.
- return WVR_REDRAW;
-}
-
-LRESULT CustomFrameWindow::OnNCHitTest(const CPoint& point) {
- // NC points are in screen coordinates.
- CPoint temp = point;
- MapWindowPoints(HWND_DESKTOP, GetHWND(), &temp, 1);
- return non_client_view_->NonClientHitTest(gfx::Point(temp.x, temp.y));
-}
-
-struct ClipState {
- // The window being painted.
- HWND parent;
-
- // DC painting to.
- HDC dc;
-
- // Origin of the window in terms of the screen.
- int x;
- int y;
-};
-
-// See comments in OnNCPaint for details of this function.
-static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) {
- ClipState* clip_state = reinterpret_cast<ClipState*>(param);
- if (GetParent(window) == clip_state->parent && IsWindowVisible(window)) {
- RECT bounds;
- GetWindowRect(window, &bounds);
- ExcludeClipRect(clip_state->dc,
- bounds.left - clip_state->x,
- bounds.top - clip_state->y,
- bounds.right - clip_state->x,
- bounds.bottom - clip_state->y);
- }
- return TRUE;
-}
-
-void CustomFrameWindow::OnNCPaint(HRGN rgn) {
- // We have an NC region and need to paint it. We expand the NC region to
- // include the dirty region of the root view. This is done to minimize
- // paints.
- CRect window_rect;
- GetWindowRect(&window_rect);
-
- if (window_rect.Width() != root_view_->width() ||
- window_rect.Height() != root_view_->height()) {
- // If the size of the window differs from the size of the root view it
- // means we're being asked to paint before we've gotten a WM_SIZE. This can
- // happen when the user is interactively resizing the window. To avoid
- // mass flickering we don't do anything here. Once we get the WM_SIZE we'll
- // reset the region of the window which triggers another WM_NCPAINT and
- // all is well.
- return;
- }
-
- CRect dirty_region;
- // A value of 1 indicates paint all.
- if (!rgn || rgn == reinterpret_cast<HRGN>(1)) {
- dirty_region = CRect(0, 0, window_rect.Width(), window_rect.Height());
- } else {
- RECT rgn_bounding_box;
- GetRgnBox(rgn, &rgn_bounding_box);
- if (!IntersectRect(&dirty_region, &rgn_bounding_box, &window_rect))
- return; // Dirty region doesn't intersect window bounds, bale.
-
- // rgn_bounding_box is in screen coordinates. Map it to window coordinates.
- OffsetRect(&dirty_region, -window_rect.left, -window_rect.top);
- }
-
- // In theory GetDCEx should do what we want, but I couldn't get it to work.
- // In particular the docs mentiond DCX_CLIPCHILDREN, but as far as I can tell
- // it doesn't work at all. So, instead we get the DC for the window then
- // manually clip out the children.
- HDC dc = GetWindowDC(GetHWND());
- ClipState clip_state;
- clip_state.x = window_rect.left;
- clip_state.y = window_rect.top;
- clip_state.parent = GetHWND();
- clip_state.dc = dc;
- EnumChildWindows(GetHWND(), &ClipDCToChild,
- reinterpret_cast<LPARAM>(&clip_state));
-
- RootView* root_view = GetRootView();
- CRect old_paint_region = root_view->GetScheduledPaintRectConstrainedToSize();
-
- if (!old_paint_region.IsRectEmpty()) {
- // The root view has a region that needs to be painted. Include it in the
- // region we're going to paint.
-
- CRect tmp = dirty_region;
- UnionRect(&dirty_region, &tmp, &old_paint_region);
- }
-
- root_view->SchedulePaint(gfx::Rect(dirty_region), false);
-
- // ChromeCanvasPaints 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.
- {
- ChromeCanvasPaint canvas(dc, opaque(), dirty_region.left, dirty_region.top,
- dirty_region.Width(), dirty_region.Height());
-
- root_view->ProcessPaint(&canvas);
- }
-
- ReleaseDC(GetHWND(), dc);
-}
-
-void CustomFrameWindow::OnNCLButtonDown(UINT ht_component,
- const CPoint& point) {
- switch (ht_component) {
- case HTCLOSE:
- case HTMINBUTTON:
- case HTMAXBUTTON: {
- // When the mouse is pressed down in these specific non-client areas, we
- // need to tell the RootView to send the mouse pressed event (which sets
- // capture, allowing subsequent WM_LBUTTONUP (note, _not_ WM_NCLBUTTONUP)
- // to fire so that the appropriate WM_SYSCOMMAND can be sent by the
- // applicable button's ButtonListener. We _have_ to do this this way
- // rather than letting Windows just send the syscommand itself (as would
- // happen if we never did this dance) because for some insane reason
- // DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed window
- // control button appearance, in the Windows classic style, over our
- // view! Ick! By handling this message we prevent Windows from doing this
- // undesirable thing, but that means we need to roll the sys-command
- // handling ourselves.
- ProcessNCMousePress(point, MK_LBUTTON);
- return;
- }
- default:
- Window::OnNCLButtonDown(ht_component, point);
- /*
- if (!IsMsgHandled()) {
- // Window::OnNCLButtonDown set the message as unhandled. This normally
- // means WidgetWin::ProcessWindowMessage will pass it to
- // DefWindowProc. Sadly, DefWindowProc for WM_NCLBUTTONDOWN does weird
- // non-client painting, so we need to call it directly here inside a
- // scoped update lock.
- ScopedRedrawLock lock(this);
- DefWindowProc(GetHWND(), WM_NCLBUTTONDOWN, ht_component,
- MAKELPARAM(point.x, point.y));
- SetMsgHandled(TRUE);
- }
- */
- break;
- }
-}
-
-LRESULT CustomFrameWindow::OnNCUAHDrawCaption(UINT msg, WPARAM w_param,
- LPARAM l_param) {
- // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for
- // an explanation about why we need to handle this message.
- SetMsgHandled(TRUE);
- return 0;
-}
-
-LRESULT CustomFrameWindow::OnNCUAHDrawFrame(UINT msg, WPARAM w_param,
- LPARAM l_param) {
- // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for
- // an explanation about why we need to handle this message.
- SetMsgHandled(TRUE);
- return 0;
-}
-
-LRESULT CustomFrameWindow::OnSetCursor(HWND window, UINT hittest_code,
- UINT message) {
- int index = RC_NORMAL;
- switch (hittest_code) {
- case HTTOP:
- case HTBOTTOM:
- index = RC_VERTICAL;
- break;
- case HTTOPLEFT:
- case HTBOTTOMRIGHT:
- index = RC_NWSE;
- break;
- case HTTOPRIGHT:
- case HTBOTTOMLEFT:
- index = RC_NESW;
- break;
- case HTLEFT:
- case HTRIGHT:
- index = RC_HORIZONTAL;
- break;
- case HTCAPTION:
- case HTCLIENT:
- index = RC_NORMAL;
- break;
- }
- SetCursor(resize_cursors_[index]);
- return 0;
-}
-
-LRESULT CustomFrameWindow::OnSetIcon(UINT size_type, HICON new_icon) {
- ScopedRedrawLock lock(this);
- return DefWindowProc(GetHWND(), WM_SETICON, size_type,
- reinterpret_cast<LPARAM>(new_icon));
-}
-
-LRESULT CustomFrameWindow::OnSetText(const wchar_t* text) {
- ScopedRedrawLock lock(this);
- return DefWindowProc(GetHWND(), WM_SETTEXT, NULL,
- reinterpret_cast<LPARAM>(text));
-}
-
-void CustomFrameWindow::OnSize(UINT param, const CSize& size) {
- Window::OnSize(param, size);
-
- // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
- // invoked OnSize we ensure the RootView has been layed out.
- ResetWindowRegion();
-}
-
-void CustomFrameWindow::OnSysCommand(UINT notification_code, CPoint click) {
- // 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;
- if ((notification_code & sc_mask) == SC_MINIMIZE ||
- (notification_code & sc_mask) == SC_MAXIMIZE ||
- (notification_code & sc_mask) == SC_RESTORE) {
- non_client_view_->ResetWindowControls();
- } else if ((notification_code & sc_mask) == SC_MOVE ||
- (notification_code & sc_mask) == SC_SIZE) {
- if (lock_updates_) {
- // We were locked, before entering a resize or move modal loop. Now that
- // we've begun to move the window, we need to unlock updates so that the
- // sizing/moving feedback can be continuous.
- UnlockUpdates();
- }
- }
- Window::OnSysCommand(notification_code, click);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CustomFrameWindow, private:
-
-// static
-void CustomFrameWindow::InitClass() {
- static bool initialized = false;
- if (!initialized) {
- resize_cursors_[RC_NORMAL] = LoadCursor(NULL, IDC_ARROW);
- resize_cursors_[RC_VERTICAL] = LoadCursor(NULL, IDC_SIZENS);
- resize_cursors_[RC_HORIZONTAL] = LoadCursor(NULL, IDC_SIZEWE);
- resize_cursors_[RC_NESW] = LoadCursor(NULL, IDC_SIZENESW);
- resize_cursors_[RC_NWSE] = LoadCursor(NULL, IDC_SIZENWSE);
- initialized = true;
- }
-}
-
-void CustomFrameWindow::LockUpdates() {
- lock_updates_ = true;
- saved_window_style_ = GetWindowLong(GetHWND(), GWL_STYLE);
- SetWindowLong(GetHWND(), GWL_STYLE, saved_window_style_ & ~WS_VISIBLE);
-}
-
-void CustomFrameWindow::UnlockUpdates() {
- SetWindowLong(GetHWND(), GWL_STYLE, saved_window_style_);
- lock_updates_ = false;
-}
-
-void CustomFrameWindow::ResetWindowRegion() {
- // 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(GetHWND(), current_rgn);
-
- CRect window_rect;
- GetWindowRect(&window_rect);
- HRGN new_region;
- if (IsMaximized()) {
- HMONITOR monitor = MonitorFromWindow(GetHWND(), 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;
- non_client_view_->GetWindowMask(gfx::Size(window_rect.Width(),
- window_rect.Height()),
- &window_mask);
- new_region = window_mask.CreateHRGN();
- }
-
- if (current_rgn_result == ERROR || !EqualRgn(current_rgn, new_region)) {
- // SetWindowRgn takes ownership of the HRGN created by CreateHRGN.
- SetWindowRgn(new_region, TRUE);
- } else {
- DeleteObject(new_region);
- }
-
- DeleteObject(current_rgn);
-}
-
-void CustomFrameWindow::ProcessNCMousePress(const CPoint& point, int flags) {
- CPoint temp = point;
- MapWindowPoints(HWND_DESKTOP, GetHWND(), &temp, 1);
- UINT message_flags = 0;
- if ((GetKeyState(VK_CONTROL) & 0x80) == 0x80)
- message_flags |= MK_CONTROL;
- if ((GetKeyState(VK_SHIFT) & 0x80) == 0x80)
- message_flags |= MK_SHIFT;
- message_flags |= flags;
- ProcessMousePressed(temp, message_flags, false, false);
-}
-
-} // namespace views
« no previous file with comments | « chrome/views/custom_frame_window.h ('k') | chrome/views/default_non_client_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698