| // Copyright (c) 2011 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/native_widget_win.h" |
| |
| #include "base/scoped_ptr.h" |
| #include "ui/base/dragdrop/drag_drop_types.h" |
| #include "ui/base/dragdrop/drag_source.h" |
| #include "ui/base/dragdrop/os_exchange_data.h" |
| #include "ui/base/dragdrop/os_exchange_data_provider_win.h" |
| #include "ui/base/system_monitor/system_monitor.h" |
| #include "ui/base/view_prop.h" |
| #include "ui/base/win/hwnd_util.h" |
| #include "ui/gfx/canvas_skia.h" |
| #include "ui/gfx/native_theme_win.h" |
| #include "ui/gfx/path.h" |
| #include "views/view.h" |
| #include "views/widget/widget_impl.h" |
| |
| namespace views { |
| namespace internal { |
| |
| namespace { |
| |
| // Called from NativeWidgetWin::Paint() to asynchronously redraw child windows. |
| 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; |
| } |
| |
| // Links the HWND to its Widget. |
| const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__"; |
| |
| // A custom MSAA object id used to determine if a screen reader is actively |
| // listening for MSAA events. |
| const int kMSAAObjectID = 1; |
| |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidgetWin, public: |
| |
| NativeWidgetWin::NativeWidgetWin(NativeWidgetListener* listener) |
| : listener_(listener), |
| active_mouse_tracking_flags_(0), |
| has_capture_(false) { |
| } |
| |
| NativeWidgetWin::~NativeWidgetWin() { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidgetWin, NativeWidget implementation: |
| |
| void NativeWidgetWin::InitWithNativeViewParent(gfx::NativeView parent, |
| const gfx::Rect& bounds) { |
| WindowImpl::Init(parent, bounds); |
| } |
| |
| void NativeWidgetWin::SetNativeWindowProperty(const char* name, void* value) { |
| // Remove the existing property (if any). |
| for (ViewProps::iterator i = props_.begin(); i != props_.end(); ++i) { |
| if ((*i)->Key() == name) { |
| props_.erase(i); |
| break; |
| } |
| } |
| |
| if (value) |
| props_.push_back(new ui::ViewProp(hwnd(), name, value)); |
| } |
| |
| void* NativeWidgetWin::GetNativeWindowProperty(const char* name) const { |
| return ui::ViewProp::GetValue(hwnd(), name); |
| } |
| |
| gfx::Rect NativeWidgetWin::GetWindowScreenBounds() const { |
| RECT r; |
| GetWindowRect(hwnd(), &r); |
| return gfx::Rect(r); |
| } |
| |
| gfx::Rect NativeWidgetWin::GetClientAreaScreenBounds() const { |
| RECT r; |
| GetClientRect(hwnd(), &r); |
| POINT point = { r.left, r.top }; |
| ClientToScreen(hwnd(), &point); |
| return gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top); |
| } |
| |
| void NativeWidgetWin::SetBounds(const gfx::Rect& bounds) { |
| SetWindowPos(hwnd(), NULL, bounds.x(), bounds.y(), bounds.width(), |
| bounds.height(), SWP_NOACTIVATE | SWP_NOZORDER); |
| } |
| |
| void NativeWidgetWin::SetShape(const gfx::Path& shape) { |
| SetWindowRgn(hwnd(), shape.CreateNativeRegion(), TRUE); |
| } |
| |
| gfx::NativeView NativeWidgetWin::GetNativeView() const { |
| return hwnd(); |
| } |
| |
| void NativeWidgetWin::Show() { |
| if (IsWindow(hwnd())) |
| ShowWindow(hwnd(), SW_SHOWNOACTIVATE); |
| // TODO(beng): move to windowposchanging to trap visibility changes instead. |
| if (IsLayeredWindow()) |
| Invalidate(); |
| } |
| |
| void NativeWidgetWin::Hide() { |
| if (IsWindow(hwnd())) { |
| // 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(hwnd(), NULL, 0, 0, 0, 0, |
| SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | |
| SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER); |
| } |
| } |
| |
| void NativeWidgetWin::Close() { |
| DestroyWindow(hwnd()); |
| } |
| |
| void NativeWidgetWin::MoveAbove(NativeWidget* other) { |
| SetWindowPos(hwnd(), other->GetNativeView(), 0, 0, 0, 0, |
| SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); |
| } |
| |
| void NativeWidgetWin::SetAlwaysOnTop(bool always_on_top) { |
| DWORD style = always_on_top ? window_ex_style() | WS_EX_TOPMOST |
| : window_ex_style() & ~WS_EX_TOPMOST; |
| set_window_ex_style(style); |
| SetWindowLong(hwnd(), GWL_EXSTYLE, window_ex_style()); |
| } |
| |
| bool NativeWidgetWin::IsVisible() const { |
| return !!IsWindowVisible(hwnd()); |
| } |
| |
| bool NativeWidgetWin::IsActive() const { |
| WINDOWINFO info; |
| return ::GetWindowInfo(hwnd(), &info) && |
| ((info.dwWindowStatus & WS_ACTIVECAPTION) != 0); |
| } |
| |
| void NativeWidgetWin::SetMouseCapture() { |
| SetCapture(hwnd()); |
| has_capture_ = true; |
| } |
| |
| void NativeWidgetWin::ReleaseMouseCapture() { |
| ReleaseCapture(); |
| has_capture_ = false; |
| } |
| |
| bool NativeWidgetWin::HasMouseCapture() const { |
| return has_capture_; |
| } |
| |
| bool NativeWidgetWin::ShouldReleaseCaptureOnMouseReleased() const { |
| return true; |
| } |
| |
| void NativeWidgetWin::Invalidate() { |
| ::InvalidateRect(hwnd(), NULL, FALSE); |
| } |
| |
| void NativeWidgetWin::InvalidateRect(const gfx::Rect& invalid_rect) { |
| // InvalidateRect() expects client coordinates. |
| RECT r = invalid_rect.ToRECT(); |
| ::InvalidateRect(hwnd(), &r, FALSE); |
| } |
| |
| void NativeWidgetWin::Paint() { |
| RECT r; |
| GetUpdateRect(hwnd(), &r, FALSE); |
| if (!IsRectEmpty(&r)) { |
| // TODO(beng): WS_EX_TRANSPARENT windows (see WidgetWin::opaque_) |
| // 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. |
| gfx::Rect screen_rect = GetWindowScreenBounds(); |
| gfx::Rect invalid_screen_rect(r); |
| invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y()); |
| |
| RedrawWindow(hwnd(), &r, NULL, |
| RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN); |
| |
| LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect); |
| EnumChildWindows(hwnd(), EnumChildProcForRedraw, lparam); |
| } |
| } |
| |
| void NativeWidgetWin::FocusNativeView(gfx::NativeView native_view) { |
| if (IsWindow(native_view)) { |
| if (GetFocus() != native_view) |
| SetFocus(native_view); |
| } else { |
| // NULL or invalid |native_view| passed, we consider this to be clearing |
| // focus. Keep the top level window focused so we continue to receive |
| // key events. |
| SetFocus(hwnd()); |
| } |
| } |
| |
| void NativeWidgetWin::RunShellDrag(const ui::OSExchangeData& data, |
| int operation) { |
| scoped_refptr<ui::DragSource> drag_source(new ui::DragSource); |
| DWORD effects; |
| DoDragDrop(ui::OSExchangeDataProviderWin::GetIDataObject(data), drag_source, |
| ui::DragDropTypes::DragOperationToDropEffect(operation), &effects); |
| } |
| |
| WidgetImpl* NativeWidgetWin::GetWidgetImpl() { |
| return listener_->GetWidgetImpl(); |
| } |
| |
| const WidgetImpl* NativeWidgetWin::GetWidgetImpl() const { |
| return listener_->GetWidgetImpl(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidetWin, MessageLoopForUI::Observer implementation |
| |
| void NativeWidgetWin::WillProcessMessage(const MSG& msg) { |
| } |
| |
| void NativeWidgetWin::DidProcessMessage(const MSG& msg) { |
| // We need to add ourselves as a message loop observer so that we can repaint |
| // aggressively if the contents of our window become invalid. Unfortunately |
| // WM_PAINT messages are starved and we get flickery redrawing when resizing |
| // if we do not do this. |
| Paint(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidgetWin, message handlers: |
| |
| void NativeWidgetWin::OnActivate(UINT action, BOOL minimized, HWND window) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnActivateApp(BOOL active, DWORD thread_id) { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT NativeWidgetWin::OnAppCommand(HWND window, short app_command, |
| WORD device, int keystate) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnCancelMode() { |
| } |
| |
| void NativeWidgetWin::OnCaptureChanged(HWND hwnd) { |
| has_capture_ = false; |
| listener_->OnMouseCaptureLost(); |
| } |
| |
| void NativeWidgetWin::OnClose() { |
| listener_->OnClose(); |
| } |
| |
| void NativeWidgetWin::OnCommand(UINT notification_code, int command_id, |
| HWND window) { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT NativeWidgetWin::OnCreate(CREATESTRUCT* create_struct) { |
| SetNativeWindowProperty(kNativeWidgetKey, this); |
| listener_->OnNativeWidgetCreated(); |
| MessageLoopForUI::current()->AddObserver(this); |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnDestroy() { |
| // TODO(beng): drop_target_ |
| props_.reset(); |
| } |
| |
| void NativeWidgetWin::OnDisplayChange(UINT bits_per_pixel, CSize screen_size) { |
| listener_->OnDisplayChanged(); |
| } |
| |
| LRESULT NativeWidgetWin::OnDwmCompositionChanged(UINT message, |
| WPARAM w_param, |
| LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnEndSession(BOOL ending, UINT logoff) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnEnterSizeMove() { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT NativeWidgetWin::OnEraseBkgnd(HDC dc) { |
| // This is needed for magical win32 flicker ju-ju |
| return 1; |
| } |
| |
| void NativeWidgetWin::OnExitMenuLoop(BOOL is_track_popup_menu) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnExitSizeMove() { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT NativeWidgetWin::OnGetObject(UINT message, WPARAM w_param, |
| LPARAM l_param) { |
| return static_cast<LRESULT>(0L); |
| } |
| |
| void NativeWidgetWin::OnGetMinMaxInfo(MINMAXINFO* minmax_info) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnHScroll(int scroll_type, short position, |
| HWND scrollbar) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnInitMenu(HMENU menu) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnInitMenuPopup(HMENU menu, UINT position, |
| BOOL is_system_menu) { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT NativeWidgetWin::OnKeyDown(UINT message, WPARAM w_param, |
| LPARAM l_param) { |
| MSG msg; |
| MakeMSG(&msg, message, w_param, l_param); |
| SetMsgHandled(listener_->OnKeyEvent(KeyEvent(msg))); |
| return 0; |
| } |
| |
| LRESULT NativeWidgetWin::OnKeyUp(UINT message, WPARAM w_param, LPARAM l_param) { |
| MSG msg; |
| MakeMSG(&msg, message, w_param, l_param); |
| SetMsgHandled(listener_->OnKeyEvent(KeyEvent(msg))); |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnKillFocus(HWND focused_window) { |
| listener_->OnNativeBlur(focused_window); |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT NativeWidgetWin::OnMouseActivate(HWND window, UINT hittest_code, |
| UINT message) { |
| SetMsgHandled(FALSE); |
| return MA_ACTIVATE; |
| } |
| |
| LRESULT NativeWidgetWin::OnMouseLeave(UINT message, WPARAM w_param, |
| LPARAM l_param) { |
| // TODO(beng): tooltip |
| MSG msg; |
| MakeMSG(&msg, message, w_param, l_param); |
| //SetMsgHandled(listener_->OnMouseEvent(MouseEvent(msg))); |
| |
| // Reset our tracking flag so that future mouse movement over this WidgetWin |
| // results in a new tracking session. |
| active_mouse_tracking_flags_ = 0; |
| |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnMove(const CPoint& point) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnMoving(UINT param, LPRECT new_bounds) { |
| } |
| |
| LRESULT NativeWidgetWin::OnMouseRange(UINT message, WPARAM w_param, |
| LPARAM l_param) { |
| // TODO(beng): tooltips |
| ProcessMouseRange(message, w_param, l_param, false); |
| return 0; |
| } |
| |
| LRESULT NativeWidgetWin::OnNCActivate(BOOL active) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT NativeWidgetWin::OnNCCalcSize(BOOL w_param, LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT NativeWidgetWin::OnNCHitTest(UINT message, WPARAM w_param, |
| LPARAM l_param) { |
| LRESULT lr = DefWindowProc(hwnd(), message, w_param, l_param); |
| return lr; |
| } |
| |
| LRESULT NativeWidgetWin::OnNCMouseRange(UINT message, WPARAM w_param, |
| LPARAM l_param) { |
| bool processed = ProcessMouseRange(message, w_param, l_param, true); |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnNCPaint(HRGN rgn) { |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT NativeWidgetWin::OnNCUAHDrawCaption(UINT message, |
| WPARAM w_param, |
| LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT NativeWidgetWin::OnNCUAHDrawFrame(UINT message, |
| WPARAM w_param, |
| LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT NativeWidgetWin::OnNotify(int w_param, NMHDR* l_param) { |
| // TODO(beng): tooltips |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnPaint(HDC dc) { |
| if (IsLayeredWindow()) { |
| // We need to clip to the dirty rect ourselves. |
| window_contents_->save(SkCanvas::kClip_SaveFlag); |
| RECT r; |
| GetUpdateRect(hwnd(), &r, FALSE); |
| window_contents_->ClipRectInt(r.left, r.top, r.right - r.left, |
| r.bottom - r.top); |
| listener_->OnPaint(window_contents_.get()); |
| window_contents_->restore(); |
| |
| RECT wr; |
| GetWindowRect(hwnd(), &wr); |
| SIZE size = {wr.right - wr.left, wr.bottom - wr.top}; |
| POINT position = {wr.left, wr.top}; |
| HDC dib_dc = window_contents_->getTopPlatformDevice().getBitmapDC(); |
| POINT zero = {0, 0}; |
| BLENDFUNCTION blend = {AC_SRC_OVER, 0, 125, AC_SRC_ALPHA}; |
| UpdateLayeredWindow(hwnd(), NULL, &position, &size, dib_dc, &zero, |
| RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); |
| } else { |
| scoped_ptr<gfx::CanvasPaint> canvas( |
| gfx::CanvasPaint::CreateCanvasPaint(hwnd())); |
| listener_->OnPaint(canvas->AsCanvas()); |
| } |
| } |
| |
| LRESULT NativeWidgetWin::OnPowerBroadcast(DWORD power_event, DWORD data) { |
| ui::SystemMonitor* monitor = ui::SystemMonitor::Get(); |
| if (monitor) |
| monitor->ProcessWmPowerBroadcastMessage(power_event); |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT NativeWidgetWin::OnReflectedMessage(UINT message, WPARAM w_param, |
| LPARAM l_param) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnSetFocus(HWND focused_window) { |
| listener_->OnNativeFocus(focused_window); |
| SetMsgHandled(FALSE); |
| } |
| |
| LRESULT NativeWidgetWin::OnSetIcon(UINT size_type, HICON new_icon) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| LRESULT NativeWidgetWin::OnSetText(const wchar_t* text) { |
| SetMsgHandled(FALSE); |
| return 0; |
| } |
| |
| void NativeWidgetWin::OnSettingChange(UINT flags, const wchar_t* section) { |
| if (flags == SPI_SETWORKAREA) |
| listener_->OnWorkAreaChanged(); |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnSize(UINT param, const CSize& size) { |
| gfx::Size s(size.cx, size.cy); |
| listener_->OnSizeChanged(s); |
| if (IsLayeredWindow()) { |
| window_contents_.reset( |
| new gfx::CanvasSkia(s.width(), s.height(), false)); |
| } |
| } |
| |
| void NativeWidgetWin::OnSysCommand(UINT notification_code, CPoint click) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnThemeChanged() { |
| gfx::NativeTheme::instance()->CloseHandles(); |
| } |
| |
| void NativeWidgetWin::OnVScroll(int scroll_type, short position, |
| HWND scrollbar) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnWindowPosChanging(WINDOWPOS* window_pos) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnWindowPosChanged(WINDOWPOS* window_pos) { |
| SetMsgHandled(FALSE); |
| } |
| |
| void NativeWidgetWin::OnFinalMessage(HWND window) { |
| delete this; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidgetWin, WindowImpl overrides: |
| |
| HICON NativeWidgetWin::GetDefaultWindowIcon() const { |
| return NULL; |
| } |
| |
| LRESULT NativeWidgetWin::OnWndProc(UINT message, WPARAM w_param, |
| LPARAM l_param) { |
| LRESULT result = 0; |
| |
| // Otherwise we handle everything else. |
| if (!ProcessWindowMessage(hwnd(), message, w_param, l_param, result)) |
| result = DefWindowProc(hwnd(), message, w_param, l_param); |
| if (message == WM_NCDESTROY) { |
| MessageLoopForUI::current()->RemoveObserver(this); |
| OnFinalMessage(hwnd()); |
| } |
| return result; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidgetWin, private: |
| |
| void NativeWidgetWin::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 NativeWidgetWin::ProcessMouseRange(UINT message, WPARAM w_param, |
| LPARAM l_param, bool non_client) { |
| MSG msg; |
| MakeMSG(&msg, message, w_param, l_param); |
| if (message == WM_MOUSEWHEEL) { |
| // Reroute the mouse-wheel to the window under the mouse pointer if |
| // applicable. |
| // TODO(beng): |
| //if (views::RerouteMouseWheel(hwnd(), w_param, l_param)) |
| // return 0; |
| //return listener_->OnMouseWheelEvent(MouseWheelEvent(msg)); |
| return 0; |
| } |
| // 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(non_client ? TME_NONCLIENT | TME_LEAVE : TME_LEAVE); |
| //return listener_->OnMouseEvent(MouseEvent(msg)); |
| return 0; |
| } |
| |
| void NativeWidgetWin::MakeMSG(MSG* msg, UINT message, WPARAM w_param, |
| LPARAM l_param) const { |
| msg->hwnd = hwnd(); |
| msg->message = message; |
| msg->wParam = w_param; |
| msg->lParam = l_param; |
| msg->time = 0; |
| msg->pt.x = msg->pt.y = 0; |
| } |
| |
| void NativeWidgetWin::CloseNow() { |
| DestroyWindow(hwnd()); |
| } |
| |
| bool NativeWidgetWin::IsLayeredWindow() const { |
| return !!(window_ex_style() & WS_EX_LAYERED); |
| } |
| |
| } // namespace internal |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidget, public: |
| |
| // static |
| NativeWidget* NativeWidget::CreateNativeWidget( |
| internal::NativeWidgetListener* listener) { |
| return new internal::NativeWidgetWin(listener); |
| } |
| |
| // static |
| NativeWidget* NativeWidget::GetNativeWidgetForNativeView( |
| gfx::NativeView native_view) { |
| if (!ui::WindowImpl::IsWindowImpl(native_view)) |
| return NULL; |
| return reinterpret_cast<internal::NativeWidgetWin*>( |
| ui::ViewProp::GetValue(native_view, internal::kNativeWidgetKey)); |
| } |
| |
| // static |
| NativeWidget* NativeWidget::GetNativeWidgetForNativeWindow( |
| gfx::NativeWindow native_window) { |
| return GetNativeWidgetForNativeView(native_window); |
| } |
| |
| // static |
| NativeWidget* NativeWidget::GetTopLevelNativeWidget( |
| gfx::NativeView native_view) { |
| // First, check if the top-level window is a Widget. |
| HWND root = ::GetAncestor(native_view, GA_ROOT); |
| if (!root) |
| return NULL; |
| |
| NativeWidget* widget = GetNativeWidgetForNativeView(root); |
| if (widget) |
| return widget; |
| |
| // Second, try to locate the last Widget window in the parent hierarchy. |
| HWND parent_hwnd = native_view; |
| NativeWidget* parent_widget; |
| do { |
| parent_widget = GetNativeWidgetForNativeView(parent_hwnd); |
| if (parent_widget) { |
| widget = parent_widget; |
| parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT); |
| } |
| } while (parent_hwnd != NULL && parent_widget != NULL); |
| |
| return widget; |
| } |
| |
| } // namespace views |