// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/views/widget/native_widget_win.h" #include <dwmapi.h> #include <shellapi.h> #include <algorithm> #include "base/bind.h" #include "base/strings/string_util.h" #include "base/win/scoped_gdi_object.h" #include "base/win/win_util.h" #include "base/win/windows_version.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drag_source_win.h" #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/dragdrop/os_exchange_data_provider_win.h" #include "ui/base/ime/input_method_factory.h" #include "ui/base/l10n/l10n_util_win.h" #include "ui/base/theme_provider.h" #include "ui/base/view_prop.h" #include "ui/base/win/mouse_wheel_util.h" #include "ui/base/win/shell.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_code_conversion_win.h" #include "ui/gfx/canvas.h" #include "ui/gfx/canvas_skia_paint.h" #include "ui/gfx/path.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/screen.h" #include "ui/gfx/size_conversions.h" #include "ui/gfx/win/dpi.h" #include "ui/gfx/win/hwnd_util.h" #include "ui/native_theme/native_theme.h" #include "ui/views/controls/native_control_win.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/drag_utils.h" #include "ui/views/focus/accelerator_handler.h" #include "ui/views/focus/view_storage.h" #include "ui/views/focus/widget_focus_manager.h" #include "ui/views/ime/input_method_bridge.h" #include "ui/views/widget/aero_tooltip_manager.h" #include "ui/views/widget/drop_target_win.h" #include "ui/views/widget/monitor_win.h" #include "ui/views/widget/native_widget_delegate.h" #include "ui/views/widget/root_view.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_hwnd_utils.h" #include "ui/views/win/fullscreen_handler.h" #include "ui/views/win/hwnd_message_handler.h" #include "ui/views/window/native_frame_view.h" #pragma comment(lib, "dwmapi.lib") using ui::ViewProp; namespace views { namespace { // Enumeration callback for NativeWidget::GetAllChildWidgets() and // NativeWidget::GetAllOwnedWidgets. Adds any HWNDs that correspond to // Widgets to a set. BOOL CALLBACK EnumerateNativeWidgets(HWND hwnd, LPARAM l_param) { Widget* widget = Widget::GetWidgetForNativeView(hwnd); if (widget) { Widget::Widgets* widgets = reinterpret_cast<Widget::Widgets*>(l_param); widgets->insert(widget); } return TRUE; } // Links the HWND to its NativeWidget. const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__"; const int kDragFrameWindowAlpha = 200; } // namespace //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, public: NativeWidgetWin::NativeWidgetWin(internal::NativeWidgetDelegate* delegate) : delegate_(delegate), ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET), drag_frame_saved_window_style_(0), drag_frame_saved_window_ex_style_(0), has_non_client_view_(false), message_handler_(new HWNDMessageHandler(this)) { } NativeWidgetWin::~NativeWidgetWin() { if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) delete delegate_; else CloseNow(); message_handler_.reset(); } // static gfx::Font NativeWidgetWin::GetWindowTitleFont() { NONCLIENTMETRICS ncm; base::win::GetNonClientMetrics(&ncm); l10n_util::AdjustUIFont(&(ncm.lfCaptionFont)); base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont))); return gfx::Font(caption_font); } void NativeWidgetWin::Show(int show_state) { message_handler_->Show(show_state); } //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, NativeWidget implementation: void NativeWidgetWin::InitNativeWidget(const Widget::InitParams& params) { gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(params.bounds); Widget::InitParams params_in_pixel(params); params_in_pixel.bounds = pixel_bounds; SetInitParams(params_in_pixel); message_handler_->Init(params.parent, pixel_bounds); } NonClientFrameView* NativeWidgetWin::CreateNonClientFrameView() { return GetWidget()->ShouldUseNativeFrame() ? new NativeFrameView(GetWidget()) : NULL; } bool NativeWidgetWin::ShouldUseNativeFrame() const { return ui::win::IsAeroGlassEnabled(); } void NativeWidgetWin::FrameTypeChanged() { message_handler_->FrameTypeChanged(); } Widget* NativeWidgetWin::GetWidget() { return delegate_->AsWidget(); } const Widget* NativeWidgetWin::GetWidget() const { return delegate_->AsWidget(); } gfx::NativeView NativeWidgetWin::GetNativeView() const { return message_handler_->hwnd(); } gfx::NativeWindow NativeWidgetWin::GetNativeWindow() const { return message_handler_->hwnd(); } Widget* NativeWidgetWin::GetTopLevelWidget() { NativeWidgetPrivate* native_widget = GetTopLevelNativeWidget(GetNativeView()); return native_widget ? native_widget->GetWidget() : NULL; } const ui::Compositor* NativeWidgetWin::GetCompositor() const { return NULL; } ui::Compositor* NativeWidgetWin::GetCompositor() { return NULL; } ui::Layer* NativeWidgetWin::GetLayer() { return NULL; } void NativeWidgetWin::ReorderNativeViews() { } void NativeWidgetWin::ViewRemoved(View* view) { if (drop_target_.get()) drop_target_->ResetTargetViewIfEquals(view); } 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 ViewProp(GetNativeView(), name, value)); } void* NativeWidgetWin::GetNativeWindowProperty(const char* name) const { return ViewProp::GetValue(GetNativeView(), name); } TooltipManager* NativeWidgetWin::GetTooltipManager() const { return tooltip_manager_.get(); } void NativeWidgetWin::SetCapture() { message_handler_->SetCapture(); } void NativeWidgetWin::ReleaseCapture() { message_handler_->ReleaseCapture(); } bool NativeWidgetWin::HasCapture() const { return message_handler_->HasCapture(); } InputMethod* NativeWidgetWin::CreateInputMethod() { return new InputMethodBridge(GetMessageHandler(), ui::GetSharedInputMethod(), true); } internal::InputMethodDelegate* NativeWidgetWin::GetInputMethodDelegate() { return message_handler_.get(); } void NativeWidgetWin::CenterWindow(const gfx::Size& size) { gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size); message_handler_->CenterWindow(size_in_pixels); } void NativeWidgetWin::GetWindowPlacement( gfx::Rect* bounds, ui::WindowShowState* show_state) const { message_handler_->GetWindowPlacement(bounds, show_state); *bounds = gfx::win::ScreenToDIPRect(*bounds); } bool NativeWidgetWin::SetWindowTitle(const string16& title) { return message_handler_->SetTitle(title); } void NativeWidgetWin::SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { message_handler_->SetWindowIcons(window_icon, app_icon); } void NativeWidgetWin::InitModalType(ui::ModalType modal_type) { message_handler_->InitModalType(modal_type); } gfx::Rect NativeWidgetWin::GetWindowBoundsInScreen() const { gfx::Rect bounds_in_pixels = message_handler_->GetWindowBoundsInScreen(); return gfx::win::ScreenToDIPRect(bounds_in_pixels); } gfx::Rect NativeWidgetWin::GetClientAreaBoundsInScreen() const { gfx::Rect bounds_in_pixels = message_handler_->GetClientAreaBoundsInScreen(); return gfx::win::ScreenToDIPRect(bounds_in_pixels); } gfx::Rect NativeWidgetWin::GetRestoredBounds() const { gfx::Rect bounds_in_pixels = message_handler_->GetRestoredBounds(); return gfx::win::ScreenToDIPRect(bounds_in_pixels); } void NativeWidgetWin::SetBounds(const gfx::Rect& bounds) { float scale = gfx::win::GetDeviceScaleFactor(); gfx::Rect bounds_in_pixels( gfx::ToCeiledPoint(gfx::ScalePoint(bounds.origin(), scale)), gfx::ToFlooredSize(gfx::ScaleSize(bounds.size(), scale))); message_handler_->SetBounds(bounds_in_pixels); } void NativeWidgetWin::SetSize(const gfx::Size& size) { message_handler_->SetSize(size); } void NativeWidgetWin::StackAbove(gfx::NativeView native_view) { message_handler_->StackAbove(native_view); } void NativeWidgetWin::StackAtTop() { message_handler_->StackAtTop(); } void NativeWidgetWin::StackBelow(gfx::NativeView native_view) { NOTIMPLEMENTED(); } void NativeWidgetWin::SetShape(gfx::NativeRegion region) { message_handler_->SetRegion(region); } void NativeWidgetWin::Close() { message_handler_->Close(); } void NativeWidgetWin::CloseNow() { message_handler_->CloseNow(); } void NativeWidgetWin::Show() { message_handler_->Show(); } void NativeWidgetWin::Hide() { message_handler_->Hide(); } void NativeWidgetWin::ShowMaximizedWithBounds( const gfx::Rect& restored_bounds) { gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(restored_bounds); message_handler_->ShowMaximizedWithBounds(pixel_bounds); } void NativeWidgetWin::ShowWithWindowState(ui::WindowShowState show_state) { message_handler_->ShowWindowWithState(show_state); } bool NativeWidgetWin::IsVisible() const { return message_handler_->IsVisible(); } void NativeWidgetWin::Activate() { message_handler_->Activate(); } void NativeWidgetWin::Deactivate() { message_handler_->Deactivate(); } bool NativeWidgetWin::IsActive() const { return message_handler_->IsActive(); } void NativeWidgetWin::SetAlwaysOnTop(bool on_top) { message_handler_->SetAlwaysOnTop(on_top); } bool NativeWidgetWin::IsAlwaysOnTop() const { return message_handler_->IsAlwaysOnTop(); } void NativeWidgetWin::Maximize() { message_handler_->Maximize(); } void NativeWidgetWin::Minimize() { message_handler_->Minimize(); } bool NativeWidgetWin::IsMaximized() const { return message_handler_->IsMaximized(); } bool NativeWidgetWin::IsMinimized() const { return message_handler_->IsMinimized(); } void NativeWidgetWin::Restore() { message_handler_->Restore(); } void NativeWidgetWin::SetFullscreen(bool fullscreen) { message_handler_->fullscreen_handler()->SetFullscreen(fullscreen); } void NativeWidgetWin::SetMetroSnapFullscreen(bool metro_snap) { message_handler_->fullscreen_handler()->SetMetroSnap(metro_snap); } bool NativeWidgetWin::IsFullscreen() const { return message_handler_->fullscreen_handler()->fullscreen(); } bool NativeWidgetWin::IsInMetroSnapMode() const { return message_handler_->fullscreen_handler()->metro_snap(); } void NativeWidgetWin::SetCanUpdateLayeredWindow(bool can_update) { message_handler_->set_can_update_layered_window(can_update); } void NativeWidgetWin::SetOpacity(unsigned char opacity) { message_handler_->SetOpacity(static_cast<BYTE>(opacity)); GetWidget()->GetRootView()->SchedulePaint(); } void NativeWidgetWin::SetUseDragFrame(bool use_drag_frame) { if (use_drag_frame) { // Make the frame slightly transparent during the drag operation. drag_frame_saved_window_style_ = GetWindowLong(GetNativeView(), GWL_STYLE); drag_frame_saved_window_ex_style_ = GetWindowLong(GetNativeView(), GWL_EXSTYLE); SetWindowLong(GetNativeView(), GWL_EXSTYLE, drag_frame_saved_window_ex_style_ | WS_EX_LAYERED); // Remove the captions tyle so the window doesn't have window controls for a // more "transparent" look. SetWindowLong(GetNativeView(), GWL_STYLE, drag_frame_saved_window_style_ & ~WS_CAPTION); SetLayeredWindowAttributes(GetNativeView(), RGB(0xFF, 0xFF, 0xFF), kDragFrameWindowAlpha, LWA_ALPHA); } else { SetWindowLong(GetNativeView(), GWL_STYLE, drag_frame_saved_window_style_); SetWindowLong(GetNativeView(), GWL_EXSTYLE, drag_frame_saved_window_ex_style_); } } void NativeWidgetWin::FlashFrame(bool flash) { message_handler_->FlashFrame(flash); } void NativeWidgetWin::RunShellDrag(View* view, const ui::OSExchangeData& data, const gfx::Point& location, int operation, ui::DragDropTypes::DragEventSource source) { views::RunShellDrag(NULL, data, location, operation, source); } void NativeWidgetWin::SchedulePaintInRect(const gfx::Rect& rect) { gfx::Rect pixel_rect = gfx::win::DIPToScreenRect(rect); message_handler_->SchedulePaintInRect(pixel_rect); } void NativeWidgetWin::SetCursor(gfx::NativeCursor cursor) { message_handler_->SetCursor(cursor); } bool NativeWidgetWin::IsMouseEventsEnabled() const { return true; } void NativeWidgetWin::ClearNativeFocus() { message_handler_->ClearNativeFocus(); } gfx::Rect NativeWidgetWin::GetWorkAreaBoundsInScreen() const { return gfx::win::ScreenToDIPRect( gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow( GetNativeView()).work_area()); } Widget::MoveLoopResult NativeWidgetWin::RunMoveLoop( const gfx::Vector2d& drag_offset, Widget::MoveLoopSource source, Widget::MoveLoopEscapeBehavior escape_behavior) { const bool hide_on_escape = escape_behavior == Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE; return message_handler_->RunMoveLoop(drag_offset, hide_on_escape) ? Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED; } void NativeWidgetWin::EndMoveLoop() { message_handler_->EndMoveLoop(); } void NativeWidgetWin::SetVisibilityChangedAnimationsEnabled(bool value) { message_handler_->SetVisibilityChangedAnimationsEnabled(value); } ui::NativeTheme* NativeWidgetWin::GetNativeTheme() const { return ui::NativeTheme::instance(); } void NativeWidgetWin::OnRootViewLayout() const { } //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, NativeWidget implementation: ui::EventHandler* NativeWidgetWin::GetEventHandler() { NOTIMPLEMENTED(); return NULL; } //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, protected: void NativeWidgetWin::OnFinalMessage(HWND window) { // We don't destroy props in WM_DESTROY as we may still get messages after // WM_DESTROY that assume the properties are still valid (such as WM_CLOSE). props_.clear(); delegate_->OnNativeWidgetDestroyed(); if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) delete this; } //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, protected: HWNDMessageHandler* NativeWidgetWin::GetMessageHandler() { return message_handler_.get(); } //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, HWNDMessageHandlerDelegate implementation: bool NativeWidgetWin::IsWidgetWindow() const { // We don't NULL check GetWidget()->non_client_view() here because this // function can be called before the widget is fully constructed. return has_non_client_view_; } bool NativeWidgetWin::IsUsingCustomFrame() const { return !GetWidget()->ShouldUseNativeFrame(); } void NativeWidgetWin::SchedulePaint() { GetWidget()->GetRootView()->SchedulePaint(); } void NativeWidgetWin::EnableInactiveRendering() { delegate_->EnableInactiveRendering(); } bool NativeWidgetWin::IsInactiveRenderingDisabled() { return delegate_->IsInactiveRenderingDisabled(); } bool NativeWidgetWin::CanResize() const { return GetWidget()->widget_delegate()->CanResize(); } bool NativeWidgetWin::CanMaximize() const { return GetWidget()->widget_delegate()->CanMaximize(); } bool NativeWidgetWin::CanActivate() const { return delegate_->CanActivate(); } bool NativeWidgetWin::WidgetSizeIsClientSize() const { const Widget* widget = GetWidget()->GetTopLevelWidget(); return IsZoomed(GetNativeView()) || (widget && widget->ShouldUseNativeFrame()); } bool NativeWidgetWin::CanSaveFocus() const { return GetWidget()->is_top_level(); } void NativeWidgetWin::SaveFocusOnDeactivate() { GetWidget()->GetFocusManager()->StoreFocusedView(true); } void NativeWidgetWin::RestoreFocusOnActivate() { // Mysteriously, this only appears to be needed support restoration of focus // to a child hwnd when restoring its top level window from the minimized // state. If we don't do this, then ::SetFocus() to that child HWND returns // ERROR_INVALID_PARAMETER, despite both HWNDs being of the same thread. // See http://crbug.com/125976 and // chrome/browser/ui/views/native_widget_win_interactive_uitest.cc . { // Since this is a synthetic reset, we don't need to tell anyone about it. AutoNativeNotificationDisabler disabler; GetWidget()->GetFocusManager()->ClearFocus(); } RestoreFocusOnEnable(); } void NativeWidgetWin::RestoreFocusOnEnable() { GetWidget()->GetFocusManager()->RestoreFocusedView(); } bool NativeWidgetWin::IsModal() const { return delegate_->IsModal(); } int NativeWidgetWin::GetInitialShowState() const { return SW_SHOWNORMAL; } bool NativeWidgetWin::WillProcessWorkAreaChange() const { return GetWidget()->widget_delegate()->WillProcessWorkAreaChange(); } int NativeWidgetWin::GetNonClientComponent(const gfx::Point& point) const { gfx::Point point_in_dip = gfx::win::ScreenToDIPPoint(point); return delegate_->GetNonClientComponent(point_in_dip); } void NativeWidgetWin::GetWindowMask(const gfx::Size& size, gfx::Path* path) { if (GetWidget()->non_client_view()) GetWidget()->non_client_view()->GetWindowMask(size, path); } bool NativeWidgetWin::GetClientAreaInsets(gfx::Insets* insets) const { return false; } void NativeWidgetWin::GetMinMaxSize(gfx::Size* min_size, gfx::Size* max_size) const { *min_size = gfx::win::ScreenToDIPSize(delegate_->GetMinimumSize()); *max_size = gfx::win::ScreenToDIPSize(delegate_->GetMaximumSize()); } gfx::Size NativeWidgetWin::GetRootViewSize() const { gfx::Size pixel_size = GetWidget()->GetRootView()->size(); return gfx::win::ScreenToDIPSize(pixel_size); } void NativeWidgetWin::ResetWindowControls() { GetWidget()->non_client_view()->ResetWindowControls(); } void NativeWidgetWin::PaintLayeredWindow(gfx::Canvas* canvas) { GetWidget()->GetRootView()->Paint(canvas); } InputMethod* NativeWidgetWin::GetInputMethod() { return GetWidget()->GetInputMethodDirect(); } gfx::NativeViewAccessible NativeWidgetWin::GetNativeViewAccessible() { return GetWidget()->GetRootView()->GetNativeViewAccessible(); } bool NativeWidgetWin::ShouldHandleSystemCommands() const { return GetWidget()->widget_delegate()->ShouldHandleSystemCommands(); } void NativeWidgetWin::HandleAppDeactivated() { if (IsInactiveRenderingDisabled()) { delegate_->EnableInactiveRendering(); } else { // TODO(pkotwicz): Remove need for SchedulePaint(). crbug.com/165841 View* non_client_view = GetWidget()->non_client_view(); if (non_client_view) non_client_view->SchedulePaint(); } } void NativeWidgetWin::HandleActivationChanged(bool active) { delegate_->OnNativeWidgetActivationChanged(active); } bool NativeWidgetWin::HandleAppCommand(short command) { // We treat APPCOMMAND ids as an extension of our command namespace, and just // let the delegate figure out what to do... return GetWidget()->widget_delegate() && GetWidget()->widget_delegate()->ExecuteWindowsCommand(command); } void NativeWidgetWin::HandleCancelMode() { } void NativeWidgetWin::HandleCaptureLost() { delegate_->OnMouseCaptureLost(); } void NativeWidgetWin::HandleClose() { GetWidget()->Close(); } bool NativeWidgetWin::HandleCommand(int command) { return GetWidget()->widget_delegate()->ExecuteWindowsCommand(command); } void NativeWidgetWin::HandleAccelerator(const ui::Accelerator& accelerator) { GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator); } void NativeWidgetWin::HandleCreate() { // TODO(beng): much of this could/should maybe move to HWNDMessageHandler. SetNativeWindowProperty(kNativeWidgetKey, this); CHECK_EQ(this, GetNativeWidgetForNativeView(GetNativeView())); props_.push_back(ui::SetWindowSupportsRerouteMouseWheel(GetNativeView())); drop_target_ = new DropTargetWin( static_cast<internal::RootView*>(GetWidget()->GetRootView())); // 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. Widget* widget = GetWidget()->GetTopLevelWidget(); if (widget && widget->ShouldUseNativeFrame()) { tooltip_manager_.reset(new AeroTooltipManager(GetWidget())); } else { tooltip_manager_.reset(new TooltipManagerWin(GetWidget())); } if (!tooltip_manager_->Init()) { // There was a problem creating the TooltipManager. Common error is 127. // See 82193 for details. LOG_GETLASTERROR(WARNING) << "tooltip creation failed, disabling tooltips"; tooltip_manager_.reset(); } delegate_->OnNativeWidgetCreated(true); } void NativeWidgetWin::HandleDestroying() { delegate_->OnNativeWidgetDestroying(); if (drop_target_.get()) { RevokeDragDrop(GetNativeView()); drop_target_ = NULL; } } void NativeWidgetWin::HandleDestroyed() { OnFinalMessage(GetNativeView()); } bool NativeWidgetWin::HandleInitialFocus() { return GetWidget()->SetInitialFocus(); } void NativeWidgetWin::HandleDisplayChange() { GetWidget()->widget_delegate()->OnDisplayChanged(); } void NativeWidgetWin::HandleBeginWMSizeMove() { delegate_->OnNativeWidgetBeginUserBoundsChange(); } void NativeWidgetWin::HandleEndWMSizeMove() { delegate_->OnNativeWidgetEndUserBoundsChange(); } void NativeWidgetWin::HandleMove() { delegate_->OnNativeWidgetMove(); } void NativeWidgetWin::HandleWorkAreaChanged() { GetWidget()->widget_delegate()->OnWorkAreaChanged(); } void NativeWidgetWin::HandleVisibilityChanging(bool visible) { delegate_->OnNativeWidgetVisibilityChanging(visible); } void NativeWidgetWin::HandleVisibilityChanged(bool visible) { delegate_->OnNativeWidgetVisibilityChanged(visible); } void NativeWidgetWin::HandleClientSizeChanged(const gfx::Size& new_size) { gfx::Size size_in_dip = gfx::win::ScreenToDIPSize(new_size); delegate_->OnNativeWidgetSizeChanged(size_in_dip); } void NativeWidgetWin::HandleFrameChanged() { // Replace the frame and layout the contents. GetWidget()->non_client_view()->UpdateFrame(); } void NativeWidgetWin::HandleNativeFocus(HWND last_focused_window) { delegate_->OnNativeFocus(last_focused_window); InputMethod* input_method = GetInputMethod(); if (input_method) input_method->OnFocus(); } void NativeWidgetWin::HandleNativeBlur(HWND focused_window) { delegate_->OnNativeBlur(focused_window); InputMethod* input_method = GetInputMethod(); if (input_method) input_method->OnBlur(); } bool NativeWidgetWin::HandleMouseEvent(const ui::MouseEvent& event) { static gfx::Transform scale_transform( 1/gfx::win::GetDeviceScaleFactor(), 0.0, 0.0, 1/gfx::win::GetDeviceScaleFactor(), 0.0, 0.0); if (event.IsMouseWheelEvent()) { ui::MouseWheelEvent dpi_event( static_cast<const ui::MouseWheelEvent&>(event)); dpi_event.UpdateForRootTransform(scale_transform); delegate_->OnMouseEvent(&dpi_event); return dpi_event.handled(); } else if (event.IsMouseEvent()) { ui::MouseEvent dpi_event(event); if (!(dpi_event.flags() & ui::EF_IS_NON_CLIENT)) dpi_event.UpdateForRootTransform(scale_transform); delegate_->OnMouseEvent(&dpi_event); return dpi_event.handled(); } NOTREACHED(); return false; } bool NativeWidgetWin::HandleKeyEvent(const ui::KeyEvent& event) { delegate_->OnKeyEvent(const_cast<ui::KeyEvent*>(&event)); return event.handled(); } bool NativeWidgetWin::HandleUntranslatedKeyEvent(const ui::KeyEvent& event) { InputMethod* input_method = GetInputMethod(); if (input_method) input_method->DispatchKeyEvent(event); return !!input_method; } void NativeWidgetWin::HandleTouchEvent(const ui::TouchEvent& event) { NOTREACHED() << "Touch events are not supported"; } bool NativeWidgetWin::HandleIMEMessage(UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) { InputMethod* input_method = GetInputMethod(); if (!input_method || input_method->IsMock()) { *result = 0; return false; } MSG msg = {}; msg.hwnd = message_handler_->hwnd(); msg.message = message; msg.wParam = w_param; msg.lParam = l_param; return input_method->OnUntranslatedIMEMessage(msg, result); } void NativeWidgetWin::HandleInputLanguageChange(DWORD character_set, HKL input_language_id) { InputMethod* input_method = GetInputMethod(); if (input_method && !input_method->IsMock()) { input_method->OnInputLocaleChanged(); } } bool NativeWidgetWin::HandlePaintAccelerated(const gfx::Rect& invalid_rect) { gfx::Rect dpi_rect = gfx::win::ScreenToDIPRect(invalid_rect); return delegate_->OnNativeWidgetPaintAccelerated(dpi_rect); } void NativeWidgetWin::HandlePaint(gfx::Canvas* canvas) { delegate_->OnNativeWidgetPaint(canvas); } bool NativeWidgetWin::HandleTooltipNotify(int w_param, NMHDR* l_param, LRESULT* l_result) { // 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; *l_result = tooltip_manager_->OnNotify(w_param, l_param, &handled); return handled; } return false; } void NativeWidgetWin::HandleTooltipMouseMove(UINT message, WPARAM w_param, LPARAM l_param) { if (tooltip_manager_.get()) tooltip_manager_->OnMouse(message, w_param, l_param); } bool NativeWidgetWin::PreHandleMSG(UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) { return false; } void NativeWidgetWin::PostHandleMSG(UINT message, WPARAM w_param, LPARAM l_param) { } bool NativeWidgetWin::HandleScrollEvent(const ui::ScrollEvent& event) { delegate_->OnScrollEvent(const_cast<ui::ScrollEvent*>(&event)); return event.handled(); } //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, private: void NativeWidgetWin::SetInitParams(const Widget::InitParams& params) { // Set non-style attributes. ownership_ = params.ownership; ConfigureWindowStyles(message_handler_.get(), params, GetWidget()->widget_delegate(), delegate_); has_non_client_view_ = Widget::RequiresNonClientView(params.type); message_handler_->set_remove_standard_frame(params.remove_standard_frame); message_handler_->set_use_system_default_icon(params.use_system_default_icon); } //////////////////////////////////////////////////////////////////////////////// // Widget, public: // static void Widget::NotifyLocaleChanged() { NOTIMPLEMENTED(); } namespace { BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) { Widget* widget = Widget::GetWidgetForNativeView(hwnd); if (widget && widget->is_secondary_widget()) widget->Close(); return TRUE; } } // namespace // static void Widget::CloseAllSecondaryWidgets() { EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, 0); } bool Widget::ConvertRect(const Widget* source, const Widget* target, gfx::Rect* rect) { DCHECK(source); DCHECK(target); DCHECK(rect); HWND source_hwnd = source->GetNativeView(); HWND target_hwnd = target->GetNativeView(); if (source_hwnd == target_hwnd) return true; RECT win_rect = gfx::win::DIPToScreenRect(*rect).ToRECT(); if (::MapWindowPoints(source_hwnd, target_hwnd, reinterpret_cast<LPPOINT>(&win_rect), sizeof(RECT)/sizeof(POINT))) { *rect = gfx::win::ScreenToDIPRect(gfx::Rect(win_rect)); return true; } return false; } namespace internal { //////////////////////////////////////////////////////////////////////////////// // internal::NativeWidgetPrivate, public: // static NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget( internal::NativeWidgetDelegate* delegate) { return new NativeWidgetWin(delegate); } // static NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView( gfx::NativeView native_view) { return reinterpret_cast<NativeWidgetWin*>( ViewProp::GetValue(native_view, kNativeWidgetKey)); } // static NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow( gfx::NativeWindow native_window) { return GetNativeWidgetForNativeView(native_window); } // static NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget( gfx::NativeView native_view) { if (!native_view) return NULL; // First, check if the top-level window is a Widget. HWND root = ::GetAncestor(native_view, GA_ROOT); if (!root) return NULL; NativeWidgetPrivate* widget = GetNativeWidgetForNativeView(root); if (widget) return widget; // Second, try to locate the last Widget window in the parent hierarchy. HWND parent_hwnd = native_view; // If we fail to find the native widget pointer for the root then it probably // means that the root belongs to a different process in which case we walk up // the native view chain looking for a parent window which corresponds to a // valid native widget. We only do this if we fail to find the native widget // for the current native view which means it is being destroyed. if (!widget && !GetNativeWidgetForNativeView(native_view)) { parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT); if (!parent_hwnd) return NULL; } NativeWidgetPrivate* 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; } // static void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view, Widget::Widgets* children) { if (!native_view) return; Widget* widget = Widget::GetWidgetForNativeView(native_view); if (widget) children->insert(widget); EnumChildWindows(native_view, EnumerateNativeWidgets, reinterpret_cast<LPARAM>(children)); } // static void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view, Widget::Widgets* owned) { if (!native_view) return; Widget::Widgets all; EnumWindows(EnumerateNativeWidgets, reinterpret_cast<LPARAM>(&all)); for (Widget::Widgets::const_iterator iter = all.begin(); iter != all.end(); ++iter) { if (native_view == GetWindow((*iter)->GetNativeView(), GW_OWNER)) owned->insert(*iter); } } // static void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view, gfx::NativeView new_parent) { if (!native_view) return; HWND previous_parent = ::GetParent(native_view); if (previous_parent == new_parent) return; Widget::Widgets widgets; GetAllChildWidgets(native_view, &widgets); // First notify all the widgets that they are being disassociated // from their previous parent. for (Widget::Widgets::iterator it = widgets.begin(); it != widgets.end(); ++it) { (*it)->NotifyNativeViewHierarchyWillChange(); } ::SetParent(native_view, new_parent); // And now, notify them that they have a brand new parent. for (Widget::Widgets::iterator it = widgets.begin(); it != widgets.end(); ++it) { (*it)->NotifyNativeViewHierarchyChanged(); } } // static bool NativeWidgetPrivate::IsMouseButtonDown() { return (GetKeyState(VK_LBUTTON) & 0x80) || (GetKeyState(VK_RBUTTON) & 0x80) || (GetKeyState(VK_MBUTTON) & 0x80) || (GetKeyState(VK_XBUTTON1) & 0x80) || (GetKeyState(VK_XBUTTON2) & 0x80); } // static bool NativeWidgetPrivate::IsTouchDown() { // This currently isn't necessary because we're not generating touch events on // windows. When we do, this will need to be updated. return false; } } // namespace internal } // namespace views