blob: 5fc87214edac04eeb1f202de099ac115364e227d [file] [log] [blame]
// 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