| // 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/widget.h" |
| |
| #include "base/debug/trace_event.h" |
| #include "base/logging.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "ui/base/cursor/cursor.h" |
| #include "ui/base/default_theme_provider.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/base/l10n/l10n_font_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/compositor/compositor.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/events/event.h" |
| #include "ui/gfx/image/image_skia.h" |
| #include "ui/gfx/screen.h" |
| #include "ui/views/controls/menu/menu_controller.h" |
| #include "ui/views/focus/focus_manager.h" |
| #include "ui/views/focus/focus_manager_factory.h" |
| #include "ui/views/focus/view_storage.h" |
| #include "ui/views/focus/widget_focus_manager.h" |
| #include "ui/views/ime/input_method.h" |
| #include "ui/views/views_delegate.h" |
| #include "ui/views/widget/native_widget_private.h" |
| #include "ui/views/widget/root_view.h" |
| #include "ui/views/widget/tooltip_manager.h" |
| #include "ui/views/widget/widget_delegate.h" |
| #include "ui/views/widget/widget_deletion_observer.h" |
| #include "ui/views/widget/widget_observer.h" |
| #include "ui/views/widget/widget_removals_observer.h" |
| #include "ui/views/window/custom_frame_view.h" |
| #include "ui/views/window/dialog_delegate.h" |
| |
| namespace views { |
| |
| namespace { |
| |
| // If |view| has a layer the layer is added to |layers|. Else this recurses |
| // through the children. This is used to build a list of the layers created by |
| // views that are direct children of the Widgets layer. |
| void BuildRootLayers(View* view, std::vector<ui::Layer*>* layers) { |
| if (view->layer()) { |
| layers->push_back(view->layer()); |
| } else { |
| for (int i = 0; i < view->child_count(); ++i) |
| BuildRootLayers(view->child_at(i), layers); |
| } |
| } |
| |
| // Create a native widget implementation. |
| // First, use the supplied one if non-NULL. |
| // Finally, make a default one. |
| NativeWidget* CreateNativeWidget(NativeWidget* native_widget, |
| internal::NativeWidgetDelegate* delegate) { |
| if (!native_widget) { |
| native_widget = |
| internal::NativeWidgetPrivate::CreateNativeWidget(delegate); |
| } |
| return native_widget; |
| } |
| |
| } // namespace |
| |
| // A default implementation of WidgetDelegate, used by Widget when no |
| // WidgetDelegate is supplied. |
| class DefaultWidgetDelegate : public WidgetDelegate { |
| public: |
| explicit DefaultWidgetDelegate(Widget* widget) : widget_(widget) { |
| } |
| virtual ~DefaultWidgetDelegate() {} |
| |
| // Overridden from WidgetDelegate: |
| virtual void DeleteDelegate() override { |
| delete this; |
| } |
| virtual Widget* GetWidget() override { |
| return widget_; |
| } |
| virtual const Widget* GetWidget() const override { |
| return widget_; |
| } |
| virtual bool ShouldAdvanceFocusToTopLevelWidget() const override { |
| // In most situations where a Widget is used without a delegate the Widget |
| // is used as a container, so that we want focus to advance to the top-level |
| // widget. A good example of this is the find bar. |
| return true; |
| } |
| |
| private: |
| Widget* widget_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DefaultWidgetDelegate); |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, InitParams: |
| |
| Widget::InitParams::InitParams() |
| : type(TYPE_WINDOW), |
| delegate(NULL), |
| child(false), |
| opacity(INFER_OPACITY), |
| accept_events(true), |
| activatable(ACTIVATABLE_DEFAULT), |
| keep_on_top(false), |
| visible_on_all_workspaces(false), |
| ownership(NATIVE_WIDGET_OWNS_WIDGET), |
| mirror_origin_in_rtl(false), |
| shadow_type(SHADOW_TYPE_DEFAULT), |
| remove_standard_frame(false), |
| use_system_default_icon(false), |
| show_state(ui::SHOW_STATE_DEFAULT), |
| double_buffer(false), |
| parent(NULL), |
| native_widget(NULL), |
| desktop_window_tree_host(NULL), |
| layer_type(aura::WINDOW_LAYER_TEXTURED), |
| context(NULL), |
| force_show_in_taskbar(false) { |
| } |
| |
| Widget::InitParams::InitParams(Type type) |
| : type(type), |
| delegate(NULL), |
| child(false), |
| opacity(INFER_OPACITY), |
| accept_events(true), |
| activatable(ACTIVATABLE_DEFAULT), |
| keep_on_top(type == TYPE_MENU || type == TYPE_DRAG), |
| visible_on_all_workspaces(false), |
| ownership(NATIVE_WIDGET_OWNS_WIDGET), |
| mirror_origin_in_rtl(false), |
| shadow_type(SHADOW_TYPE_DEFAULT), |
| remove_standard_frame(false), |
| use_system_default_icon(false), |
| show_state(ui::SHOW_STATE_DEFAULT), |
| double_buffer(false), |
| parent(NULL), |
| native_widget(NULL), |
| desktop_window_tree_host(NULL), |
| layer_type(aura::WINDOW_LAYER_TEXTURED), |
| context(NULL), |
| force_show_in_taskbar(false) { |
| } |
| |
| Widget::InitParams::~InitParams() { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, public: |
| |
| Widget::Widget() |
| : native_widget_(NULL), |
| widget_delegate_(NULL), |
| non_client_view_(NULL), |
| dragged_view_(NULL), |
| ownership_(InitParams::NATIVE_WIDGET_OWNS_WIDGET), |
| is_secondary_widget_(true), |
| frame_type_(FRAME_TYPE_DEFAULT), |
| disable_inactive_rendering_(false), |
| widget_closed_(false), |
| saved_show_state_(ui::SHOW_STATE_DEFAULT), |
| focus_on_creation_(true), |
| is_top_level_(false), |
| native_widget_initialized_(false), |
| native_widget_destroyed_(false), |
| ignore_capture_loss_(false), |
| last_mouse_event_was_move_(false), |
| auto_release_capture_(true), |
| root_layers_dirty_(false), |
| movement_disabled_(false), |
| observer_manager_(this) { |
| } |
| |
| Widget::~Widget() { |
| DestroyRootView(); |
| if (ownership_ == InitParams::WIDGET_OWNS_NATIVE_WIDGET) { |
| delete native_widget_; |
| } else { |
| DCHECK(native_widget_destroyed_) |
| << "Destroying a widget with a live native widget. " |
| << "Widget probably should use WIDGET_OWNS_NATIVE_WIDGET ownership."; |
| } |
| } |
| |
| // static |
| Widget* Widget::CreateWindow(WidgetDelegate* delegate) { |
| return CreateWindowWithBounds(delegate, gfx::Rect()); |
| } |
| |
| // static |
| Widget* Widget::CreateWindowWithBounds(WidgetDelegate* delegate, |
| const gfx::Rect& bounds) { |
| Widget* widget = new Widget; |
| Widget::InitParams params; |
| params.bounds = bounds; |
| params.delegate = delegate; |
| widget->Init(params); |
| return widget; |
| } |
| |
| // static |
| Widget* Widget::CreateWindowWithParent(WidgetDelegate* delegate, |
| gfx::NativeView parent) { |
| return CreateWindowWithParentAndBounds(delegate, parent, gfx::Rect()); |
| } |
| |
| // static |
| Widget* Widget::CreateWindowWithParentAndBounds(WidgetDelegate* delegate, |
| gfx::NativeView parent, |
| const gfx::Rect& bounds) { |
| Widget* widget = new Widget; |
| Widget::InitParams params; |
| params.delegate = delegate; |
| params.parent = parent; |
| params.bounds = bounds; |
| widget->Init(params); |
| return widget; |
| } |
| |
| // static |
| Widget* Widget::CreateWindowWithContext(WidgetDelegate* delegate, |
| gfx::NativeWindow context) { |
| return CreateWindowWithContextAndBounds(delegate, context, gfx::Rect()); |
| } |
| |
| // static |
| Widget* Widget::CreateWindowWithContextAndBounds(WidgetDelegate* delegate, |
| gfx::NativeWindow context, |
| const gfx::Rect& bounds) { |
| Widget* widget = new Widget; |
| Widget::InitParams params; |
| params.delegate = delegate; |
| params.context = context; |
| params.bounds = bounds; |
| widget->Init(params); |
| return widget; |
| } |
| |
| // static |
| Widget* Widget::GetWidgetForNativeView(gfx::NativeView native_view) { |
| internal::NativeWidgetPrivate* native_widget = |
| internal::NativeWidgetPrivate::GetNativeWidgetForNativeView(native_view); |
| return native_widget ? native_widget->GetWidget() : NULL; |
| } |
| |
| // static |
| Widget* Widget::GetWidgetForNativeWindow(gfx::NativeWindow native_window) { |
| internal::NativeWidgetPrivate* native_widget = |
| internal::NativeWidgetPrivate::GetNativeWidgetForNativeWindow( |
| native_window); |
| return native_widget ? native_widget->GetWidget() : NULL; |
| } |
| |
| // static |
| Widget* Widget::GetTopLevelWidgetForNativeView(gfx::NativeView native_view) { |
| internal::NativeWidgetPrivate* native_widget = |
| internal::NativeWidgetPrivate::GetTopLevelNativeWidget(native_view); |
| return native_widget ? native_widget->GetWidget() : NULL; |
| } |
| |
| |
| // static |
| void Widget::GetAllChildWidgets(gfx::NativeView native_view, |
| Widgets* children) { |
| internal::NativeWidgetPrivate::GetAllChildWidgets(native_view, children); |
| } |
| |
| // static |
| void Widget::GetAllOwnedWidgets(gfx::NativeView native_view, |
| Widgets* owned) { |
| internal::NativeWidgetPrivate::GetAllOwnedWidgets(native_view, owned); |
| } |
| |
| // static |
| void Widget::ReparentNativeView(gfx::NativeView native_view, |
| gfx::NativeView new_parent) { |
| internal::NativeWidgetPrivate::ReparentNativeView(native_view, new_parent); |
| } |
| |
| // static |
| int Widget::GetLocalizedContentsWidth(int col_resource_id) { |
| return ui::GetLocalizedContentsWidthForFont(col_resource_id, |
| ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont)); |
| } |
| |
| // static |
| int Widget::GetLocalizedContentsHeight(int row_resource_id) { |
| return ui::GetLocalizedContentsHeightForFont(row_resource_id, |
| ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont)); |
| } |
| |
| // static |
| gfx::Size Widget::GetLocalizedContentsSize(int col_resource_id, |
| int row_resource_id) { |
| return gfx::Size(GetLocalizedContentsWidth(col_resource_id), |
| GetLocalizedContentsHeight(row_resource_id)); |
| } |
| |
| // static |
| bool Widget::RequiresNonClientView(InitParams::Type type) { |
| return type == InitParams::TYPE_WINDOW || |
| type == InitParams::TYPE_PANEL || |
| type == InitParams::TYPE_BUBBLE; |
| } |
| |
| void Widget::Init(const InitParams& in_params) { |
| TRACE_EVENT0("views", "Widget::Init"); |
| InitParams params = in_params; |
| |
| params.child |= (params.type == InitParams::TYPE_CONTROL); |
| is_top_level_ = !params.child; |
| |
| if (params.opacity == views::Widget::InitParams::INFER_OPACITY && |
| params.type != views::Widget::InitParams::TYPE_WINDOW && |
| params.type != views::Widget::InitParams::TYPE_PANEL) |
| params.opacity = views::Widget::InitParams::OPAQUE_WINDOW; |
| |
| if (ViewsDelegate::views_delegate) |
| ViewsDelegate::views_delegate->OnBeforeWidgetInit(¶ms, this); |
| |
| if (params.opacity == views::Widget::InitParams::INFER_OPACITY) |
| params.opacity = views::Widget::InitParams::OPAQUE_WINDOW; |
| |
| bool can_activate = false; |
| if (params.activatable != InitParams::ACTIVATABLE_DEFAULT) { |
| can_activate = (params.activatable == InitParams::ACTIVATABLE_YES); |
| } else if (params.type != InitParams::TYPE_CONTROL && |
| params.type != InitParams::TYPE_POPUP && |
| params.type != InitParams::TYPE_MENU && |
| params.type != InitParams::TYPE_TOOLTIP && |
| params.type != InitParams::TYPE_DRAG) { |
| can_activate = true; |
| params.activatable = InitParams::ACTIVATABLE_YES; |
| } else { |
| can_activate = false; |
| params.activatable = InitParams::ACTIVATABLE_NO; |
| } |
| |
| widget_delegate_ = params.delegate ? |
| params.delegate : new DefaultWidgetDelegate(this); |
| widget_delegate_->set_can_activate(can_activate); |
| |
| ownership_ = params.ownership; |
| native_widget_ = CreateNativeWidget(params.native_widget, this)-> |
| AsNativeWidgetPrivate(); |
| root_view_.reset(CreateRootView()); |
| default_theme_provider_.reset(new ui::DefaultThemeProvider); |
| native_widget_->InitNativeWidget(params); |
| if (RequiresNonClientView(params.type)) { |
| non_client_view_ = new NonClientView; |
| non_client_view_->SetFrameView(CreateNonClientFrameView()); |
| // Create the ClientView, add it to the NonClientView and add the |
| // NonClientView to the RootView. This will cause everything to be parented. |
| non_client_view_->set_client_view(widget_delegate_->CreateClientView(this)); |
| non_client_view_->SetOverlayView(widget_delegate_->CreateOverlayView()); |
| SetContentsView(non_client_view_); |
| // Initialize the window's title before setting the window's initial bounds; |
| // the frame view's preferred height may depend on the presence of a title. |
| UpdateWindowTitle(); |
| non_client_view_->ResetWindowControls(); |
| SetInitialBounds(params.bounds); |
| if (params.show_state == ui::SHOW_STATE_MAXIMIZED) |
| Maximize(); |
| else if (params.show_state == ui::SHOW_STATE_MINIMIZED) |
| Minimize(); |
| } else if (params.delegate) { |
| SetContentsView(params.delegate->GetContentsView()); |
| SetInitialBoundsForFramelessWindow(params.bounds); |
| } |
| // This must come after SetContentsView() or it might not be able to find |
| // the correct NativeTheme (on Linux). See http://crbug.com/384492 |
| observer_manager_.Add(GetNativeTheme()); |
| native_widget_initialized_ = true; |
| } |
| |
| // Unconverted methods (see header) -------------------------------------------- |
| |
| gfx::NativeView Widget::GetNativeView() const { |
| return native_widget_->GetNativeView(); |
| } |
| |
| gfx::NativeWindow Widget::GetNativeWindow() const { |
| return native_widget_->GetNativeWindow(); |
| } |
| |
| void Widget::AddObserver(WidgetObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void Widget::RemoveObserver(WidgetObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| bool Widget::HasObserver(WidgetObserver* observer) { |
| return observers_.HasObserver(observer); |
| } |
| |
| void Widget::AddRemovalsObserver(WidgetRemovalsObserver* observer) { |
| removals_observers_.AddObserver(observer); |
| } |
| |
| void Widget::RemoveRemovalsObserver(WidgetRemovalsObserver* observer) { |
| removals_observers_.RemoveObserver(observer); |
| } |
| |
| bool Widget::HasRemovalsObserver(WidgetRemovalsObserver* observer) { |
| return removals_observers_.HasObserver(observer); |
| } |
| |
| bool Widget::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) const { |
| return false; |
| } |
| |
| void Widget::ViewHierarchyChanged( |
| const View::ViewHierarchyChangedDetails& details) { |
| if (!details.is_add) { |
| if (details.child == dragged_view_) |
| dragged_view_ = NULL; |
| FocusManager* focus_manager = GetFocusManager(); |
| if (focus_manager) |
| focus_manager->ViewRemoved(details.child); |
| ViewStorage::GetInstance()->ViewRemoved(details.child); |
| native_widget_->ViewRemoved(details.child); |
| } |
| } |
| |
| void Widget::NotifyNativeViewHierarchyWillChange() { |
| FocusManager* focus_manager = GetFocusManager(); |
| // We are being removed from a window hierarchy. Treat this as |
| // the root_view_ being removed. |
| if (focus_manager) |
| focus_manager->ViewRemoved(root_view_.get()); |
| } |
| |
| void Widget::NotifyNativeViewHierarchyChanged() { |
| root_view_->NotifyNativeViewHierarchyChanged(); |
| } |
| |
| void Widget::NotifyWillRemoveView(View* view) { |
| FOR_EACH_OBSERVER(WidgetRemovalsObserver, |
| removals_observers_, |
| OnWillRemoveView(this, view)); |
| } |
| |
| // Converted methods (see header) ---------------------------------------------- |
| |
| Widget* Widget::GetTopLevelWidget() { |
| return const_cast<Widget*>( |
| static_cast<const Widget*>(this)->GetTopLevelWidget()); |
| } |
| |
| const Widget* Widget::GetTopLevelWidget() const { |
| // GetTopLevelNativeWidget doesn't work during destruction because |
| // property is gone after gobject gets deleted. Short circuit here |
| // for toplevel so that InputMethod can remove itself from |
| // focus manager. |
| return is_top_level() ? this : native_widget_->GetTopLevelWidget(); |
| } |
| |
| void Widget::SetContentsView(View* view) { |
| // Do not SetContentsView() again if it is already set to the same view. |
| if (view == GetContentsView()) |
| return; |
| root_view_->SetContentsView(view); |
| if (non_client_view_ != view) { |
| // |non_client_view_| can only be non-NULL here if RequiresNonClientView() |
| // was true when the widget was initialized. Creating widgets with non |
| // client views and then setting the contents view can cause subtle |
| // problems on Windows, where the native widget thinks there is still a |
| // |non_client_view_|. If you get this error, either use a different type |
| // when initializing the widget, or don't call SetContentsView(). |
| DCHECK(!non_client_view_); |
| non_client_view_ = NULL; |
| } |
| } |
| |
| View* Widget::GetContentsView() { |
| return root_view_->GetContentsView(); |
| } |
| |
| gfx::Rect Widget::GetWindowBoundsInScreen() const { |
| return native_widget_->GetWindowBoundsInScreen(); |
| } |
| |
| gfx::Rect Widget::GetClientAreaBoundsInScreen() const { |
| return native_widget_->GetClientAreaBoundsInScreen(); |
| } |
| |
| gfx::Rect Widget::GetRestoredBounds() const { |
| return native_widget_->GetRestoredBounds(); |
| } |
| |
| void Widget::SetBounds(const gfx::Rect& bounds) { |
| native_widget_->SetBounds(bounds); |
| } |
| |
| void Widget::SetSize(const gfx::Size& size) { |
| native_widget_->SetSize(size); |
| } |
| |
| void Widget::CenterWindow(const gfx::Size& size) { |
| native_widget_->CenterWindow(size); |
| } |
| |
| void Widget::SetBoundsConstrained(const gfx::Rect& bounds) { |
| gfx::Rect work_area = |
| gfx::Screen::GetScreenFor(GetNativeView())->GetDisplayNearestPoint( |
| bounds.origin()).work_area(); |
| if (work_area.IsEmpty()) { |
| SetBounds(bounds); |
| } else { |
| // Inset the work area slightly. |
| work_area.Inset(10, 10, 10, 10); |
| work_area.AdjustToFit(bounds); |
| SetBounds(work_area); |
| } |
| } |
| |
| void Widget::SetVisibilityChangedAnimationsEnabled(bool value) { |
| native_widget_->SetVisibilityChangedAnimationsEnabled(value); |
| } |
| |
| Widget::MoveLoopResult Widget::RunMoveLoop( |
| const gfx::Vector2d& drag_offset, |
| MoveLoopSource source, |
| MoveLoopEscapeBehavior escape_behavior) { |
| return native_widget_->RunMoveLoop(drag_offset, source, escape_behavior); |
| } |
| |
| void Widget::EndMoveLoop() { |
| native_widget_->EndMoveLoop(); |
| } |
| |
| void Widget::StackAboveWidget(Widget* widget) { |
| native_widget_->StackAbove(widget->GetNativeView()); |
| } |
| |
| void Widget::StackAbove(gfx::NativeView native_view) { |
| native_widget_->StackAbove(native_view); |
| } |
| |
| void Widget::StackAtTop() { |
| native_widget_->StackAtTop(); |
| } |
| |
| void Widget::StackBelow(gfx::NativeView native_view) { |
| native_widget_->StackBelow(native_view); |
| } |
| |
| void Widget::SetShape(gfx::NativeRegion shape) { |
| native_widget_->SetShape(shape); |
| } |
| |
| void Widget::Close() { |
| if (widget_closed_) { |
| // It appears we can hit this code path if you close a modal dialog then |
| // close the last browser before the destructor is hit, which triggers |
| // invoking Close again. |
| return; |
| } |
| |
| bool can_close = true; |
| if (non_client_view_) |
| can_close = non_client_view_->CanClose(); |
| if (can_close) { |
| SaveWindowPlacement(); |
| |
| // During tear-down the top-level focus manager becomes unavailable to |
| // GTK tabbed panes and their children, so normal deregistration via |
| // |FormManager::ViewRemoved()| calls are fouled. We clear focus here |
| // to avoid these redundant steps and to avoid accessing deleted views |
| // that may have been in focus. |
| if (is_top_level() && focus_manager_.get()) |
| focus_manager_->SetFocusedView(NULL); |
| |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetClosing(this)); |
| native_widget_->Close(); |
| widget_closed_ = true; |
| } |
| } |
| |
| void Widget::CloseNow() { |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetClosing(this)); |
| native_widget_->CloseNow(); |
| } |
| |
| bool Widget::IsClosed() const { |
| return widget_closed_; |
| } |
| |
| void Widget::Show() { |
| TRACE_EVENT0("views", "Widget::Show"); |
| if (non_client_view_) { |
| // While initializing, the kiosk mode will go to full screen before the |
| // widget gets shown. In that case we stay in full screen mode, regardless |
| // of the |saved_show_state_| member. |
| if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED && |
| !initial_restored_bounds_.IsEmpty() && |
| !IsFullscreen()) { |
| native_widget_->ShowMaximizedWithBounds(initial_restored_bounds_); |
| } else { |
| native_widget_->ShowWithWindowState( |
| IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : saved_show_state_); |
| } |
| // |saved_show_state_| only applies the first time the window is shown. |
| // If we don't reset the value the window may be shown maximized every time |
| // it is subsequently shown after being hidden. |
| saved_show_state_ = ui::SHOW_STATE_NORMAL; |
| } else { |
| CanActivate() |
| ? native_widget_->Show() |
| : native_widget_->ShowWithWindowState(ui::SHOW_STATE_INACTIVE); |
| } |
| } |
| |
| void Widget::Hide() { |
| native_widget_->Hide(); |
| } |
| |
| void Widget::ShowInactive() { |
| // If this gets called with saved_show_state_ == ui::SHOW_STATE_MAXIMIZED, |
| // call SetBounds()with the restored bounds to set the correct size. This |
| // normally should not happen, but if it does we should avoid showing unsized |
| // windows. |
| if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED && |
| !initial_restored_bounds_.IsEmpty()) { |
| SetBounds(initial_restored_bounds_); |
| saved_show_state_ = ui::SHOW_STATE_NORMAL; |
| } |
| native_widget_->ShowWithWindowState(ui::SHOW_STATE_INACTIVE); |
| } |
| |
| void Widget::Activate() { |
| native_widget_->Activate(); |
| } |
| |
| void Widget::Deactivate() { |
| native_widget_->Deactivate(); |
| } |
| |
| bool Widget::IsActive() const { |
| return native_widget_->IsActive(); |
| } |
| |
| void Widget::DisableInactiveRendering() { |
| SetInactiveRenderingDisabled(true); |
| } |
| |
| void Widget::SetAlwaysOnTop(bool on_top) { |
| native_widget_->SetAlwaysOnTop(on_top); |
| } |
| |
| bool Widget::IsAlwaysOnTop() const { |
| return native_widget_->IsAlwaysOnTop(); |
| } |
| |
| void Widget::SetVisibleOnAllWorkspaces(bool always_visible) { |
| native_widget_->SetVisibleOnAllWorkspaces(always_visible); |
| } |
| |
| void Widget::Maximize() { |
| native_widget_->Maximize(); |
| } |
| |
| void Widget::Minimize() { |
| native_widget_->Minimize(); |
| } |
| |
| void Widget::Restore() { |
| native_widget_->Restore(); |
| } |
| |
| bool Widget::IsMaximized() const { |
| return native_widget_->IsMaximized(); |
| } |
| |
| bool Widget::IsMinimized() const { |
| return native_widget_->IsMinimized(); |
| } |
| |
| void Widget::SetFullscreen(bool fullscreen) { |
| if (IsFullscreen() == fullscreen) |
| return; |
| |
| native_widget_->SetFullscreen(fullscreen); |
| |
| if (non_client_view_) |
| non_client_view_->Layout(); |
| } |
| |
| bool Widget::IsFullscreen() const { |
| return native_widget_->IsFullscreen(); |
| } |
| |
| void Widget::SetOpacity(unsigned char opacity) { |
| native_widget_->SetOpacity(opacity); |
| } |
| |
| void Widget::SetUseDragFrame(bool use_drag_frame) { |
| native_widget_->SetUseDragFrame(use_drag_frame); |
| } |
| |
| void Widget::FlashFrame(bool flash) { |
| native_widget_->FlashFrame(flash); |
| } |
| |
| View* Widget::GetRootView() { |
| return root_view_.get(); |
| } |
| |
| const View* Widget::GetRootView() const { |
| return root_view_.get(); |
| } |
| |
| bool Widget::IsVisible() const { |
| return native_widget_->IsVisible(); |
| } |
| |
| ui::ThemeProvider* Widget::GetThemeProvider() const { |
| const Widget* root_widget = GetTopLevelWidget(); |
| if (root_widget && root_widget != this) { |
| // Attempt to get the theme provider, and fall back to the default theme |
| // provider if not found. |
| ui::ThemeProvider* provider = root_widget->GetThemeProvider(); |
| if (provider) |
| return provider; |
| |
| provider = root_widget->default_theme_provider_.get(); |
| if (provider) |
| return provider; |
| } |
| return default_theme_provider_.get(); |
| } |
| |
| const ui::NativeTheme* Widget::GetNativeTheme() const { |
| return native_widget_->GetNativeTheme(); |
| } |
| |
| FocusManager* Widget::GetFocusManager() { |
| Widget* toplevel_widget = GetTopLevelWidget(); |
| return toplevel_widget ? toplevel_widget->focus_manager_.get() : NULL; |
| } |
| |
| const FocusManager* Widget::GetFocusManager() const { |
| const Widget* toplevel_widget = GetTopLevelWidget(); |
| return toplevel_widget ? toplevel_widget->focus_manager_.get() : NULL; |
| } |
| |
| InputMethod* Widget::GetInputMethod() { |
| return const_cast<InputMethod*>( |
| const_cast<const Widget*>(this)->GetInputMethod()); |
| } |
| |
| const InputMethod* Widget::GetInputMethod() const { |
| if (is_top_level()) { |
| if (!input_method_.get()) |
| input_method_ = const_cast<Widget*>(this)->CreateInputMethod().Pass(); |
| return input_method_.get(); |
| } else { |
| const Widget* toplevel = GetTopLevelWidget(); |
| // If GetTopLevelWidget() returns itself which is not toplevel, |
| // the widget is detached from toplevel widget. |
| // TODO(oshima): Fix GetTopLevelWidget() to return NULL |
| // if there is no toplevel. We probably need to add GetTopMostWidget() |
| // to replace some use cases. |
| return (toplevel && toplevel != this) ? toplevel->GetInputMethod() : NULL; |
| } |
| } |
| |
| ui::InputMethod* Widget::GetHostInputMethod() { |
| return native_widget_private()->GetHostInputMethod(); |
| } |
| |
| void Widget::RunShellDrag(View* view, |
| const ui::OSExchangeData& data, |
| const gfx::Point& location, |
| int operation, |
| ui::DragDropTypes::DragEventSource source) { |
| dragged_view_ = view; |
| OnDragWillStart(); |
| native_widget_->RunShellDrag(view, data, location, operation, source); |
| // If the view is removed during the drag operation, dragged_view_ is set to |
| // NULL. |
| if (view && dragged_view_ == view) { |
| dragged_view_ = NULL; |
| view->OnDragDone(); |
| } |
| OnDragComplete(); |
| } |
| |
| void Widget::SchedulePaintInRect(const gfx::Rect& rect) { |
| native_widget_->SchedulePaintInRect(rect); |
| } |
| |
| void Widget::SetCursor(gfx::NativeCursor cursor) { |
| native_widget_->SetCursor(cursor); |
| } |
| |
| bool Widget::IsMouseEventsEnabled() const { |
| return native_widget_->IsMouseEventsEnabled(); |
| } |
| |
| void Widget::SetNativeWindowProperty(const char* name, void* value) { |
| native_widget_->SetNativeWindowProperty(name, value); |
| } |
| |
| void* Widget::GetNativeWindowProperty(const char* name) const { |
| return native_widget_->GetNativeWindowProperty(name); |
| } |
| |
| void Widget::UpdateWindowTitle() { |
| if (!non_client_view_) |
| return; |
| |
| // Update the native frame's text. We do this regardless of whether or not |
| // the native frame is being used, since this also updates the taskbar, etc. |
| base::string16 window_title = widget_delegate_->GetWindowTitle(); |
| base::i18n::AdjustStringForLocaleDirection(&window_title); |
| if (!native_widget_->SetWindowTitle(window_title)) |
| return; |
| non_client_view_->UpdateWindowTitle(); |
| |
| // If the non-client view is rendering its own title, it'll need to relayout |
| // now and to get a paint update later on. |
| non_client_view_->Layout(); |
| } |
| |
| void Widget::UpdateWindowIcon() { |
| if (non_client_view_) |
| non_client_view_->UpdateWindowIcon(); |
| native_widget_->SetWindowIcons(widget_delegate_->GetWindowIcon(), |
| widget_delegate_->GetWindowAppIcon()); |
| } |
| |
| FocusTraversable* Widget::GetFocusTraversable() { |
| return static_cast<internal::RootView*>(root_view_.get()); |
| } |
| |
| void Widget::ThemeChanged() { |
| root_view_->ThemeChanged(); |
| } |
| |
| void Widget::LocaleChanged() { |
| root_view_->LocaleChanged(); |
| } |
| |
| void Widget::SetFocusTraversableParent(FocusTraversable* parent) { |
| root_view_->SetFocusTraversableParent(parent); |
| } |
| |
| void Widget::SetFocusTraversableParentView(View* parent_view) { |
| root_view_->SetFocusTraversableParentView(parent_view); |
| } |
| |
| void Widget::ClearNativeFocus() { |
| native_widget_->ClearNativeFocus(); |
| } |
| |
| NonClientFrameView* Widget::CreateNonClientFrameView() { |
| NonClientFrameView* frame_view = |
| widget_delegate_->CreateNonClientFrameView(this); |
| if (!frame_view) |
| frame_view = native_widget_->CreateNonClientFrameView(); |
| if (!frame_view && ViewsDelegate::views_delegate) { |
| frame_view = |
| ViewsDelegate::views_delegate->CreateDefaultNonClientFrameView(this); |
| } |
| if (frame_view) |
| return frame_view; |
| |
| CustomFrameView* custom_frame_view = new CustomFrameView; |
| custom_frame_view->Init(this); |
| return custom_frame_view; |
| } |
| |
| bool Widget::ShouldUseNativeFrame() const { |
| if (frame_type_ != FRAME_TYPE_DEFAULT) |
| return frame_type_ == FRAME_TYPE_FORCE_NATIVE; |
| return native_widget_->ShouldUseNativeFrame(); |
| } |
| |
| bool Widget::ShouldWindowContentsBeTransparent() const { |
| return native_widget_->ShouldWindowContentsBeTransparent(); |
| } |
| |
| void Widget::DebugToggleFrameType() { |
| if (frame_type_ == FRAME_TYPE_DEFAULT) { |
| frame_type_ = ShouldUseNativeFrame() ? FRAME_TYPE_FORCE_CUSTOM : |
| FRAME_TYPE_FORCE_NATIVE; |
| } else { |
| frame_type_ = frame_type_ == FRAME_TYPE_FORCE_CUSTOM ? |
| FRAME_TYPE_FORCE_NATIVE : FRAME_TYPE_FORCE_CUSTOM; |
| } |
| FrameTypeChanged(); |
| } |
| |
| void Widget::FrameTypeChanged() { |
| native_widget_->FrameTypeChanged(); |
| } |
| |
| const ui::Compositor* Widget::GetCompositor() const { |
| return native_widget_->GetCompositor(); |
| } |
| |
| ui::Compositor* Widget::GetCompositor() { |
| return native_widget_->GetCompositor(); |
| } |
| |
| ui::Layer* Widget::GetLayer() { |
| return native_widget_->GetLayer(); |
| } |
| |
| void Widget::ReorderNativeViews() { |
| native_widget_->ReorderNativeViews(); |
| } |
| |
| void Widget::UpdateRootLayers() { |
| // Calculate the layers requires traversing the tree, and since nearly any |
| // mutation of the tree can trigger this call we delay until absolutely |
| // necessary. |
| root_layers_dirty_ = true; |
| } |
| |
| const NativeWidget* Widget::native_widget() const { |
| return native_widget_; |
| } |
| |
| NativeWidget* Widget::native_widget() { |
| return native_widget_; |
| } |
| |
| void Widget::SetCapture(View* view) { |
| if (!native_widget_->HasCapture()) { |
| native_widget_->SetCapture(); |
| |
| // Early return if setting capture was unsuccessful. |
| if (!native_widget_->HasCapture()) |
| return; |
| } |
| |
| root_view_->SetMouseHandler(view); |
| } |
| |
| void Widget::ReleaseCapture() { |
| if (native_widget_->HasCapture()) |
| native_widget_->ReleaseCapture(); |
| } |
| |
| bool Widget::HasCapture() { |
| return native_widget_->HasCapture(); |
| } |
| |
| TooltipManager* Widget::GetTooltipManager() { |
| return native_widget_->GetTooltipManager(); |
| } |
| |
| const TooltipManager* Widget::GetTooltipManager() const { |
| return native_widget_->GetTooltipManager(); |
| } |
| |
| gfx::Rect Widget::GetWorkAreaBoundsInScreen() const { |
| return native_widget_->GetWorkAreaBoundsInScreen(); |
| } |
| |
| void Widget::SynthesizeMouseMoveEvent() { |
| last_mouse_event_was_move_ = false; |
| ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, |
| last_mouse_event_position_, |
| last_mouse_event_position_, |
| ui::EF_IS_SYNTHESIZED, 0); |
| root_view_->OnMouseMoved(mouse_event); |
| } |
| |
| void Widget::OnRootViewLayout() { |
| native_widget_->OnRootViewLayout(); |
| } |
| |
| bool Widget::IsTranslucentWindowOpacitySupported() const { |
| return native_widget_->IsTranslucentWindowOpacitySupported(); |
| } |
| |
| void Widget::OnSizeConstraintsChanged() { |
| native_widget_->OnSizeConstraintsChanged(); |
| non_client_view_->SizeConstraintsChanged(); |
| } |
| |
| void Widget::OnOwnerClosing() { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, NativeWidgetDelegate implementation: |
| |
| bool Widget::IsModal() const { |
| return widget_delegate_->GetModalType() != ui::MODAL_TYPE_NONE; |
| } |
| |
| bool Widget::IsDialogBox() const { |
| return !!widget_delegate_->AsDialogDelegate(); |
| } |
| |
| bool Widget::CanActivate() const { |
| return widget_delegate_->CanActivate(); |
| } |
| |
| bool Widget::IsInactiveRenderingDisabled() const { |
| return disable_inactive_rendering_; |
| } |
| |
| void Widget::EnableInactiveRendering() { |
| SetInactiveRenderingDisabled(false); |
| } |
| |
| void Widget::OnNativeWidgetActivationChanged(bool active) { |
| // On windows we may end up here before we've completed initialization (from |
| // an WM_NCACTIVATE). If that happens the WidgetDelegate likely doesn't know |
| // the Widget and will crash attempting to access it. |
| if (!active && native_widget_initialized_) |
| SaveWindowPlacement(); |
| |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, |
| OnWidgetActivationChanged(this, active)); |
| |
| // During window creation, the widget gets focused without activation, and in |
| // that case, the focus manager cannot set the appropriate text input client |
| // because the widget is not active. Thus we have to notify the focus manager |
| // not only when the focus changes but also when the widget gets activated. |
| // See crbug.com/377479 for details. |
| views::FocusManager* focus_manager = GetFocusManager(); |
| if (focus_manager) { |
| if (active) |
| focus_manager->FocusTextInputClient(focus_manager->GetFocusedView()); |
| else |
| focus_manager->BlurTextInputClient(focus_manager->GetFocusedView()); |
| } |
| |
| if (IsVisible() && non_client_view()) |
| non_client_view()->frame_view()->SchedulePaint(); |
| } |
| |
| void Widget::OnNativeFocus(gfx::NativeView old_focused_view) { |
| WidgetFocusManager::GetInstance()->OnWidgetFocusEvent(old_focused_view, |
| GetNativeView()); |
| } |
| |
| void Widget::OnNativeBlur(gfx::NativeView new_focused_view) { |
| WidgetFocusManager::GetInstance()->OnWidgetFocusEvent(GetNativeView(), |
| new_focused_view); |
| } |
| |
| void Widget::OnNativeWidgetVisibilityChanging(bool visible) { |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, |
| OnWidgetVisibilityChanging(this, visible)); |
| } |
| |
| void Widget::OnNativeWidgetVisibilityChanged(bool visible) { |
| View* root = GetRootView(); |
| if (root) |
| root->PropagateVisibilityNotifications(root, visible); |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, |
| OnWidgetVisibilityChanged(this, visible)); |
| if (GetCompositor() && root && root->layer()) |
| root->layer()->SetVisible(visible); |
| } |
| |
| void Widget::OnNativeWidgetCreated(bool desktop_widget) { |
| if (is_top_level()) |
| focus_manager_.reset(FocusManagerFactory::Create(this, desktop_widget)); |
| |
| native_widget_->InitModalType(widget_delegate_->GetModalType()); |
| |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetCreated(this)); |
| } |
| |
| void Widget::OnNativeWidgetDestroying() { |
| // Tell the focus manager (if any) that root_view is being removed |
| // in case that the focused view is under this root view. |
| if (GetFocusManager()) |
| GetFocusManager()->ViewRemoved(root_view_.get()); |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetDestroying(this)); |
| if (non_client_view_) |
| non_client_view_->WindowClosing(); |
| widget_delegate_->WindowClosing(); |
| } |
| |
| void Widget::OnNativeWidgetDestroyed() { |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetDestroyed(this)); |
| widget_delegate_->DeleteDelegate(); |
| widget_delegate_ = NULL; |
| native_widget_destroyed_ = true; |
| } |
| |
| gfx::Size Widget::GetMinimumSize() const { |
| return non_client_view_ ? non_client_view_->GetMinimumSize() : gfx::Size(); |
| } |
| |
| gfx::Size Widget::GetMaximumSize() const { |
| return non_client_view_ ? non_client_view_->GetMaximumSize() : gfx::Size(); |
| } |
| |
| void Widget::OnNativeWidgetMove() { |
| widget_delegate_->OnWidgetMove(); |
| View* root = GetRootView(); |
| if (root && root->GetFocusManager()) { |
| View* focused_view = root->GetFocusManager()->GetFocusedView(); |
| if (focused_view && focused_view->GetInputMethod()) |
| focused_view->GetInputMethod()->OnCaretBoundsChanged(focused_view); |
| } |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetBoundsChanged( |
| this, |
| GetWindowBoundsInScreen())); |
| } |
| |
| void Widget::OnNativeWidgetSizeChanged(const gfx::Size& new_size) { |
| View* root = GetRootView(); |
| if (root) { |
| root->SetSize(new_size); |
| if (root->GetFocusManager()) { |
| View* focused_view = GetRootView()->GetFocusManager()->GetFocusedView(); |
| if (focused_view && focused_view->GetInputMethod()) |
| focused_view->GetInputMethod()->OnCaretBoundsChanged(focused_view); |
| } |
| } |
| SaveWindowPlacementIfInitialized(); |
| |
| FOR_EACH_OBSERVER(WidgetObserver, observers_, OnWidgetBoundsChanged( |
| this, |
| GetWindowBoundsInScreen())); |
| } |
| |
| void Widget::OnNativeWidgetWindowShowStateChanged() { |
| SaveWindowPlacementIfInitialized(); |
| } |
| |
| void Widget::OnNativeWidgetBeginUserBoundsChange() { |
| widget_delegate_->OnWindowBeginUserBoundsChange(); |
| } |
| |
| void Widget::OnNativeWidgetEndUserBoundsChange() { |
| widget_delegate_->OnWindowEndUserBoundsChange(); |
| } |
| |
| bool Widget::HasFocusManager() const { |
| return !!focus_manager_.get(); |
| } |
| |
| bool Widget::OnNativeWidgetPaintAccelerated(const gfx::Rect& dirty_region) { |
| ui::Compositor* compositor = GetCompositor(); |
| if (!compositor) |
| return false; |
| |
| compositor->ScheduleRedrawRect(dirty_region); |
| return true; |
| } |
| |
| void Widget::OnNativeWidgetPaint(gfx::Canvas* canvas) { |
| // On Linux Aura, we can get here during Init() because of the |
| // SetInitialBounds call. |
| if (native_widget_initialized_) |
| GetRootView()->Paint(canvas, CullSet()); |
| } |
| |
| int Widget::GetNonClientComponent(const gfx::Point& point) { |
| int component = non_client_view_ ? |
| non_client_view_->NonClientHitTest(point) : |
| HTNOWHERE; |
| |
| if (movement_disabled_ && (component == HTCAPTION || component == HTSYSMENU)) |
| return HTNOWHERE; |
| |
| return component; |
| } |
| |
| void Widget::OnKeyEvent(ui::KeyEvent* event) { |
| SendEventToProcessor(event); |
| } |
| |
| // TODO(tdanderson): We should not be calling the OnMouse*() functions on |
| // RootView from anywhere in Widget. Use |
| // SendEventToProcessor() instead. See crbug.com/348087. |
| void Widget::OnMouseEvent(ui::MouseEvent* event) { |
| if (event->type() != ui::ET_MOUSE_MOVED) |
| last_mouse_event_was_move_ = false; |
| |
| View* root_view = GetRootView(); |
| switch (event->type()) { |
| case ui::ET_MOUSE_PRESSED: { |
| // We may get deleted by the time we return from OnMousePressed. So we |
| // use an observer to make sure we are still alive. |
| WidgetDeletionObserver widget_deletion_observer(this); |
| |
| // Make sure we're still visible before we attempt capture as the mouse |
| // press processing may have made the window hide (as happens with menus). |
| |
| // It is possible for a View to show a context menu on mouse-press. Since |
| // the menu does a capture and starts a nested message-loop, the release |
| // would go to the menu. The next click (i.e. both mouse-press and release |
| // events) also go to the menu. The menu (and the nested message-loop) |
| // gets closed after this second release event. The code then resumes from |
| // here. So make sure that the mouse-button is still down before doing a |
| // capture. |
| if (root_view && root_view->OnMousePressed(*event) && |
| widget_deletion_observer.IsWidgetAlive() && IsVisible() && |
| internal::NativeWidgetPrivate::IsMouseButtonDown()) { |
| if (!native_widget_->HasCapture()) |
| native_widget_->SetCapture(); |
| event->SetHandled(); |
| } |
| return; |
| } |
| |
| case ui::ET_MOUSE_RELEASED: |
| // Release capture first, to avoid confusion if OnMouseReleased blocks. |
| if (auto_release_capture_ && native_widget_->HasCapture()) { |
| base::AutoReset<bool> resetter(&ignore_capture_loss_, true); |
| native_widget_->ReleaseCapture(); |
| } |
| if (root_view) |
| root_view->OnMouseReleased(*event); |
| if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) |
| event->SetHandled(); |
| return; |
| |
| case ui::ET_MOUSE_MOVED: |
| if (!last_mouse_event_was_move_ || |
| last_mouse_event_position_ != event->location()) { |
| last_mouse_event_position_ = event->location(); |
| last_mouse_event_was_move_ = true; |
| if (root_view) |
| root_view->OnMouseMoved(*event); |
| } |
| return; |
| |
| case ui::ET_MOUSE_DRAGGED: |
| if (root_view) |
| root_view->OnMouseDragged(*event); |
| return; |
| |
| case ui::ET_MOUSE_EXITED: |
| if (root_view) |
| root_view->OnMouseExited(*event); |
| return; |
| |
| case ui::ET_MOUSEWHEEL: |
| if (root_view && root_view->OnMouseWheel( |
| static_cast<const ui::MouseWheelEvent&>(*event))) |
| event->SetHandled(); |
| return; |
| |
| default: |
| return; |
| } |
| } |
| |
| void Widget::OnMouseCaptureLost() { |
| if (ignore_capture_loss_) |
| return; |
| |
| View* root_view = GetRootView(); |
| if (root_view) |
| root_view->OnMouseCaptureLost(); |
| } |
| |
| void Widget::OnScrollEvent(ui::ScrollEvent* event) { |
| ui::ScrollEvent event_copy(*event); |
| SendEventToProcessor(&event_copy); |
| |
| // Convert unhandled ui::ET_SCROLL events into ui::ET_MOUSEWHEEL events. |
| if (!event_copy.handled() && event_copy.type() == ui::ET_SCROLL) { |
| ui::MouseWheelEvent wheel(*event); |
| OnMouseEvent(&wheel); |
| } |
| } |
| |
| void Widget::OnGestureEvent(ui::GestureEvent* event) { |
| // We explicitly do not capture here. Not capturing enables multiple widgets |
| // to get tap events at the same time. Views (such as tab dragging) may |
| // explicitly capture. |
| SendEventToProcessor(event); |
| } |
| |
| bool Widget::ExecuteCommand(int command_id) { |
| return widget_delegate_->ExecuteWindowsCommand(command_id); |
| } |
| |
| InputMethod* Widget::GetInputMethodDirect() { |
| return input_method_.get(); |
| } |
| |
| const std::vector<ui::Layer*>& Widget::GetRootLayers() { |
| if (root_layers_dirty_) { |
| root_layers_dirty_ = false; |
| root_layers_.clear(); |
| BuildRootLayers(GetRootView(), &root_layers_); |
| } |
| return root_layers_; |
| } |
| |
| bool Widget::HasHitTestMask() const { |
| return widget_delegate_->WidgetHasHitTestMask(); |
| } |
| |
| void Widget::GetHitTestMask(gfx::Path* mask) const { |
| DCHECK(mask); |
| widget_delegate_->GetWidgetHitTestMask(mask); |
| } |
| |
| Widget* Widget::AsWidget() { |
| return this; |
| } |
| |
| const Widget* Widget::AsWidget() const { |
| return this; |
| } |
| |
| bool Widget::SetInitialFocus(ui::WindowShowState show_state) { |
| View* v = widget_delegate_->GetInitiallyFocusedView(); |
| if (!focus_on_creation_ || show_state == ui::SHOW_STATE_INACTIVE || |
| show_state == ui::SHOW_STATE_MINIMIZED) { |
| // If not focusing the window now, tell the focus manager which view to |
| // focus when the window is restored. |
| if (v) |
| focus_manager_->SetStoredFocusView(v); |
| return true; |
| } |
| if (v) |
| v->RequestFocus(); |
| return !!v; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, ui::EventSource implementation: |
| ui::EventProcessor* Widget::GetEventProcessor() { |
| return root_view_.get(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, FocusTraversable implementation: |
| |
| FocusSearch* Widget::GetFocusSearch() { |
| return root_view_->GetFocusSearch(); |
| } |
| |
| FocusTraversable* Widget::GetFocusTraversableParent() { |
| // We are a proxy to the root view, so we should be bypassed when traversing |
| // up and as a result this should not be called. |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| View* Widget::GetFocusTraversableParentView() { |
| // We are a proxy to the root view, so we should be bypassed when traversing |
| // up and as a result this should not be called. |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, ui::NativeThemeObserver implementation: |
| |
| void Widget::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) { |
| DCHECK(observer_manager_.IsObserving(observed_theme)); |
| |
| ui::NativeTheme* current_native_theme = GetNativeTheme(); |
| if (!observer_manager_.IsObserving(current_native_theme)) { |
| observer_manager_.RemoveAll(); |
| observer_manager_.Add(current_native_theme); |
| } |
| |
| root_view_->PropagateNativeThemeChanged(current_native_theme); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, protected: |
| |
| internal::RootView* Widget::CreateRootView() { |
| return new internal::RootView(this); |
| } |
| |
| void Widget::DestroyRootView() { |
| non_client_view_ = NULL; |
| root_view_.reset(); |
| // Input method has to be destroyed before focus manager. |
| input_method_.reset(); |
| } |
| |
| void Widget::OnDragWillStart() { |
| } |
| |
| void Widget::OnDragComplete() { |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Widget, private: |
| |
| void Widget::SetInactiveRenderingDisabled(bool value) { |
| if (value == disable_inactive_rendering_) |
| return; |
| |
| disable_inactive_rendering_ = value; |
| if (non_client_view_) |
| non_client_view_->SetInactiveRenderingDisabled(value); |
| } |
| |
| void Widget::SaveWindowPlacement() { |
| // The window delegate does the actual saving for us. It seems like (judging |
| // by go/crash) that in some circumstances we can end up here after |
| // WM_DESTROY, at which point the window delegate is likely gone. So just |
| // bail. |
| if (!widget_delegate_) |
| return; |
| |
| ui::WindowShowState show_state = ui::SHOW_STATE_NORMAL; |
| gfx::Rect bounds; |
| native_widget_->GetWindowPlacement(&bounds, &show_state); |
| widget_delegate_->SaveWindowPlacement(bounds, show_state); |
| } |
| |
| void Widget::SaveWindowPlacementIfInitialized() { |
| if (native_widget_initialized_) |
| SaveWindowPlacement(); |
| } |
| |
| void Widget::SetInitialBounds(const gfx::Rect& bounds) { |
| if (!non_client_view_) |
| return; |
| |
| gfx::Rect saved_bounds; |
| if (GetSavedWindowPlacement(&saved_bounds, &saved_show_state_)) { |
| if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED) { |
| // If we're going to maximize, wait until Show is invoked to set the |
| // bounds. That way we avoid a noticeable resize. |
| initial_restored_bounds_ = saved_bounds; |
| } else if (!saved_bounds.IsEmpty()) { |
| // If the saved bounds are valid, use them. |
| SetBounds(saved_bounds); |
| } |
| } else { |
| if (bounds.IsEmpty()) { |
| // No initial bounds supplied, so size the window to its content and |
| // center over its parent. |
| native_widget_->CenterWindow(non_client_view_->GetPreferredSize()); |
| } else { |
| // Use the supplied initial bounds. |
| SetBoundsConstrained(bounds); |
| } |
| } |
| } |
| |
| void Widget::SetInitialBoundsForFramelessWindow(const gfx::Rect& bounds) { |
| if (bounds.IsEmpty()) { |
| View* contents_view = GetContentsView(); |
| DCHECK(contents_view); |
| // No initial bounds supplied, so size the window to its content and |
| // center over its parent if preferred size is provided. |
| gfx::Size size = contents_view->GetPreferredSize(); |
| if (!size.IsEmpty()) |
| native_widget_->CenterWindow(size); |
| } else { |
| // Use the supplied initial bounds. |
| SetBoundsConstrained(bounds); |
| } |
| } |
| |
| bool Widget::GetSavedWindowPlacement(gfx::Rect* bounds, |
| ui::WindowShowState* show_state) { |
| // First we obtain the window's saved show-style and store it. We need to do |
| // this here, rather than in Show() because by the time Show() is called, |
| // the window's size will have been reset (below) and the saved maximized |
| // state will have been lost. Sadly there's no way to tell on Windows when |
| // a window is restored from maximized state, so we can't more accurately |
| // track maximized state independently of sizing information. |
| |
| // Restore the window's placement from the controller. |
| if (widget_delegate_->GetSavedWindowPlacement(this, bounds, show_state)) { |
| if (!widget_delegate_->ShouldRestoreWindowSize()) { |
| bounds->set_size(non_client_view_->GetPreferredSize()); |
| } else { |
| gfx::Size minimum_size = GetMinimumSize(); |
| // Make sure the bounds are at least the minimum size. |
| if (bounds->width() < minimum_size.width()) |
| bounds->set_width(minimum_size.width()); |
| |
| if (bounds->height() < minimum_size.height()) |
| bounds->set_height(minimum_size.height()); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| scoped_ptr<InputMethod> Widget::CreateInputMethod() { |
| scoped_ptr<InputMethod> input_method(native_widget_->CreateInputMethod()); |
| if (input_method.get()) |
| input_method->Init(this); |
| return input_method.Pass(); |
| } |
| |
| void Widget::ReplaceInputMethod(InputMethod* input_method) { |
| input_method_.reset(input_method); |
| input_method->SetDelegate(native_widget_->GetInputMethodDelegate()); |
| input_method->Init(this); |
| } |
| |
| namespace internal { |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // internal::NativeWidgetPrivate, NativeWidget implementation: |
| |
| internal::NativeWidgetPrivate* NativeWidgetPrivate::AsNativeWidgetPrivate() { |
| return this; |
| } |
| |
| } // namespace internal |
| } // namespace views |