| // 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 |