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