| // Copyright (c) 2010 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 "views/widget/widget_win.h" |
| |
| #include "app/l10n_util_win.h" |
| #include "app/system_monitor.h" |
| #include "app/win_util.h" |
| #include "base/string_util.h" |
| #include "base/win_util.h" |
| #include "gfx/canvas_skia.h" |
| #include "gfx/native_theme_win.h" |
| #include "gfx/path.h" |
| #include "views/accessibility/view_accessibility.h" |
| #include "views/controls/native_control_win.h" |
| #include "views/focus/focus_util_win.h" |
| #include "views/views_delegate.h" |
| #include "views/widget/aero_tooltip_manager.h" |
| #include "views/widget/default_theme_provider.h" |
| #include "views/widget/drop_target_win.h" |
| #include "views/widget/root_view.h" |
| #include "views/widget/widget_delegate.h" |
| #include "views/window/window_win.h" |
| |
| namespace views { |
| |
| // Property used to link the HWND to its RootView. |
| static const wchar_t* const kRootViewWindowProperty = L"__ROOT_VIEW__"; |
| static const wchar_t* kWidgetKey = L"__VIEWS_WIDGET__"; |
| |
| 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)); |
| } |
| |
| NativeControlWin* GetNativeControlWinForHWND(HWND hwnd) { |
| return reinterpret_cast<NativeControlWin*>( |
| GetProp(hwnd, NativeControlWin::kNativeControlWinKey)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // WidgetWin, public |
| |
| WidgetWin::WidgetWin() |
| : close_widget_factory_(this), |
| active_mouse_tracking_flags_(0), |
| has_capture_(false), |
| use_layered_buffer_(true), |
| layered_alpha_(255), |
| delete_on_destroy_(true), |
| can_update_layered_window_(true), |
| last_mouse_event_was_move_(false), |
| is_mouse_down_(false), |
| is_window_(false), |
| restore_focus_when_enabled_(false), |
| delegate_(NULL), |
| accessibility_view_events_index_(-1), |
| accessibility_view_events_(kMaxAccessibilityViewEvents) { |
| } |
| |
| WidgetWin::~WidgetWin() { |
| } |
| |
| // static |
| WidgetWin* WidgetWin::GetWidget(HWND hwnd) { |
| // TODO(jcivelli): http://crbug.com/44499 We need a way to test that hwnd is |
| // associated with a WidgetWin (it might be a pure |
| // WindowImpl). |
| if (!WindowImpl::IsWindowImpl(hwnd)) |
| return NULL; |
| return reinterpret_cast<WidgetWin*>(win_util::GetWindowUserData(hwnd)); |
| } |
| |
| // static |
| WidgetWin* WidgetWin::GetRootWidget(HWND hwnd) { |
| // First, check if the top-level window is a Widget. |
| HWND root = ::GetAncestor(hwnd, GA_ROOT); |
| if (!root) |
| return NULL; |
| |
| WidgetWin* widget = WidgetWin::GetWidget(root); |
| if (widget) |
| return widget; |
| |
| // Second, try to locate the last Widget window in the parent hierarchy. |
| HWND parent_hwnd = hwnd; |
| WidgetWin* parent_widget; |
| do { |
| parent_widget = WidgetWin::GetWidget(parent_hwnd); |
| if (parent_widget) { |
| widget = parent_widget; |
| parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT); |
| } |
| } while (parent_hwnd != NULL && parent_widget != NULL); |
| |
| return widget; |
| } |
| |
| void WidgetWin::SetUseLayeredBuffer(bool use_layered_buffer) { |
| if (use_layered_buffer_ == use_layered_buffer) |
| return; |
| |
| use_layered_buffer_ = use_layered_buffer; |
| if (!hwnd()) |
| return; |
| |
| if (use_layered_buffer_) |
| LayoutRootView(); |
| else |
| contents_.reset(NULL); |
| } |
| |
| View* WidgetWin::GetAccessibilityViewEventAt(int id) { |
| // Convert from MSAA child id. |
| id = -(id + 1); |
| DCHECK(id >= 0 && id < kMaxAccessibilityViewEvents); |
| return accessibility_view_events_[id]; |
| } |
| |
| int WidgetWin::AddAccessibilityViewEvent(View* view) { |
| accessibility_view_events_index_ = |
| (accessibility_view_events_index_ + 1) % kMaxAccessibilityViewEvents; |
| accessibility_view_events_[accessibility_view_events_index_] = view; |
| |
| // Convert to MSAA child id. |
| return -(accessibility_view_events_index_ + 1); |
| } |
| |
| void WidgetWin::ClearAccessibilityViewEvent(View* view) { |
| for (std::vector<View*>::iterator it = accessibility_view_events_.begin(); |
| it != accessibility_view_events_.end(); |
| ++it) { |
| if (*it == view) |
| *it = NULL; |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Widget implementation: |
| |
| void WidgetWin::Init(gfx::NativeView parent, const gfx::Rect& bounds) { |
| // Force creation of the RootView; otherwise, we may get a WM_SIZE after the |
| // window is created and before the root view is set up. |
| GetRootView(); |
| |
| // Create the window. |
| WindowImpl::Init(parent, bounds); |
| |
| // See if the style has been overridden. |
| opaque_ = !(window_ex_style() & WS_EX_TRANSPARENT); |
| use_layered_buffer_ = (use_layered_buffer_ && |
| !!(window_ex_style() & WS_EX_LAYERED)); |
| |
| default_theme_provider_.reset(new DefaultThemeProvider()); |
| |
| SetWindowSupportsRerouteMouseWheel(hwnd()); |
| |
| drop_target_ = new DropTargetWin(root_view_.get()); |
| |
| if ((window_style() & WS_CHILD) == 0 || |
| (WidgetWin::GetRootWidget(parent) == NULL && |
| parent != GetDesktopWindow())) { |
| // Top-level widgets and child widgets who do not have a top-level widget |
| // ancestor get a FocusManager. Child widgets parented to the desktop do not |
| // get a FocusManager because parenting to the desktop is the technique used |
| // to intentionally exclude a widget from the FocusManager hierarchy. |
| focus_manager_.reset(new FocusManager(this)); |
| } |
| |
| // 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 (GetThemeProvider()->ShouldUseNativeFrame()) { |
| tooltip_manager_.reset(new AeroTooltipManager(this)); |
| } else { |
| tooltip_manager_.reset(new TooltipManagerWin(this)); |
| } |
| |
| // This message initializes the window so that focus border are shown for |
| // windows. |
| SendMessage(hwnd(), |
| 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(hwnd(), NULL, 0); |
| } |
| |
| void WidgetWin::InitWithWidget(Widget* parent, const gfx::Rect& bounds) { |
| Init(parent->GetNativeView(), bounds); |
| } |
| |
| WidgetDelegate* WidgetWin::GetWidgetDelegate() { |
| return delegate_; |
| } |
| |
| void WidgetWin::SetWidgetDelegate(WidgetDelegate* delegate) { |
| delegate_ = delegate; |
| } |
| |
| void WidgetWin::SetContentsView(View* view) { |
| root_view_->SetContentsView(view); |
| } |
| |
| void WidgetWin::GetBounds(gfx::Rect* out, bool including_frame) const { |
| CRect crect; |
| if (including_frame) { |
| GetWindowRect(&crect); |
| *out = gfx::Rect(crect); |
| return; |
| } |
| |
| GetClientRect(&crect); |
| POINT p = {0, 0}; |
| ClientToScreen(hwnd(), &p); |
| out->SetRect(crect.left + p.x, crect.top + p.y, |
| crect.Width(), crect.Height()); |
| } |
| |
| void WidgetWin::SetBounds(const gfx::Rect& bounds) { |
| SetWindowPos(NULL, bounds.x(), bounds.y(), bounds.width(), bounds.height(), |
| SWP_NOACTIVATE | SWP_NOZORDER); |
| } |
| |
| void WidgetWin::MoveAbove(Widget* other) { |
| gfx::Rect bounds; |
| GetBounds(&bounds, false); |
| SetWindowPos(other->GetNativeView(), bounds.x(), bounds.y(), |
| bounds.width(), bounds.height(), SWP_NOACTIVATE); |
| } |
| |
| void WidgetWin::SetShape(gfx::NativeRegion region) { |
| SetWindowRgn(region, TRUE); |
| } |
| |
| void WidgetWin::Close() { |
| if (!IsWindow()) |
| return; // No need to do anything. |
| |
| // 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::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(hwnd()); |
| } |
| |
| void WidgetWin::Show() { |
| if (IsWindow()) |
| ShowWindow(SW_SHOWNOACTIVATE); |
| } |
| |
| void WidgetWin::Hide() { |
| if (IsWindow()) { |
| // 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); |
| } |
| } |
| |
| gfx::NativeView WidgetWin::GetNativeView() const { |
| return WindowImpl::hwnd(); |
| } |
| |
| static BOOL CALLBACK EnumChildProcForRedraw(HWND hwnd, LPARAM lparam) { |
| DWORD process_id; |
| GetWindowThreadProcessId(hwnd, &process_id); |
| gfx::Rect invalid_rect = *reinterpret_cast<gfx::Rect*>(lparam); |
| |
| RECT window_rect; |
| GetWindowRect(hwnd, &window_rect); |
| invalid_rect.Offset(-window_rect.left, -window_rect.top); |
| |
| int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME; |
| if (process_id == GetCurrentProcessId()) |
| flags |= RDW_UPDATENOW; |
| RedrawWindow(hwnd, &invalid_rect.ToRECT(), NULL, flags); |
| return TRUE; |
| } |
| |
| void WidgetWin::PaintNow(const gfx::Rect& update_rect) { |
| if (use_layered_buffer_) { |
| 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 { |
| // Paint child windows that are in a different process asynchronously. |
| // This prevents a hang in other processes from blocking this process. |
| |
| // Calculate the invalid rect in screen coordinates before the first |
| // RedrawWindow call to the parent HWND, since that will empty update_rect |
| // (which comes from a member variable) in the OnPaint call. |
| CRect screen_rect_temp; |
| GetWindowRect(&screen_rect_temp); |
| gfx::Rect screen_rect(screen_rect_temp); |
| gfx::Rect invalid_screen_rect = update_rect; |
| invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y()); |
| |
| RedrawWindow(hwnd(), &update_rect.ToRECT(), NULL, |
| RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN); |
| |
| LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect); |
| EnumChildWindows(hwnd(), EnumChildProcForRedraw, lparam); |
| } |
| // 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(); |
| } |
| } |
| |
| void WidgetWin::SetOpacity(unsigned char opacity) { |
| layered_alpha_ = static_cast<BYTE>(opacity); |
| } |
| |
| void WidgetWin::SetAlwaysOnTop(bool on_top) { |
| if (on_top) |
| set_window_ex_style(window_ex_style() | WS_EX_TOPMOST); |
| else |
| set_window_ex_style(window_ex_style() & ~WS_EX_TOPMOST); |
| } |
| |
| 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(); |
| } |
| |
| Widget* WidgetWin::GetRootWidget() const { |
| return GetRootWidget(hwnd()); |
| } |
| |
| bool WidgetWin::IsVisible() const { |
| return !!::IsWindowVisible(hwnd()); |
| } |
| |
| bool WidgetWin::IsActive() const { |
| return win_util::IsWindowActive(hwnd()); |
| } |
| |
| TooltipManager* WidgetWin::GetTooltipManager() { |
| return tooltip_manager_.get(); |
| } |
| |
| void WidgetWin::GenerateMousePressedForView(View* view, |
| const gfx::Point& point) { |
| gfx::Point point_in_widget(point); |
| View::ConvertPointToWidget(view, &point_in_widget); |
| root_view_->SetMouseHandler(view); |
| ProcessMousePressed(point_in_widget.ToPOINT(), MK_LBUTTON, false, false); |
| } |
| |
| bool WidgetWin::GetAccelerator(int cmd_id, menus::Accelerator* accelerator) { |
| return false; |
| } |
| |
| Window* WidgetWin::GetWindow() { |
| return GetWindowImpl(hwnd()); |
| } |
| |
| const Window* WidgetWin::GetWindow() const { |
| return GetWindowImpl(hwnd()); |
| } |
| |
| void WidgetWin::SetNativeWindowProperty(const std::wstring& name, |
| void* value) { |
| if (value) |
| SetProp(hwnd(), name.c_str(), value); |
| else |
| RemoveProp(hwnd(), name.c_str()); |
| } |
| |
| void* WidgetWin::GetNativeWindowProperty(const std::wstring& name) { |
| return GetProp(hwnd(), name.c_str()); |
| } |
| |
| ThemeProvider* WidgetWin::GetThemeProvider() const { |
| Widget* widget = GetRootWidget(); |
| if (widget && widget != this) { |
| // Attempt to get the theme provider, and fall back to the default theme |
| // provider if not found. |
| ThemeProvider* provider = widget->GetThemeProvider(); |
| if (provider) |
| return provider; |
| |
| provider = widget->GetDefaultThemeProvider(); |
| if (provider) |
| return provider; |
| } |
| return default_theme_provider_.get(); |
| } |
| |
| ThemeProvider* WidgetWin::GetDefaultThemeProvider() const { |
| return default_theme_provider_.get(); |
| } |
| |
| FocusManager* WidgetWin::GetFocusManager() { |
| if (focus_manager_.get()) |
| return focus_manager_.get(); |
| |
| WidgetWin* widget = static_cast<WidgetWin*>(GetRootWidget()); |
| if (widget && widget != this) { |
| // WidgetWin subclasses may override GetFocusManager(), for example for |
| // dealing with cases where the widget has been unparented. |
| return widget->GetFocusManager(); |
| } |
| return NULL; |
| } |
| |
| void WidgetWin::ViewHierarchyChanged(bool is_add, View *parent, |
| View *child) { |
| if (drop_target_.get()) |
| drop_target_->ResetTargetViewIfEquals(child); |
| |
| if (!is_add) |
| ClearAccessibilityViewEvent(child); |
| } |
| |
| |
| bool WidgetWin::ContainsNativeView(gfx::NativeView native_view) { |
| if (hwnd() == native_view) |
| return true; |
| |
| // Traverse the set of parents of the given view to determine if native_view |
| // is a descendant of this window. |
| HWND parent_window = ::GetParent(native_view); |
| HWND previous_child = native_view; |
| while (parent_window && parent_window != previous_child) { |
| if (hwnd() == parent_window) |
| return true; |
| previous_child = parent_window; |
| parent_window = ::GetParent(parent_window); |
| } |
| |
| // A views::NativeViewHost may contain the given native view, without it being |
| // an ancestor of hwnd(), so traverse the views::View hierarchy looking for |
| // such views. |
| return GetRootView()->ContainsNativeView(native_view); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // MessageLoop::Observer |
| |
| void WidgetWin::WillProcessMessage(const MSG& msg) { |
| } |
| |
| void WidgetWin::DidProcessMessage(const MSG& msg) { |
| if (root_view_->NeedsPainting(true)) { |
| PaintNow(root_view_->GetScheduledPaintRect()); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // FocusTraversable |
| |
| FocusSearch* WidgetWin::GetFocusSearch() { |
| return root_view_->GetFocusSearch(); |
| } |
| |
| 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::OnActivate(UINT action, BOOL minimized, HWND window) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnActivateApp(BOOL active, DWORD thread_id) { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT WidgetWin::OnAppCommand(HWND window, short app_command, WORD device, |
| int keystate) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void WidgetWin::OnCancelMode() { |
| } |
| |
| 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() { |
| Close(); |
| } |
| |
| void WidgetWin::OnCommand(UINT notification_code, int command_id, HWND window) { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT WidgetWin::OnCreate(CREATESTRUCT* create_struct) { |
| // Widget::GetWidgetFromNativeView expects the contents of this property |
| // to be of type Widget, so the cast is necessary. |
| SetNativeWindowProperty(kWidgetKey, static_cast<Widget*>(this)); |
| return 0; |
| } |
| |
| void WidgetWin::OnDestroy() { |
| SetNativeWindowProperty(kWidgetKey, NULL); |
| |
| if (drop_target_.get()) { |
| RevokeDragDrop(hwnd()); |
| drop_target_ = NULL; |
| } |
| |
| RemoveProp(hwnd(), kRootViewWindowProperty); |
| } |
| |
| void WidgetWin::OnDisplayChange(UINT bits_per_pixel, CSize screen_size) { |
| if (GetWidgetDelegate()) |
| GetWidgetDelegate()->DisplayChanged(); |
| } |
| |
| LRESULT WidgetWin::OnDwmCompositionChanged(UINT msg, |
| WPARAM w_param, |
| LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void WidgetWin::OnEndSession(BOOL ending, UINT logoff) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnEnterSizeMove() { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT WidgetWin::OnEraseBkgnd(HDC dc) { |
| // This is needed for magical win32 flicker ju-ju |
| return 1; |
| } |
| |
| void WidgetWin::OnExitMenuLoop(BOOL is_track_popup_menu) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnExitSizeMove() { |
| SetMsgHandled(FALSE); |
| } |
| |
| 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); |
| } |
| |
| ScopedComPtr<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); |
| } |
| } |
| |
| // 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::OnGetMinMaxInfo(MINMAXINFO* minmax_info) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnHScroll(int scroll_type, short position, HWND scrollbar) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnInitMenu(HMENU menu) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnInitMenuPopup(HMENU menu, |
| UINT position, |
| BOOL is_system_menu) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags) { |
| KeyEvent event(Event::ET_KEY_PRESSED, win_util::WinToKeyboardCode(c), |
| KeyEvent::GetKeyStateFlags(), rep_cnt, flags); |
| RootView* root_view = GetFocusedViewRootView(); |
| if (!root_view) |
| root_view = root_view_.get(); |
| |
| SetMsgHandled(root_view->ProcessKeyEvent(event)); |
| } |
| |
| void WidgetWin::OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags) { |
| KeyEvent event(Event::ET_KEY_RELEASED, win_util::WinToKeyboardCode(c), |
| KeyEvent::GetKeyStateFlags(), rep_cnt, flags); |
| RootView* root_view = GetFocusedViewRootView(); |
| if (!root_view) |
| root_view = root_view_.get(); |
| |
| SetMsgHandled(root_view->ProcessKeyEvent(event)); |
| } |
| |
| void WidgetWin::OnKillFocus(HWND focused_window) { |
| GetFocusManager()->GetWidgetFocusManager()->OnWidgetFocusEvent( |
| this->GetNativeView(), |
| focused_window); |
| SetMsgHandled(FALSE); |
| } |
| |
| // TODO(pkasting): ORing the pressed/released button into the flags is _wrong_. |
| // It makes it impossible to tell which button was modified when multiple |
| // buttons are/were held down. We need to instead put the modified button into |
| // a separate member on the MouseEvent, then audit all consumers of MouseEvents |
| // to fix them to use the resulting values correctly. |
| |
| void WidgetWin::OnLButtonDown(UINT flags, const CPoint& point) { |
| ProcessMousePressed(point, flags | MK_LBUTTON, false, 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, false); |
| } |
| |
| void WidgetWin::OnMButtonDown(UINT flags, const CPoint& point) { |
| ProcessMousePressed(point, flags | MK_MBUTTON, false, 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, false); |
| } |
| |
| 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 message, WPARAM w_param, LPARAM l_param) { |
| tooltip_manager_->OnMouseLeave(); |
| ProcessMouseExited(); |
| return 0; |
| } |
| |
| LRESULT WidgetWin::OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param) { |
| // Reroute the mouse-wheel to the window under the mouse pointer if |
| // applicable. |
| if (message == WM_MOUSEWHEEL && |
| views::RerouteMouseWheel(hwnd(), w_param, l_param)) { |
| return 0; |
| } |
| |
| int flags = GET_KEYSTATE_WPARAM(w_param); |
| short distance = GET_WHEEL_DELTA_WPARAM(w_param); |
| int x = GET_X_LPARAM(l_param); |
| int y = GET_Y_LPARAM(l_param); |
| MouseWheelEvent e(distance, x, y, Event::ConvertWindowsFlags(flags)); |
| return root_view_->ProcessMouseWheelEvent(e) ? 0 : 1; |
| } |
| |
| void WidgetWin::OnMove(const CPoint& point) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnMoving(UINT param, const LPRECT new_bounds) { |
| } |
| |
| LRESULT WidgetWin::OnMouseRange(UINT msg, WPARAM w_param, LPARAM l_param) { |
| tooltip_manager_->OnMouse(msg, w_param, l_param); |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT WidgetWin::OnNCActivate(BOOL active) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT WidgetWin::OnNCCalcSize(BOOL w_param, LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT WidgetWin::OnNCHitTest(const CPoint& pt) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void WidgetWin::OnNCLButtonDblClk(UINT flags, const CPoint& point) { |
| SetMsgHandled(ProcessMousePressed(point, flags | MK_LBUTTON, true, true)); |
| } |
| |
| void WidgetWin::OnNCLButtonDown(UINT flags, const CPoint& point) { |
| SetMsgHandled(ProcessMousePressed(point, flags | MK_LBUTTON, false, true)); |
| } |
| |
| void WidgetWin::OnNCLButtonUp(UINT flags, const CPoint& point) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnNCMButtonDblClk(UINT flags, const CPoint& point) { |
| SetMsgHandled(ProcessMousePressed(point, flags | MK_MBUTTON, true, true)); |
| } |
| |
| void WidgetWin::OnNCMButtonDown(UINT flags, const CPoint& point) { |
| SetMsgHandled(ProcessMousePressed(point, flags | MK_MBUTTON, false, true)); |
| } |
| |
| 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, hwnd(), &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::OnNCPaint(HRGN rgn) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnNCRButtonDblClk(UINT flags, const CPoint& point) { |
| SetMsgHandled(ProcessMousePressed(point, flags | MK_RBUTTON, true, true)); |
| } |
| |
| void WidgetWin::OnNCRButtonDown(UINT flags, const CPoint& point) { |
| SetMsgHandled(ProcessMousePressed(point, flags | MK_RBUTTON, false, true)); |
| } |
| |
| void WidgetWin::OnNCRButtonUp(UINT flags, const CPoint& point) { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT WidgetWin::OnNCUAHDrawCaption(UINT msg, |
| WPARAM w_param, |
| LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT WidgetWin::OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| 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(hwnd()); |
| } |
| |
| LRESULT WidgetWin::OnPowerBroadcast(DWORD power_event, DWORD data) { |
| SystemMonitor* monitor = SystemMonitor::Get(); |
| if (monitor) |
| monitor->ProcessWmPowerBroadcastMessage(power_event); |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void WidgetWin::OnRButtonDown(UINT flags, const CPoint& point) { |
| ProcessMousePressed(point, flags | MK_RBUTTON, false, 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, false); |
| } |
| |
| LRESULT WidgetWin::OnReflectedMessage(UINT msg, |
| WPARAM w_param, |
| LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void WidgetWin::OnSetFocus(HWND focused_window) { |
| GetFocusManager()->GetWidgetFocusManager()->OnWidgetFocusEvent( |
| focused_window, |
| this->GetNativeView()); |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT WidgetWin::OnSetIcon(UINT size_type, HICON new_icon) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT WidgetWin::OnSetText(const wchar_t* text) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void WidgetWin::OnSettingChange(UINT flags, const wchar_t* section) { |
| if (flags == SPI_SETWORKAREA && GetWidgetDelegate()) |
| GetWidgetDelegate()->WorkAreaChanged(); |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnSize(UINT param, const CSize& size) { |
| LayoutRootView(); |
| } |
| |
| void WidgetWin::OnSysCommand(UINT notification_code, CPoint click) { |
| } |
| |
| void WidgetWin::OnThemeChanged() { |
| // Notify NativeTheme. |
| gfx::NativeTheme::instance()->CloseHandles(); |
| } |
| |
| void WidgetWin::OnFinalMessage(HWND window) { |
| if (delete_on_destroy_) |
| delete this; |
| } |
| |
| void WidgetWin::OnVScroll(int scroll_type, short position, HWND scrollbar) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnWindowPosChanging(WINDOWPOS* window_pos) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void WidgetWin::OnWindowPosChanged(WINDOWPOS* window_pos) { |
| SetMsgHandled(FALSE); |
| } |
| |
| gfx::Size WidgetWin::GetRootViewSize() const { |
| CRect rect; |
| if (use_layered_buffer_) |
| GetWindowRect(&rect); |
| else |
| GetClientRect(&rect); |
| |
| return gfx::Size(rect.Width(), rect.Height()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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 = hwnd(); |
| 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, |
| bool non_client) { |
| last_mouse_event_was_move_ = false; |
| // Windows gives screen coordinates for nonclient events, while the RootView |
| // expects window coordinates; convert if necessary. |
| gfx::Point converted_point(point); |
| if (non_client) |
| View::ConvertPointToView(NULL, root_view_.get(), &converted_point); |
| MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, |
| converted_point.x(), |
| converted_point.y(), |
| (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) | |
| (non_client ? MouseEvent::EF_IS_NON_CLIENT : 0) | |
| Event::ConvertWindowsFlags(flags)); |
| if (root_view_->OnMousePressed(mouse_pressed)) { |
| is_mouse_down_ = true; |
| if (!has_capture_) { |
| SetCapture(); |
| has_capture_ = true; |
| } |
| 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; |
| 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::LayoutRootView() { |
| gfx::Size size(GetRootViewSize()); |
| |
| if (use_layered_buffer_) |
| SizeContents(size); |
| |
| // Resizing changes the size of the view hierarchy and thus forces a |
| // complete relayout. |
| root_view_->SetBounds(0, 0, size.width(), size.height()); |
| root_view_->SchedulePaint(); |
| |
| if (use_layered_buffer_) |
| PaintNow(gfx::Rect(0, 0, size.width(), size.height())); |
| } |
| |
| bool WidgetWin::ReleaseCaptureOnMouseReleased() { |
| return true; |
| } |
| |
| RootView* WidgetWin::CreateRootView() { |
| return new RootView(this); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // WidgetWin, private: |
| |
| // static |
| Window* WidgetWin::GetWindowImpl(HWND hwnd) { |
| // NOTE: we can't use GetAncestor here as constrained windows are a Window, |
| // but not a top level window. |
| HWND parent = hwnd; |
| while (parent) { |
| WidgetWin* widget = |
| reinterpret_cast<WidgetWin*>(win_util::GetWindowUserData(parent)); |
| if (widget && widget->is_window_) |
| return static_cast<WindowWin*>(widget); |
| parent = ::GetParent(parent); |
| } |
| return NULL; |
| } |
| |
| void WidgetWin::SizeContents(const gfx::Size& window_size) { |
| contents_.reset(new gfx::CanvasSkia(window_size.width(), |
| window_size.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(use_layered_buffer_); |
| 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); |
| } |
| } |
| |
| RootView* WidgetWin::GetFocusedViewRootView() { |
| FocusManager* focus_manager = GetFocusManager(); |
| if (!focus_manager) { |
| NOTREACHED(); |
| return NULL; |
| } |
| View* focused_view = focus_manager->GetFocusedView(); |
| if (!focused_view) |
| return NULL; |
| return focused_view->GetRootView(); |
| } |
| |
| // Get the source HWND of the specified message. Depending on the message, the |
| // source HWND is encoded in either the WPARAM or the LPARAM value. |
| HWND GetControlHWNDForMessage(UINT message, WPARAM w_param, LPARAM l_param) { |
| // Each of the following messages can be sent by a child HWND and must be |
| // forwarded to its associated NativeControlWin for handling. |
| switch (message) { |
| case WM_NOTIFY: |
| return reinterpret_cast<NMHDR*>(l_param)->hwndFrom; |
| case WM_COMMAND: |
| return reinterpret_cast<HWND>(l_param); |
| case WM_CONTEXTMENU: |
| return reinterpret_cast<HWND>(w_param); |
| case WM_CTLCOLORBTN: |
| case WM_CTLCOLORSTATIC: |
| return reinterpret_cast<HWND>(l_param); |
| } |
| return NULL; |
| } |
| |
| HICON WidgetWin::GetDefaultWindowIcon() const { |
| if (ViewsDelegate::views_delegate) |
| return ViewsDelegate::views_delegate->GetDefaultWindowIcon(); |
| return NULL; |
| } |
| |
| // Some messages may be sent to us by a child HWND managed by |
| // NativeControlWin. If this is the case, this function will forward those |
| // messages on to the object associated with the source HWND and return true, |
| // in which case the window procedure must not do any further processing of |
| // the message. If there is no associated NativeControlWin, the return value |
| // will be false and the WndProc can continue processing the message normally. |
| // |l_result| contains the result of the message processing by the control and |
| // must be returned by the WndProc if the return value is true. |
| bool ProcessNativeControlMessage(UINT message, |
| WPARAM w_param, |
| LPARAM l_param, |
| LRESULT* l_result) { |
| *l_result = 0; |
| |
| HWND control_hwnd = GetControlHWNDForMessage(message, w_param, l_param); |
| if (IsWindow(control_hwnd)) { |
| NativeControlWin* wrapper = GetNativeControlWinForHWND(control_hwnd); |
| if (wrapper) |
| return wrapper->ProcessMessage(message, w_param, l_param, l_result); |
| } |
| |
| return false; |
| } |
| |
| LRESULT WidgetWin::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) { |
| HWND window = hwnd(); |
| LRESULT result = 0; |
| |
| // First allow messages sent by child controls to be processed directly by |
| // their associated views. If such a view is present, it will handle the |
| // message *instead of* this WidgetWin. |
| if (ProcessNativeControlMessage(message, w_param, l_param, &result)) |
| return result; |
| |
| // Otherwise we handle everything else. |
| if (!ProcessWindowMessage(window, message, w_param, l_param, result)) |
| result = DefWindowProc(window, message, w_param, l_param); |
| if (message == WM_NCDESTROY) { |
| MessageLoopForUI::current()->RemoveObserver(this); |
| OnFinalMessage(window); |
| } |
| if (message == WM_ACTIVATE) |
| PostProcessActivateMessage(this, LOWORD(w_param)); |
| if (message == WM_ENABLE && restore_focus_when_enabled_) { |
| restore_focus_when_enabled_ = false; |
| focus_manager_->RestoreFocusedView(); |
| } |
| return result; |
| } |
| |
| // static |
| void WidgetWin::PostProcessActivateMessage(WidgetWin* widget, |
| int activation_state) { |
| if (!widget->focus_manager_.get()) { |
| NOTREACHED(); |
| return; |
| } |
| if (WA_INACTIVE == activation_state) { |
| // We might get activated/inactivated without being enabled, so we need to |
| // clear restore_focus_when_enabled_. |
| widget->restore_focus_when_enabled_ = false; |
| widget->focus_manager_->StoreFocusedView(); |
| } else { |
| // We must restore the focus after the message has been DefProc'ed as it |
| // does set the focus to the last focused HWND. |
| // Note that if the window is not enabled, we cannot restore the focus as |
| // calling ::SetFocus on a child of the non-enabled top-window would fail. |
| // This is the case when showing a modal dialog (such as 'open file', |
| // 'print'...) from a different thread. |
| // In that case we delay the focus restoration to when the window is enabled |
| // again. |
| if (!IsWindowEnabled(widget->GetNativeView())) { |
| DCHECK(!widget->restore_focus_when_enabled_); |
| widget->restore_focus_when_enabled_ = true; |
| return; |
| } |
| widget->focus_manager_->RestoreFocusedView(); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, public: |
| |
| // static |
| Widget* Widget::CreatePopupWidget(TransparencyParam transparent, |
| EventsParam accept_events, |
| DeleteParam delete_on_destroy, |
| MirroringParam mirror_in_rtl) { |
| WidgetWin* popup = new WidgetWin; |
| DWORD ex_style = WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE; |
| if (mirror_in_rtl == MirrorOriginInRTL) |
| ex_style |= l10n_util::GetExtendedTooltipStyles(); |
| if (transparent == Transparent) |
| ex_style |= WS_EX_LAYERED; |
| if (accept_events != AcceptEvents) |
| ex_style |= WS_EX_TRANSPARENT; |
| popup->set_window_style(WS_POPUP); |
| popup->set_window_ex_style(ex_style); |
| popup->set_delete_on_destroy(delete_on_destroy == DeleteOnDestroy); |
| return popup; |
| } |
| |
| 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* Widget::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; |
| } |
| |
| // Enumerate child windows as they could have RootView distinct from |
| // the HWND's root view. |
| BOOL CALLBACK EnumAllRootViewsChildProc(HWND hwnd, LPARAM l_param) { |
| RootView* root_view = |
| reinterpret_cast<RootView*>(GetProp(hwnd, kRootViewWindowProperty)); |
| if (root_view) { |
| std::set<RootView*>* root_views_set = |
| reinterpret_cast<std::set<RootView*>*>(l_param); |
| root_views_set->insert(root_view); |
| } |
| return TRUE; // Keep enumerating. |
| } |
| |
| void Widget::FindAllRootViews(HWND window, |
| std::vector<RootView*>* root_views) { |
| RootView* root_view = |
| reinterpret_cast<RootView*>(GetProp(window, kRootViewWindowProperty)); |
| std::set<RootView*> root_views_set; |
| if (root_view) |
| root_views_set.insert(root_view); |
| // Enumerate all children and check if they have a RootView. |
| EnumChildWindows(window, EnumAllRootViewsChildProc, |
| reinterpret_cast<LPARAM>(&root_views_set)); |
| root_views->clear(); |
| root_views->reserve(root_views_set.size()); |
| for (std::set<RootView*>::iterator it = root_views_set.begin(); |
| it != root_views_set.end(); |
| ++it) |
| root_views->push_back(*it); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, public: |
| |
| // static |
| Widget* Widget::GetWidgetFromNativeView(gfx::NativeView native_view) { |
| if (IsWindow(native_view)) { |
| HANDLE raw_widget = GetProp(native_view, kWidgetKey); |
| if (raw_widget) |
| return reinterpret_cast<Widget*>(raw_widget); |
| } |
| return NULL; |
| } |
| |
| // static |
| Widget* Widget::GetWidgetFromNativeWindow(gfx::NativeWindow native_window) { |
| return Widget::GetWidgetFromNativeView(native_window); |
| } |
| |
| // static |
| void Widget::NotifyLocaleChanged() { |
| NOTIMPLEMENTED(); |
| } |
| |
| } // namespace views |