| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "views/widget/native_widget_views.h" |
| |
| #include "ui/gfx/compositor/compositor.h" |
| #include "views/desktop/desktop_window_view.h" |
| #include "views/view.h" |
| #include "views/views_delegate.h" |
| #include "views/widget/native_widget_view.h" |
| #include "views/widget/root_view.h" |
| #include "views/widget/window_manager.h" |
| |
| #if defined(HAVE_IBUS) |
| #include "views/ime/input_method_ibus.h" |
| #else |
| #include "views/ime/mock_input_method.h" |
| #endif |
| |
| namespace views { |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidgetViews, public: |
| |
| NativeWidgetViews::NativeWidgetViews(internal::NativeWidgetDelegate* delegate) |
| : delegate_(delegate), |
| view_(NULL), |
| active_(false), |
| minimized_(false), |
| ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)), |
| hosting_widget_(NULL), |
| ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET), |
| delete_native_view_(true) { |
| } |
| |
| NativeWidgetViews::~NativeWidgetViews() { |
| delegate_->OnNativeWidgetDestroying(); |
| |
| if (view_ && delete_native_view_) { |
| // We must prevent the NativeWidgetView from attempting to delete us. |
| view_->set_delete_native_widget(false); |
| delete view_; |
| } |
| |
| delegate_->OnNativeWidgetDestroyed(); |
| if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) |
| delete delegate_; |
| } |
| |
| View* NativeWidgetViews::GetView() { |
| return view_; |
| } |
| |
| const View* NativeWidgetViews::GetView() const { |
| return view_; |
| } |
| |
| void NativeWidgetViews::OnActivate(bool active) { |
| // TODO(oshima): find out if we should check toplevel here. |
| if (active_ == active) |
| return; |
| active_ = active; |
| delegate_->OnNativeWidgetActivationChanged(active); |
| |
| // TODO(oshima): Focus change should be separated from window activation. |
| // This will be fixed when we have WM API. |
| Widget* widget = GetWidget(); |
| if (widget->is_top_level()) { |
| InputMethod* input_method = widget->GetInputMethodDirect(); |
| if (active) { |
| input_method->OnFocus(); |
| // See description of got_initial_focus_in_ for details on this. |
| widget->GetFocusManager()->RestoreFocusedView(); |
| } else { |
| input_method->OnBlur(); |
| widget->GetFocusManager()->StoreFocusedView(); |
| } |
| } |
| view_->SchedulePaint(); |
| } |
| |
| bool NativeWidgetViews::OnKeyEvent(const KeyEvent& key_event) { |
| InputMethod* input_method = GetWidget()->GetInputMethodDirect(); |
| DCHECK(input_method); |
| input_method->DispatchKeyEvent(key_event); |
| return true; |
| } |
| |
| void NativeWidgetViews::DispatchKeyEventPostIME(const KeyEvent& key) { |
| // TODO(oshima): GTK impl handles menu_key in special way. This may be |
| // necessary when running under NativeWidgetX. |
| delegate_->OnKeyEvent(key); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidgetViews, NativeWidget implementation: |
| |
| void NativeWidgetViews::InitNativeWidget(const Widget::InitParams& params) { |
| ownership_ = params.ownership; |
| View* parent_view = NULL; |
| if (params.parent_widget) { |
| hosting_widget_ = params.parent_widget; |
| parent_view = hosting_widget_->GetChildViewParent(); |
| } else { |
| parent_view = ViewsDelegate::views_delegate->GetDefaultParentView(); |
| hosting_widget_ = parent_view->GetWidget(); |
| } |
| |
| view_ = new internal::NativeWidgetView(this); |
| view_->SetBoundsRect(params.bounds); |
| view_->SetPaintToLayer(true); |
| |
| // With the default NATIVE_WIDGET_OWNS_WIDGET ownership, the |
| // deletion of either of the NativeWidgetViews or NativeWidgetView |
| // (e.g. via View hierarchy destruction) will delete the other. |
| // With WIDGET_OWNS_NATIVE_WIDGET, NativeWidgetViews should only |
| // be deleted by its Widget. |
| if (ownership_ == Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET) |
| view_->set_delete_native_widget(false); |
| |
| parent_view->AddChildView(view_); |
| |
| // TODO(beng): SetInitParams(). |
| } |
| |
| NonClientFrameView* NativeWidgetViews::CreateNonClientFrameView() { |
| return NULL; |
| } |
| |
| void NativeWidgetViews::UpdateFrameAfterFrameChange() { |
| } |
| |
| bool NativeWidgetViews::ShouldUseNativeFrame() const { |
| // NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void NativeWidgetViews::FrameTypeChanged() { |
| } |
| |
| Widget* NativeWidgetViews::GetWidget() { |
| return delegate_->AsWidget(); |
| } |
| |
| const Widget* NativeWidgetViews::GetWidget() const { |
| return delegate_->AsWidget(); |
| } |
| |
| gfx::NativeView NativeWidgetViews::GetNativeView() const { |
| return GetParentNativeWidget()->GetNativeView(); |
| } |
| |
| gfx::NativeWindow NativeWidgetViews::GetNativeWindow() const { |
| return GetParentNativeWidget()->GetNativeWindow(); |
| } |
| |
| Widget* NativeWidgetViews::GetTopLevelWidget() { |
| // This can get called when this is in the process of being destroyed, and |
| // view_ has already been unset. |
| if (!view_) |
| return GetWidget(); |
| if (view_->parent() == ViewsDelegate::views_delegate->GetDefaultParentView()) |
| return GetWidget(); |
| // During Widget destruction, this function may be called after |view_| is |
| // detached from a Widget, at which point this NativeWidget's Widget becomes |
| // the effective toplevel. |
| Widget* containing_widget = view_->GetWidget(); |
| return containing_widget ? containing_widget->GetTopLevelWidget() |
| : GetWidget(); |
| } |
| |
| const ui::Compositor* NativeWidgetViews::GetCompositor() const { |
| return hosting_widget_->GetCompositor(); |
| } |
| |
| ui::Compositor* NativeWidgetViews::GetCompositor() { |
| return hosting_widget_->GetCompositor(); |
| } |
| |
| void NativeWidgetViews::MarkLayerDirty() { |
| view_->MarkLayerDirty(); |
| } |
| |
| void NativeWidgetViews::CalculateOffsetToAncestorWithLayer(gfx::Point* offset, |
| View** ancestor) { |
| view_->CalculateOffsetToAncestorWithLayer(offset, ancestor); |
| } |
| |
| void NativeWidgetViews::ViewRemoved(View* view) { |
| internal::NativeWidgetPrivate* parent = GetParentNativeWidget(); |
| if (parent) |
| parent->ViewRemoved(view); |
| } |
| |
| void NativeWidgetViews::SetNativeWindowProperty(const char* name, void* value) { |
| if (value) |
| window_properties_[name] = value; |
| else |
| window_properties_.erase(name); |
| } |
| |
| void* NativeWidgetViews::GetNativeWindowProperty(const char* name) const { |
| std::map<const char*, void*>::const_iterator iter = |
| window_properties_.find(name); |
| return iter != window_properties_.end() ? iter->second : NULL; |
| } |
| |
| TooltipManager* NativeWidgetViews::GetTooltipManager() const { |
| const internal::NativeWidgetPrivate* parent = GetParentNativeWidget(); |
| return parent ? parent->GetTooltipManager() : NULL; |
| } |
| |
| bool NativeWidgetViews::IsScreenReaderActive() const { |
| return GetParentNativeWidget()->IsScreenReaderActive(); |
| } |
| |
| void NativeWidgetViews::SendNativeAccessibilityEvent( |
| View* view, |
| ui::AccessibilityTypes::Event event_type) { |
| return GetParentNativeWidget()->SendNativeAccessibilityEvent(view, |
| event_type); |
| } |
| |
| void NativeWidgetViews::SetMouseCapture() { |
| WindowManager::Get()->SetMouseCapture(GetWidget()); |
| } |
| |
| void NativeWidgetViews::ReleaseMouseCapture() { |
| WindowManager::Get()->ReleaseMouseCapture(GetWidget()); |
| } |
| |
| bool NativeWidgetViews::HasMouseCapture() const { |
| return WindowManager::Get()->HasMouseCapture(GetWidget()); |
| } |
| |
| InputMethod* NativeWidgetViews::CreateInputMethod() { |
| #if defined(HAVE_IBUS) |
| return new InputMethodIBus(this); |
| #else |
| return new MockInputMethod(this); |
| #endif |
| } |
| |
| void NativeWidgetViews::CenterWindow(const gfx::Size& size) { |
| const gfx::Size parent_size = GetView()->parent()->size(); |
| GetView()->SetBounds((parent_size.width() - size.width())/2, |
| (parent_size.height() - size.height())/2, |
| size.width(), size.height()); |
| } |
| |
| void NativeWidgetViews::GetWindowBoundsAndMaximizedState( |
| gfx::Rect* bounds, |
| bool* maximized) const { |
| *bounds = GetView()->bounds(); |
| *maximized = false; |
| } |
| |
| void NativeWidgetViews::SetWindowTitle(const std::wstring& title) { |
| } |
| |
| void NativeWidgetViews::SetWindowIcons(const SkBitmap& window_icon, |
| const SkBitmap& app_icon) { |
| } |
| |
| void NativeWidgetViews::SetAccessibleName(const std::wstring& name) { |
| } |
| |
| void NativeWidgetViews::SetAccessibleRole(ui::AccessibilityTypes::Role role) { |
| } |
| |
| void NativeWidgetViews::SetAccessibleState( |
| ui::AccessibilityTypes::State state) { |
| } |
| |
| void NativeWidgetViews::BecomeModal() { |
| NOTIMPLEMENTED(); |
| } |
| |
| gfx::Rect NativeWidgetViews::GetWindowScreenBounds() const { |
| if (GetWidget() == GetWidget()->GetTopLevelWidget()) |
| return view_->bounds(); |
| gfx::Point origin = view_->bounds().origin(); |
| View::ConvertPointToScreen(view_->parent(), &origin); |
| return gfx::Rect(origin.x(), origin.y(), view_->width(), view_->height()); |
| } |
| |
| gfx::Rect NativeWidgetViews::GetClientAreaScreenBounds() const { |
| return GetWindowScreenBounds(); |
| } |
| |
| gfx::Rect NativeWidgetViews::GetRestoredBounds() const { |
| return GetWindowScreenBounds(); |
| } |
| |
| void NativeWidgetViews::SetBounds(const gfx::Rect& bounds) { |
| // |bounds| are supplied in the coordinates of the parent. |
| view_->SetBoundsRect(bounds); |
| } |
| |
| void NativeWidgetViews::SetSize(const gfx::Size& size) { |
| view_->SetSize(size); |
| } |
| |
| void NativeWidgetViews::SetBoundsConstrained(const gfx::Rect& bounds, |
| Widget* other_widget) { |
| // TODO(beng): honor other_widget. |
| SetBounds(bounds); |
| } |
| |
| void NativeWidgetViews::MoveAbove(gfx::NativeView native_view) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void NativeWidgetViews::MoveToTop() { |
| view_->parent()->ReorderChildView(view_, -1); |
| } |
| |
| void NativeWidgetViews::SetShape(gfx::NativeRegion region) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void NativeWidgetViews::Close() { |
| Hide(); |
| if (close_widget_factory_.empty()) { |
| MessageLoop::current()->PostTask(FROM_HERE, |
| close_widget_factory_.NewRunnableMethod(&NativeWidgetViews::CloseNow)); |
| } |
| } |
| |
| void NativeWidgetViews::CloseNow() { |
| delete view_; |
| view_ = NULL; |
| } |
| |
| void NativeWidgetViews::EnableClose(bool enable) { |
| } |
| |
| void NativeWidgetViews::Show() { |
| view_->SetVisible(true); |
| GetWidget()->SetInitialFocus(); |
| } |
| |
| void NativeWidgetViews::Hide() { |
| view_->SetVisible(false); |
| if (HasMouseCapture()) |
| ReleaseMouseCapture(); |
| } |
| |
| void NativeWidgetViews::ShowWithState(ShowState state) { |
| Show(); |
| } |
| |
| void NativeWidgetViews::ShowMaximizedWithBounds( |
| const gfx::Rect& restored_bounds) { |
| Show(); |
| } |
| |
| bool NativeWidgetViews::IsVisible() const { |
| return view_->IsVisible(); |
| } |
| |
| void NativeWidgetViews::Activate() { |
| // Enable WidgetObserverTest.ActivationChange when this is implemented. |
| MoveToTop(); |
| OnActivate(true); |
| } |
| |
| void NativeWidgetViews::Deactivate() { |
| OnActivate(false); |
| } |
| |
| bool NativeWidgetViews::IsActive() const { |
| return active_; |
| } |
| |
| void NativeWidgetViews::SetAlwaysOnTop(bool on_top) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void NativeWidgetViews::Maximize() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void NativeWidgetViews::Minimize() { |
| gfx::Rect view_bounds = view_->bounds(); |
| gfx::Rect parent_bounds = view_->parent()->bounds(); |
| |
| restored_bounds_ = view_bounds; |
| restored_transform_ = view_->GetTransform(); |
| |
| float aspect_ratio = static_cast<float>(view_bounds.width()) / |
| static_cast<float>(view_bounds.height()); |
| int target_size = 100; |
| int target_height = target_size; |
| int target_width = static_cast<int>(aspect_ratio * target_height); |
| if (target_width > target_size) { |
| target_width = target_size; |
| target_height = static_cast<int>(target_width / aspect_ratio); |
| } |
| |
| int target_x = 20; |
| int target_y = parent_bounds.height() - target_size - 20; |
| |
| view_->SetBounds( |
| target_x, target_y, view_bounds.width(), view_bounds.height()); |
| |
| ui::Transform transform; |
| transform.SetScale((float)target_width / (float)view_bounds.width(), |
| (float)target_height / (float)view_bounds.height()); |
| view_->SetTransform(transform); |
| |
| minimized_ = true; |
| } |
| |
| bool NativeWidgetViews::IsMaximized() const { |
| // NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| bool NativeWidgetViews::IsMinimized() const { |
| return minimized_; |
| } |
| |
| void NativeWidgetViews::Restore() { |
| minimized_ = false; |
| view_->SetBoundsRect(restored_bounds_); |
| view_->SetTransform(restored_transform_); |
| } |
| |
| void NativeWidgetViews::SetFullscreen(bool fullscreen) { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool NativeWidgetViews::IsFullscreen() const { |
| // NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void NativeWidgetViews::SetOpacity(unsigned char opacity) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void NativeWidgetViews::SetUseDragFrame(bool use_drag_frame) { |
| NOTIMPLEMENTED(); |
| } |
| |
| bool NativeWidgetViews::IsAccessibleWidget() const { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void NativeWidgetViews::RunShellDrag(View* view, |
| const ui::OSExchangeData& data, |
| int operation) { |
| GetParentNativeWidget()->RunShellDrag(view, data, operation); |
| } |
| |
| void NativeWidgetViews::SchedulePaintInRect(const gfx::Rect& rect) { |
| view_->SchedulePaintInternal(rect); |
| } |
| |
| void NativeWidgetViews::SetCursor(gfx::NativeCursor cursor) { |
| view_->set_cursor(cursor); |
| GetParentNativeWidget()->SetCursor(cursor); |
| } |
| |
| void NativeWidgetViews::ClearNativeFocus() { |
| GetParentNativeWidget()->ClearNativeFocus(); |
| } |
| |
| void NativeWidgetViews::FocusNativeView(gfx::NativeView native_view) { |
| GetParentNativeWidget()->FocusNativeView(native_view); |
| } |
| |
| bool NativeWidgetViews::ConvertPointFromAncestor( |
| const Widget* ancestor, gfx::Point* point) const { |
| // This method converts the point from ancestor's coordinates to |
| // this widget's coordinate using recursion as the widget hierachy |
| // is usually shallow. |
| |
| if (ancestor == GetWidget()) |
| return true; // no conversion necessary |
| |
| const Widget* parent_widget = view_->GetWidget(); |
| if (!parent_widget) // couldn't reach the ancestor. |
| return false; |
| |
| if (parent_widget == ancestor || |
| parent_widget->ConvertPointFromAncestor(ancestor, point)) { |
| View::ConvertPointToView(parent_widget->GetRootView(), GetView(), point); |
| return true; |
| } |
| return false; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // NativeWidgetViews, private: |
| |
| internal::NativeWidgetPrivate* NativeWidgetViews::GetParentNativeWidget() { |
| Widget* containing_widget = view_ ? view_->GetWidget() : NULL; |
| return containing_widget ? static_cast<internal::NativeWidgetPrivate*>( |
| containing_widget->native_widget()) : |
| NULL; |
| } |
| |
| const internal::NativeWidgetPrivate* |
| NativeWidgetViews::GetParentNativeWidget() const { |
| const Widget* containing_widget = view_ ? view_->GetWidget() : NULL; |
| return containing_widget ? static_cast<const internal::NativeWidgetPrivate*>( |
| containing_widget->native_widget()) : |
| NULL; |
| } |
| |
| } // namespace views |