diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-21 20:51:20 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-21 20:51:20 +0000 |
commit | a0dde12f2e4f92f1a59885c45cfecd10dbfdfdfd (patch) | |
tree | d8283a980977f11c43542016d57f698d3a83b73d /chrome/views/widget_win.cc | |
parent | 933cc00eb856db684b9e64b7486ca20edbb2c3ea (diff) | |
download | chromium_src-a0dde12f2e4f92f1a59885c45cfecd10dbfdfdfd.zip chromium_src-a0dde12f2e4f92f1a59885c45cfecd10dbfdfdfd.tar.gz chromium_src-a0dde12f2e4f92f1a59885c45cfecd10dbfdfdfd.tar.bz2 |
Rename Container->Widget
R=erg
review url = http://codereview.chromium.org/11348/show
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5849 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/views/widget_win.cc')
-rw-r--r-- | chrome/views/widget_win.cc | 923 |
1 files changed, 923 insertions, 0 deletions
diff --git a/chrome/views/widget_win.cc b/chrome/views/widget_win.cc new file mode 100644 index 0000000..cd0e913 --- /dev/null +++ b/chrome/views/widget_win.cc @@ -0,0 +1,923 @@ +// 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/widget_win.h" + +#include "base/gfx/native_theme.h" +#include "base/string_util.h" +#include "base/win_util.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/win_util.h" +#include "chrome/views/aero_tooltip_manager.h" +#include "chrome/views/accessibility/view_accessibility.h" +#include "chrome/views/hwnd_notification_source.h" +#include "chrome/views/root_view.h" + +namespace views { + +static const DWORD kWindowDefaultChildStyle = + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; +static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW; +static const DWORD kWindowDefaultExStyle = 0; + +// Property used to link the HWND to its RootView. +static const wchar_t* const kRootViewWindowProperty = L"__ROOT_VIEW__"; + +bool SetRootViewForHWND(HWND hwnd, RootView* root_view) { + return ::SetProp(hwnd, kRootViewWindowProperty, root_view) ? true : false; +} + +RootView* GetRootViewForHWND(HWND hwnd) { + return reinterpret_cast<RootView*>(::GetProp(hwnd, kRootViewWindowProperty)); +} + +// Used to locate the WidgetWin issuing the current Create. Only valid for the +// life of Create. +// +// This obviously assumes we only create WidgetWins from the same thread, +// which is currently the case. +static WidgetWin* instance_issuing_create = NULL; + +/////////////////////////////////////////////////////////////////////////////// +// FillLayout + +FillLayout::FillLayout() { +} + +FillLayout::~FillLayout() { +} + +void FillLayout::Layout(View* host) { + if (host->GetChildViewCount() == 0) + return; + + View* frame_view = host->GetChildViewAt(0); + frame_view->SetBounds(0, 0, host->width(), host->height()); +} + +gfx::Size FillLayout::GetPreferredSize(View* host) { + DCHECK(host->GetChildViewCount() == 1); + return host->GetChildViewAt(0)->GetPreferredSize(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Window class tracking. + +// static +const wchar_t* const WidgetWin::kBaseClassName = + L"Chrome_WidgetWin_"; + +// Window class information used for registering unique windows. +struct ClassInfo { + UINT style; + HBRUSH background; + + explicit ClassInfo(int style) + : style(style), + background(NULL) {} + + // Compares two ClassInfos. Returns true if all members match. + bool Equals(const ClassInfo& other) { + return (other.style == style && other.background == background); + } +}; + +// Represents a registered window class. +struct RegisteredClass { + RegisteredClass(const ClassInfo& info, + const std::wstring& name, + ATOM atom) + : info(info), + name(name), + atom(atom) { + } + + // Info used to create the class. + ClassInfo info; + + // The name given to the window. + std::wstring name; + + // The ATOM returned from creating the window. + ATOM atom; +}; + +typedef std::list<RegisteredClass> RegisteredClasses; + +// The list of registered classes. +static RegisteredClasses* registered_classes = NULL; + + +/////////////////////////////////////////////////////////////////////////////// +// WidgetWin, public + +WidgetWin::WidgetWin() + : active_mouse_tracking_flags_(0), + has_capture_(false), + current_action_(FA_NONE), + toplevel_(false), + window_style_(0), + window_ex_style_(kWindowDefaultExStyle), + layered_(false), + layered_alpha_(255), + delete_on_destroy_(true), + can_update_layered_window_(true), + last_mouse_event_was_move_(false), + is_mouse_down_(false), + class_style_(CS_DBLCLKS), + hwnd_(NULL), + close_widget_factory_(this) { +} + +WidgetWin::~WidgetWin() { + MessageLoopForUI::current()->RemoveObserver(this); +} + +void WidgetWin::Init(HWND parent, const gfx::Rect& bounds, + bool has_own_focus_manager) { + toplevel_ = parent == NULL; + + if (window_style_ == 0) + window_style_ = toplevel_ ? kWindowDefaultStyle : kWindowDefaultChildStyle; + + // See if the style has been overridden. + opaque_ = !(window_ex_style_ & WS_EX_TRANSPARENT); + layered_ = !!(window_ex_style_ & WS_EX_LAYERED); + + // Force creation of the RootView if it hasn't been created yet. + GetRootView(); + + // Ensures the parent we have been passed is valid, otherwise CreateWindowEx + // will fail. + if (parent && !::IsWindow(parent)) { + NOTREACHED() << "invalid parent window specified."; + parent = NULL; + } + + hwnd_ = CreateWindowEx(window_ex_style_, GetWindowClassName().c_str(), L"", + window_style_, bounds.x(), bounds.y(), bounds.width(), + bounds.height(), parent, NULL, NULL, this); + DCHECK(hwnd_); + // The window procedure should have set the data for us. + DCHECK(win_util::GetWindowUserData(hwnd_) == this); + + root_view_->OnWidgetCreated(); + + if (has_own_focus_manager) { + FocusManager::CreateFocusManager(hwnd_, GetRootView()); + } else { + // Subclass the window so we get the tab key messages when a view with no + // associated native window is focused. + FocusManager::InstallFocusSubclass(hwnd_, NULL); + } + + // Sets the RootView as a property, so the automation can introspect windows. + SetRootViewForHWND(hwnd_, root_view_.get()); + + MessageLoopForUI::current()->AddObserver(this); + + // Windows special DWM window frame requires a special tooltip manager so + // that window controls in Chrome windows don't flicker when you move your + // mouse over them. See comment in aero_tooltip_manager.h. + if (win_util::ShouldUseVistaFrame()) { + tooltip_manager_.reset(new AeroTooltipManager(this, GetHWND())); + } else { + tooltip_manager_.reset(new TooltipManager(this, GetHWND())); + } + + // This message initializes the window so that focus border are shown for + // windows. + ::SendMessage(GetHWND(), + WM_CHANGEUISTATE, + MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS), + 0); + + // Bug 964884: detach the IME attached to this window. + // We should attach IMEs only when we need to input CJK strings. + ::ImmAssociateContextEx(GetHWND(), NULL, 0); +} + +void WidgetWin::SetContentsView(View* view) { + DCHECK(view && hwnd_) << "Can't be called until after the HWND is created!"; + // The ContentsView must be set up _after_ the window is created so that its + // Widget pointer is valid. + root_view_->SetLayoutManager(new FillLayout); + if (root_view_->GetChildViewCount() != 0) + root_view_->RemoveAllChildViews(true); + root_view_->AddChildView(view); + + // Manually size the window here to ensure the root view is laid out. + RECT wr; + GetWindowRect(&wr); + ChangeSize(0, CSize(wr.right - wr.left, wr.bottom - wr.top)); +} + +/////////////////////////////////////////////////////////////////////////////// +// Widget implementation: + +void WidgetWin::GetBounds(CRect *out, bool including_frame) const { + if (including_frame) { + GetWindowRect(out); + } else { + GetClientRect(out); + + POINT p = {0, 0}; + ::ClientToScreen(hwnd_, &p); + + out->left += p.x; + out->top += p.y; + out->right += p.x; + out->bottom += p.y; + } +} + +void WidgetWin::MoveToFront(bool should_activate) { + int flags = SWP_NOMOVE | SWP_NOSIZE; + if (!should_activate) { + flags |= SWP_NOACTIVATE; + } + SetWindowPos(HWND_NOTOPMOST, 0, 0, 0, 0, flags); +} + +HWND WidgetWin::GetHWND() const { + return hwnd_; +} + +void WidgetWin::PaintNow(const gfx::Rect& update_rect) { + if (layered_) { + PaintLayeredWindow(); + } else if (root_view_->NeedsPainting(false) && IsWindow()) { + if (!opaque_ && GetParent()) { + // We're transparent. Need to force painting to occur from our parent. + CRect parent_update_rect = update_rect.ToRECT(); + POINT location_in_parent = { 0, 0 }; + ClientToScreen(hwnd_, &location_in_parent); + ::ScreenToClient(GetParent(), &location_in_parent); + parent_update_rect.OffsetRect(location_in_parent); + ::RedrawWindow(GetParent(), parent_update_rect, NULL, + RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN); + } else { + RECT native_update_rect = update_rect.ToRECT(); + RedrawWindow(hwnd_, &native_update_rect, NULL, + RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN); + } + // As we were created with a style of WS_CLIPCHILDREN redraw requests may + // result in an empty paint rect in WM_PAINT (this'll happen if a + // child HWND completely contains the update _rect). In such a scenario + // RootView would never get a ProcessPaint and always think it needs to + // be painted (leading to a steady stream of RedrawWindow requests on every + // event). For this reason we tell RootView it doesn't need to paint + // here. + root_view_->ClearPaintRect(); + } +} + +RootView* WidgetWin::GetRootView() { + if (!root_view_.get()) { + // First time the root view is being asked for, create it now. + root_view_.reset(CreateRootView()); + } + return root_view_.get(); +} + +bool WidgetWin::IsVisible() { + return !!::IsWindowVisible(GetHWND()); +} + +bool WidgetWin::IsActive() { + return win_util::IsWindowActive(GetHWND()); +} + +TooltipManager* WidgetWin::GetTooltipManager() { + return tooltip_manager_.get(); +} + + +void WidgetWin::SetLayeredAlpha(BYTE layered_alpha) { + layered_alpha_ = layered_alpha; + +// if (hwnd_) +// UpdateWindowFromContents(contents_->getTopPlatformDevice().getBitmapDC()); +} + +static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM l_param) { + RootView* root_view = + reinterpret_cast<RootView*>(GetProp(hwnd, kRootViewWindowProperty)); + if (root_view) { + *reinterpret_cast<RootView**>(l_param) = root_view; + return FALSE; // Stop enumerating. + } + return TRUE; // Keep enumerating. +} + +// static +RootView* WidgetWin::FindRootView(HWND hwnd) { + RootView* root_view = + reinterpret_cast<RootView*>(GetProp(hwnd, kRootViewWindowProperty)); + if (root_view) + return root_view; + + // Enumerate all children and check if they have a RootView. + EnumChildWindows(hwnd, EnumChildProc, reinterpret_cast<LPARAM>(&root_view)); + + return root_view; +} + +void WidgetWin::Close() { + // Let's hide ourselves right away. + Hide(); + if (close_widget_factory_.empty()) { + // And we delay the close so that if we are called from an ATL callback, + // we don't destroy the window before the callback returned (as the caller + // may delete ourselves on destroy and the ATL callback would still + // dereference us when the callback returns). + MessageLoop::current()->PostTask(FROM_HERE, + close_widget_factory_.NewRunnableMethod( + &WidgetWin::CloseNow)); + } +} + +void WidgetWin::Hide() { + // NOTE: Be careful not to activate any windows here (for example, calling + // ShowWindow(SW_HIDE) will automatically activate another window). This + // code can be called while a window is being deactivated, and activating + // another window will screw up the activation that is already in progress. + SetWindowPos(NULL, 0, 0, 0, 0, + SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | + SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER); +} + +void WidgetWin::CloseNow() { + // We may already have been destroyed if the selection resulted in a tab + // switch which will have reactivated the browser window and closed us, so + // we need to check to see if we're still a window before trying to destroy + // ourself. + if (IsWindow()) + DestroyWindow(); +} + +/////////////////////////////////////////////////////////////////////////////// +// MessageLoop::Observer + +void WidgetWin::WillProcessMessage(const MSG& msg) { +} + +void WidgetWin::DidProcessMessage(const MSG& msg) { + if (root_view_->NeedsPainting(true)) { + PaintNow(root_view_->GetScheduledPaintRect()); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// FocusTraversable + +View* WidgetWin::FindNextFocusableView( + View* starting_view, bool reverse, Direction direction, bool dont_loop, + FocusTraversable** focus_traversable, View** focus_traversable_view) { + return root_view_->FindNextFocusableView(starting_view, + reverse, + direction, + dont_loop, + focus_traversable, + focus_traversable_view); +} + +FocusTraversable* WidgetWin::GetFocusTraversableParent() { + // We are a proxy to the root view, so we should be bypassed when traversing + // up and as a result this should not be called. + NOTREACHED(); + return NULL; +} + +void WidgetWin::SetFocusTraversableParent(FocusTraversable* parent) { + root_view_->SetFocusTraversableParent(parent); +} + +View* WidgetWin::GetFocusTraversableParentView() { + // We are a proxy to the root view, so we should be bypassed when traversing + // up and as a result this should not be called. + NOTREACHED(); + return NULL; +} + +void WidgetWin::SetFocusTraversableParentView(View* parent_view) { + root_view_->SetFocusTraversableParentView(parent_view); +} + +/////////////////////////////////////////////////////////////////////////////// +// Message handlers + +void WidgetWin::OnCaptureChanged(HWND hwnd) { + if (has_capture_) { + if (is_mouse_down_) + root_view_->ProcessMouseDragCanceled(); + is_mouse_down_ = false; + has_capture_ = false; + } +} + +void WidgetWin::OnClose() { + // WARNING: this method is NOT called for all WidgetWins. If you need to do + // cleanup code before WidgetWin is destroyed, put it in OnDestroy. + NotificationService::current()->Notify( + NOTIFY_WINDOW_CLOSED, Source<HWND>(hwnd_), + NotificationService::NoDetails()); + + Close(); +} + +void WidgetWin::OnDestroy() { + root_view_->OnWidgetDestroyed(); + + RemoveProp(hwnd_, kRootViewWindowProperty); +} + +LRESULT WidgetWin::OnEraseBkgnd(HDC dc) { + // This is needed for magical win32 flicker ju-ju + return 1; +} + +LRESULT WidgetWin::OnGetObject(UINT uMsg, WPARAM w_param, LPARAM l_param) { + LRESULT reference_result = static_cast<LRESULT>(0L); + + // Accessibility readers will send an OBJID_CLIENT message + if (OBJID_CLIENT == l_param) { + // If our MSAA root is already created, reuse that pointer. Otherwise, + // create a new one. + if (!accessibility_root_) { + CComObject<ViewAccessibility>* instance = NULL; + + HRESULT hr = CComObject<ViewAccessibility>::CreateInstance(&instance); + DCHECK(SUCCEEDED(hr)); + + if (!instance) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + CComPtr<IAccessible> accessibility_instance(instance); + + if (!SUCCEEDED(instance->Initialize(root_view_.get()))) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + // All is well, assign the temp instance to the class smart pointer + accessibility_root_.Attach(accessibility_instance.Detach()); + + if (!accessibility_root_) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + // Notify that an instance of IAccessible was allocated for m_hWnd + ::NotifyWinEvent(EVENT_OBJECT_CREATE, GetHWND(), OBJID_CLIENT, + CHILDID_SELF); + } + + // Create a reference to ViewAccessibility that MSAA will marshall + // to the client. + reference_result = LresultFromObject(IID_IAccessible, w_param, + static_cast<IAccessible*>(accessibility_root_)); + } + return reference_result; +} + +void WidgetWin::OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags) { + KeyEvent event(Event::ET_KEY_PRESSED, c, rep_cnt, flags); + root_view_->ProcessKeyEvent(event); +} + +void WidgetWin::OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags) { + KeyEvent event(Event::ET_KEY_RELEASED, c, rep_cnt, flags); + root_view_->ProcessKeyEvent(event); +} + +void WidgetWin::OnLButtonDown(UINT flags, const CPoint& point) { + ProcessMousePressed(point, flags | MK_LBUTTON, false); +} + +void WidgetWin::OnLButtonUp(UINT flags, const CPoint& point) { + ProcessMouseReleased(point, flags | MK_LBUTTON); +} + +void WidgetWin::OnLButtonDblClk(UINT flags, const CPoint& point) { + ProcessMousePressed(point, flags | MK_LBUTTON, true); +} + +void WidgetWin::OnMButtonDown(UINT flags, const CPoint& point) { + ProcessMousePressed(point, flags | MK_MBUTTON, false); +} + +void WidgetWin::OnMButtonUp(UINT flags, const CPoint& point) { + ProcessMouseReleased(point, flags | MK_MBUTTON); +} + +void WidgetWin::OnMButtonDblClk(UINT flags, const CPoint& point) { + ProcessMousePressed(point, flags | MK_MBUTTON, true); +} + +LRESULT WidgetWin::OnMouseActivate(HWND window, UINT hittest_code, + UINT message) { + SetMsgHandled(FALSE); + return MA_ACTIVATE; +} + +void WidgetWin::OnMouseMove(UINT flags, const CPoint& point) { + ProcessMouseMoved(point, flags, false); +} + +LRESULT WidgetWin::OnMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param) { + tooltip_manager_->OnMouseLeave(); + ProcessMouseExited(); + return 0; +} + +LRESULT WidgetWin::OnMouseWheel(UINT flags, short distance, + const CPoint& point) { + MouseWheelEvent e(distance, + point.x, + point.y, + Event::ConvertWindowsFlags(flags)); + return root_view_->ProcessMouseWheelEvent(e) ? 0 : 1; +} + +LRESULT WidgetWin::OnMouseRange(UINT msg, WPARAM w_param, LPARAM l_param) { + tooltip_manager_->OnMouse(msg, w_param, l_param); + SetMsgHandled(FALSE); + return 0; +} + +void WidgetWin::OnNCLButtonDblClk(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +void WidgetWin::OnNCLButtonDown(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +void WidgetWin::OnNCLButtonUp(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +void WidgetWin::OnNCMButtonDblClk(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +void WidgetWin::OnNCMButtonDown(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +void WidgetWin::OnNCMButtonUp(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +LRESULT WidgetWin::OnNCMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param) { + ProcessMouseExited(); + return 0; +} + +LRESULT WidgetWin::OnNCMouseMove(UINT flags, const CPoint& point) { + // NC points are in screen coordinates. + CPoint temp = point; + MapWindowPoints(HWND_DESKTOP, GetHWND(), &temp, 1); + ProcessMouseMoved(temp, 0, true); + + // We need to process this message to stop Windows from drawing the window + // controls as the mouse moves over the title bar area when the window is + // maximized. + return 0; +} + +void WidgetWin::OnNCRButtonDblClk(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +void WidgetWin::OnNCRButtonDown(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +void WidgetWin::OnNCRButtonUp(UINT flags, const CPoint& point) { + SetMsgHandled(FALSE); +} + +LRESULT WidgetWin::OnNotify(int w_param, NMHDR* l_param) { + // We can be sent this message before the tooltip manager is created, if a + // subclass overrides OnCreate and creates some kind of Windows control there + // that sends WM_NOTIFY messages. + if (tooltip_manager_.get()) { + bool handled; + LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled); + SetMsgHandled(handled); + return result; + } + SetMsgHandled(FALSE); + return 0; +} + +void WidgetWin::OnPaint(HDC dc) { + root_view_->OnPaint(GetHWND()); +} + +void WidgetWin::OnRButtonDown(UINT flags, const CPoint& point) { + ProcessMousePressed(point, flags | MK_RBUTTON, false); +} + +void WidgetWin::OnRButtonUp(UINT flags, const CPoint& point) { + ProcessMouseReleased(point, flags | MK_RBUTTON); +} + +void WidgetWin::OnRButtonDblClk(UINT flags, const CPoint& point) { + ProcessMousePressed(point, flags | MK_RBUTTON, true); +} + +LRESULT WidgetWin::OnSettingChange(UINT msg, WPARAM w_param, LPARAM l_param) { + if (toplevel_) { + SetMsgHandled(FALSE); + if (w_param != SPI_SETWORKAREA) + return 0; // Return value is effectively ignored in atlwin.h. + + AdjustWindowToFitScreenSize(); + SetMsgHandled(TRUE); + } + // Don't care, overridden by interested subclasses + return 0; +} + +void WidgetWin::OnSize(UINT param, const CSize& size) { + ChangeSize(param, size); +} + +void WidgetWin::OnThemeChanged() { + // Notify NativeTheme. + gfx::NativeTheme::instance()->CloseHandles(); +} + +void WidgetWin::OnFinalMessage(HWND window) { + if (delete_on_destroy_) + delete this; +} + +/////////////////////////////////////////////////////////////////////////////// +// WidgetWin, protected: + +void WidgetWin::TrackMouseEvents(DWORD mouse_tracking_flags) { + // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE + // when the user moves the mouse outside this HWND's bounds. + if (active_mouse_tracking_flags_ == 0 || mouse_tracking_flags & TME_CANCEL) { + if (mouse_tracking_flags & TME_CANCEL) { + // We're about to cancel active mouse tracking, so empty out the stored + // state. + active_mouse_tracking_flags_ = 0; + } else { + active_mouse_tracking_flags_ = mouse_tracking_flags; + } + + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.dwFlags = mouse_tracking_flags; + tme.hwndTrack = GetHWND(); + tme.dwHoverTime = 0; + TrackMouseEvent(&tme); + } else if (mouse_tracking_flags != active_mouse_tracking_flags_) { + TrackMouseEvents(active_mouse_tracking_flags_ | TME_CANCEL); + TrackMouseEvents(mouse_tracking_flags); + } +} + +bool WidgetWin::ProcessMousePressed(const CPoint& point, UINT flags, + bool dbl_click) { + last_mouse_event_was_move_ = false; + MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, + point.x, + point.y, + (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) | + Event::ConvertWindowsFlags(flags)); + if (root_view_->OnMousePressed(mouse_pressed)) { + is_mouse_down_ = true; + if (!has_capture_) { + SetCapture(); + has_capture_ = true; + current_action_ = FA_FORWARDING; + } + return true; + } + return false; +} + +void WidgetWin::ProcessMouseDragged(const CPoint& point, UINT flags) { + last_mouse_event_was_move_ = false; + MouseEvent mouse_drag(Event::ET_MOUSE_DRAGGED, + point.x, + point.y, + Event::ConvertWindowsFlags(flags)); + root_view_->OnMouseDragged(mouse_drag); +} + +void WidgetWin::ProcessMouseReleased(const CPoint& point, UINT flags) { + last_mouse_event_was_move_ = false; + MouseEvent mouse_up(Event::ET_MOUSE_RELEASED, + point.x, + point.y, + Event::ConvertWindowsFlags(flags)); + // Release the capture first, that way we don't get confused if + // OnMouseReleased blocks. + if (has_capture_ && ReleaseCaptureOnMouseReleased()) { + has_capture_ = false; + current_action_ = FA_NONE; + ReleaseCapture(); + } + is_mouse_down_ = false; + root_view_->OnMouseReleased(mouse_up, false); +} + +void WidgetWin::ProcessMouseMoved(const CPoint &point, UINT flags, + bool is_nonclient) { + // Windows only fires WM_MOUSELEAVE events if the application begins + // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events. + // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE. + if (!has_capture_) + TrackMouseEvents(is_nonclient ? TME_NONCLIENT | TME_LEAVE : TME_LEAVE); + if (has_capture_ && is_mouse_down_) { + ProcessMouseDragged(point, flags); + } else { + gfx::Point screen_loc(point); + View::ConvertPointToScreen(root_view_.get(), &screen_loc); + if (last_mouse_event_was_move_ && last_mouse_move_x_ == screen_loc.x() && + last_mouse_move_y_ == screen_loc.y()) { + // Don't generate a mouse event for the same location as the last. + return; + } + last_mouse_move_x_ = screen_loc.x(); + last_mouse_move_y_ = screen_loc.y(); + last_mouse_event_was_move_ = true; + MouseEvent mouse_move(Event::ET_MOUSE_MOVED, + point.x, + point.y, + Event::ConvertWindowsFlags(flags)); + root_view_->OnMouseMoved(mouse_move); + } +} + +void WidgetWin::ProcessMouseExited() { + last_mouse_event_was_move_ = false; + root_view_->ProcessOnMouseExited(); + // Reset our tracking flag so that future mouse movement over this WidgetWin + // results in a new tracking session. + active_mouse_tracking_flags_ = 0; +} + +void WidgetWin::AdjustWindowToFitScreenSize() { + // Desktop size has changed. Make sure we're still on screen. + CRect wr; + GetWindowRect(&wr); + HMONITOR hmon = MonitorFromRect(&wr, MONITOR_DEFAULTTONEAREST); + if (!hmon) { + // No monitor available. + return; + } + + MONITORINFO mi; + mi.cbSize = sizeof(mi); + GetMonitorInfo(hmon, &mi); + gfx::Rect window_rect(wr); + gfx::Rect monitor_rect(mi.rcWork); + gfx::Rect new_window_rect = window_rect.AdjustToFit(monitor_rect); + if (!new_window_rect.Equals(window_rect)) { + // New position differs from last, resize window. + ::SetWindowPos(GetHWND(), + 0, + new_window_rect.x(), + new_window_rect.y(), + new_window_rect.width(), + new_window_rect.height(), + SWP_NOACTIVATE | SWP_NOZORDER); + } +} + +void WidgetWin::ChangeSize(UINT size_param, const CSize& size) { + CRect rect; + if (layered_) { + GetWindowRect(&rect); + SizeContents(rect); + } else { + GetClientRect(&rect); + } + + // Resizing changes the size of the view hierarchy and thus forces a + // complete relayout. + root_view_->SetBounds(0, 0, rect.Width(), rect.Height()); + root_view_->Layout(); + root_view_->SchedulePaint(); + + if (layered_) + PaintNow(gfx::Rect(rect)); +} + +RootView* WidgetWin::CreateRootView() { + return new RootView(this); +} + +/////////////////////////////////////////////////////////////////////////////// +// WidgetWin, private: + +void WidgetWin::SizeContents(const CRect& window_rect) { + contents_.reset(new ChromeCanvas(window_rect.Width(), + window_rect.Height(), + false)); +} + +void WidgetWin::PaintLayeredWindow() { + // Painting monkeys with our cliprect, so we need to save it so that the + // call to UpdateLayeredWindow updates the entire window, not just the + // cliprect. + contents_->save(SkCanvas::kClip_SaveFlag); + gfx::Rect dirty_rect = root_view_->GetScheduledPaintRect(); + contents_->ClipRectInt(dirty_rect.x(), dirty_rect.y(), dirty_rect.width(), + dirty_rect.height()); + root_view_->ProcessPaint(contents_.get()); + contents_->restore(); + + UpdateWindowFromContents(contents_->getTopPlatformDevice().getBitmapDC()); +} + +void WidgetWin::UpdateWindowFromContents(HDC dib_dc) { + DCHECK(layered_); + if (can_update_layered_window_) { + CRect wr; + GetWindowRect(&wr); + CSize size(wr.right - wr.left, wr.bottom - wr.top); + CPoint zero_origin(0, 0); + CPoint window_position = wr.TopLeft(); + + BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA}; + ::UpdateLayeredWindow( + hwnd_, NULL, &window_position, &size, dib_dc, &zero_origin, + RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); + } +} + +std::wstring WidgetWin::GetWindowClassName() { + if (!registered_classes) + registered_classes = new RegisteredClasses(); + ClassInfo class_info(initial_class_style()); + for (RegisteredClasses::iterator i = registered_classes->begin(); + i != registered_classes->end(); ++i) { + if (class_info.Equals(i->info)) + return i->name; + } + + // No class found, need to register one. + static int registered_count = 0; + std::wstring name = + std::wstring(kBaseClassName) + IntToWString(registered_count++); + WNDCLASSEX class_ex; + class_ex.cbSize = sizeof(WNDCLASSEX); + class_ex.style = class_info.style; + class_ex.lpfnWndProc = &WidgetWin::WndProc; + class_ex.cbClsExtra = 0; + class_ex.cbWndExtra = 0; + class_ex.hInstance = NULL; + class_ex.hIcon = LoadIcon(GetModuleHandle(L"chrome.dll"), + MAKEINTRESOURCE(IDR_MAINFRAME)); + class_ex.hCursor = LoadCursor(NULL, IDC_ARROW); + class_ex.hbrBackground = reinterpret_cast<HBRUSH>(class_info.background + 1); + class_ex.lpszMenuName = NULL; + class_ex.lpszClassName = name.c_str(); + class_ex.hIconSm = class_ex.hIcon; + ATOM atom = RegisterClassEx(&class_ex); + DCHECK(atom); + RegisteredClass registered_class(class_info, name, atom); + registered_classes->push_back(registered_class); + return name; +} + +// static +LRESULT CALLBACK WidgetWin::WndProc(HWND window, UINT message, + WPARAM w_param, LPARAM l_param) { + if (message == WM_NCCREATE) { + CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param); + WidgetWin* widget = reinterpret_cast<WidgetWin*>(cs->lpCreateParams); + DCHECK(widget); + win_util::SetWindowUserData(window, widget); + widget->hwnd_ = window; + return TRUE; + } + WidgetWin* widget = reinterpret_cast<WidgetWin*>( + win_util::GetWindowUserData(window)); + if (!widget) + return 0; + LRESULT result = 0; + if (!widget->ProcessWindowMessage(window, message, w_param, l_param, result)) + result = DefWindowProc(window, message, w_param, l_param); + if (message == WM_NCDESTROY) { + widget->hwnd_ = NULL; + widget->OnFinalMessage(window); + } + return result; +} + +} // namespace views + |