diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-10-26 13:57:00 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-11-02 11:31:01 +0000 |
commit | 1943b3c2a1dcee36c233724fc4ee7613d71b9cf6 (patch) | |
tree | 8c1b5f12357025c197da5427ae02cfdc2f3570d6 /chromium/ui/views/widget | |
parent | 21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (diff) | |
download | qtwebengine-chromium-1943b3c2a1dcee36c233724fc4ee7613d71b9cf6.tar.gz |
BASELINE: Update Chromium to 94.0.4606.111
Change-Id: I924781584def20fc800bedf6ff41fdb96c438193
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/ui/views/widget')
35 files changed, 656 insertions, 243 deletions
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc index d437e382af5..93a726143bb 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc @@ -4,6 +4,7 @@ #include "ui/views/widget/desktop_aura/desktop_capture_client.h" +#include "base/containers/cxx20_erase.h" #include "ui/aura/client/capture_client_observer.h" #include "ui/aura/env.h" #include "ui/aura/window.h" diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc index cb7cea0d488..9307934a4ae 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_win.cc @@ -43,15 +43,12 @@ ui::mojom::DragOperation DesktopDragDropClientWin::StartDragAndDrop( int allowed_operations, ui::mojom::DragEventSource source) { drag_drop_in_progress_ = true; + gfx::Point touch_screen_point; if (source == ui::mojom::DragEventSource::kTouch) { - gfx::Point screen_point = display::win::ScreenWin::DIPToScreenPoint( - {screen_location.x(), screen_location.y()}); - // Send a mouse down and mouse move before do drag drop runs its own event - // loop. This is required for ::DoDragDrop to start the drag. - ui::SendMouseEvent(screen_point, - MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE); - ui::SendMouseEvent(screen_point, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE); - desktop_host_->SetInTouchDrag(true); + touch_screen_point = + screen_location + source_window->GetBoundsInScreen().OffsetFromOrigin(); + source_window->GetHost()->ConvertDIPToPixels(&touch_screen_point); + desktop_host_->StartTouchDrag(touch_screen_point); // Gesture state gets left in a state where you can't start // another drag, unless it's cleaned up. Cleaning it up before starting // drag drop also fixes an issue with getting two kGestureScrollBegin events @@ -68,9 +65,11 @@ ui::mojom::DragOperation DesktopDragDropClientWin::StartDragAndDrop( DWORD effect; - // Disable hang watching until the end of the function since the user can take - // unbounded time to complete the drag. (http://crbug.com/806174) - base::IgnoreHangsInScope disabler; + // Never consider the current scope as hung. The hang watching deadline (if + // any) is not valid since the user can take unbounded time to complete the + // drag. (http://crbug.com/806174) + base::HangWatcher::InvalidateActiveExpectations(); + base::TimeTicks start_time = base::TimeTicks::Now(); HRESULT result = ::DoDragDrop( @@ -87,8 +86,8 @@ ui::mojom::DragOperation DesktopDragDropClientWin::StartDragAndDrop( // it's called when it gets a mouse move event as well. (::DoDragDrop // doesn't support touch, so Chrome synthesizes mouse events from touch // events during drag drop.) - // In the touch failure case, when ::DoDragDrop blocks waiting for a right - // mouse button down event to start the drag, it only calls + // In the touch failure case, when ::DoDragDrop blocks waiting for a mouse + // button down event to start the drag, it only calls // QueryContinueDrag once, when it gets an event that terminates the blocked // drag drop, e.g., a swipe gesture from outside the Chrome window. So, we // detect the failure case when a drag drop lasts more than one second, and @@ -98,7 +97,10 @@ ui::mojom::DragOperation DesktopDragDropClientWin::StartDragAndDrop( drag_source_->num_query_continues() > 1 || (base::TimeTicks::Now() - start_time < base::TimeDelta::FromSeconds(1))); - desktop_host_->SetInTouchDrag(false); + desktop_host_->FinishTouchDrag(touch_screen_point); + // Move the mouse cursor to where the drag drop started, to avoid issues + // when the drop is outside of the Chrome window. + ::SetCursorPos(touch_screen_point.x(), touch_screen_point.y()); } drag_source_copy->set_data(nullptr); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index de5ad7a0142..841458639c0 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -68,6 +68,7 @@ #include "ui/wm/core/visibility_controller.h" #include "ui/wm/core/window_animations.h" #include "ui/wm/core/window_modality_controller.h" +#include "ui/wm/core/window_util.h" #include "ui/wm/public/activation_client.h" #if defined(OS_WIN) @@ -110,8 +111,7 @@ class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver { #if defined(OS_WIN) // For menus, on Windows versions that support drop shadow remove // the standard frame in order to keep just the shadow. - if (::features::IsFormControlsRefreshEnabled() && - init_params.type == Widget::InitParams::TYPE_MENU) + if (init_params.type == Widget::InitParams::TYPE_MENU) init_params.remove_standard_frame = true; #endif init_params.bounds = bounds; @@ -404,7 +404,18 @@ void DesktopNativeWidgetAura::HandleActivationChanged(bool active) { : focus_manager->GetStoredFocusView(); if (!view_for_activation || !view_for_activation->GetWidget()) { view_for_activation = GetWidget()->GetRootView(); + activation_client->ActivateWindow(content_window_); } else if (view_for_activation == focus_manager->GetStoredFocusView()) { + // Update activation before restoring focus to prevent race condition. + // RestoreFocusedView() will activate the widget if Widget::IsActive() + // is false. Note that IsActive() checks ActivationClient for active + // widget, if ActivationClient is updated after focus, we risk running + // into an infinite loop. + // In practice, infinite loop does not happen because the window tree + // host avoids re-entrance to Activate() when the OS's window is active. + // But this is still a risk when two DNWAs both try to activate itself. + activation_client->ActivateWindow( + view_for_activation->GetWidget()->GetNativeView()); // When desktop native widget has modal transient child, we don't // restore focused view here, as the modal transient child window will // get activated and focused. Thus, we are not left with multiple @@ -418,8 +429,7 @@ void DesktopNativeWidgetAura::HandleActivationChanged(bool active) { restore_focus_on_activate_ = false; } } - activation_client->ActivateWindow( - view_for_activation->GetWidget()->GetNativeView()); + // Refreshes the focus info to IMF in case that IMF cached the old info // about focused text input client when it was "inactive". GetInputMethod()->OnFocus(); @@ -580,8 +590,8 @@ void DesktopNativeWidgetAura::InitNativeWidget(Widget::InitParams params) { if (params.type != Widget::InitParams::TYPE_TOOLTIP) { tooltip_manager_ = std::make_unique<TooltipManagerAura>(GetWidget()); tooltip_controller_ = std::make_unique<corewm::TooltipController>( - - desktop_window_tree_host_->CreateTooltip()); + desktop_window_tree_host_->CreateTooltip(), + wm::GetActivationClient(host_->window())); wm::SetTooltipClient(host_->window(), tooltip_controller_.get()); host_->window()->AddPreTargetHandler(tooltip_controller_.get()); } @@ -739,6 +749,14 @@ void DesktopNativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon, app_icon); } +const gfx::ImageSkia* DesktopNativeWidgetAura::GetWindowIcon() { + return nullptr; +} + +const gfx::ImageSkia* DesktopNativeWidgetAura::GetWindowAppIcon() { + return nullptr; +} + void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) { // 99% of the time, we should not be asked to create a // DesktopNativeWidgetAura that is modal. We only support window modal @@ -836,7 +854,7 @@ bool DesktopNativeWidgetAura::IsVisible() const { void DesktopNativeWidgetAura::Activate() { if (content_window_) { - bool was_active = IsActive(); + bool was_tree_active = desktop_window_tree_host_->IsActive(); desktop_window_tree_host_->Activate(); // If the whole window tree host was already active, @@ -846,7 +864,7 @@ void DesktopNativeWidgetAura::Activate() { // since if client code is calling Widget::Activate() they probably // want that particular widget to be activated, not just something // within that widget hierarchy. - if (was_active && focus_client_->GetFocusedWindow() != content_window_) + if (was_tree_active && focus_client_->GetFocusedWindow() != content_window_) focus_client_->FocusWindow(content_window_); } } @@ -857,7 +875,8 @@ void DesktopNativeWidgetAura::Deactivate() { } bool DesktopNativeWidgetAura::IsActive() const { - return content_window_ && desktop_window_tree_host_->IsActive(); + return content_window_ && desktop_window_tree_host_->IsActive() && + wm::IsActiveWindow(content_window_); } void DesktopNativeWidgetAura::SetZOrderLevel(ui::ZOrderLevel order) { @@ -907,7 +926,8 @@ void DesktopNativeWidgetAura::Restore() { desktop_window_tree_host_->Restore(); } -void DesktopNativeWidgetAura::SetFullscreen(bool fullscreen) { +void DesktopNativeWidgetAura::SetFullscreen(bool fullscreen, + const base::TimeDelta& delay) { if (content_window_) desktop_window_tree_host_->SetFullscreen(fullscreen); } @@ -1273,9 +1293,12 @@ ui::mojom::DragOperation DesktopNativeWidgetAura::OnPerformDrop( aura::client::DragDropDelegate::DropCallback DesktopNativeWidgetAura::GetDropCallback(const ui::DropTargetEvent& event) { - // TODO(crbug.com/1197505): Return drop callback. - NOTREACHED(); - return base::NullCallback(); + DCHECK(drop_helper_); + if (ShouldActivate()) + Activate(); + + return drop_helper_->GetDropCallback(event.data(), event.location(), + last_drop_operation_); } //////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index 8dd86cd6e28..661b6cd232b 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h @@ -138,6 +138,8 @@ class VIEWS_EXPORT DesktopNativeWidgetAura bool SetWindowTitle(const std::u16string& title) override; void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) override; + const gfx::ImageSkia* GetWindowIcon() override; + const gfx::ImageSkia* GetWindowAppIcon() override; void InitModalType(ui::ModalType modal_type) override; gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; @@ -167,7 +169,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura bool IsMaximized() const override; bool IsMinimized() const override; void Restore() override; - void SetFullscreen(bool fullscreen) override; + void SetFullscreen(bool fullscreen, const base::TimeDelta& delay) override; bool IsFullscreen() const override; void SetCanAppearInExistingFullscreenSpaces( bool can_appear_in_existing_fullscreen_spaces) override; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc index 956c0824a45..ac6e5399e39 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc @@ -100,7 +100,7 @@ gfx::NativeWindow DesktopScreenX11::GetLocalProcessWindowAtPoint( } int DesktopScreenX11::GetNumDisplays() const { - return int{x11_display_manager_->displays().size()}; + return static_cast<int>(x11_display_manager_->displays().size()); } const std::vector<display::Display>& DesktopScreenX11::GetAllDisplays() const { diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.cc index 047f9a9523d..493674eea83 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.cc @@ -4,6 +4,7 @@ #include "ui/views/widget/desktop_aura/desktop_window_tree_host.h" +#include "build/build_config.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/display/screen.h" @@ -12,7 +13,15 @@ namespace views { void DesktopWindowTreeHost::SetBoundsInDIP(const gfx::Rect& bounds) { +#if defined(OS_WIN) + // The window parameter is intentionally passed as nullptr on Windows because + // a non-null window parameter causes errors when restoring windows to saved + // positions in variable-DPI situations. See https://crbug.com/1224715 for + // details. + aura::Window* root = nullptr; +#else aura::Window* root = AsWindowTreeHost()->window(); +#endif const gfx::Rect bounds_in_pixels = display::Screen::GetScreen()->DIPToScreenRectInWindow(root, bounds); AsWindowTreeHost()->SetBoundsInPixels(bounds_in_pixels); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc index 7f7d82f5186..6e09038a0ff 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc @@ -19,6 +19,7 @@ #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/events/event.h" +#include "ui/platform_window/extensions/desk_extension.h" #include "ui/platform_window/extensions/wayland_extension.h" #include "ui/platform_window/extensions/x11_extension.h" #include "ui/platform_window/platform_window_init_properties.h" @@ -159,12 +160,22 @@ base::OnceClosure DesktopWindowTreeHostLinux::DisableEventListening() { } ui::WaylandExtension* DesktopWindowTreeHostLinux::GetWaylandExtension() { - return ui::GetWaylandExtension(*(platform_window())); + return platform_window() ? ui::GetWaylandExtension(*(platform_window())) + : nullptr; } const ui::WaylandExtension* DesktopWindowTreeHostLinux::GetWaylandExtension() const { - return ui::GetWaylandExtension(*(platform_window())); + return platform_window() ? ui::GetWaylandExtension(*(platform_window())) + : nullptr; +} + +ui::DeskExtension* DesktopWindowTreeHostLinux::GetDeskExtension() { + return ui::GetDeskExtension(*(platform_window())); +} + +const ui::DeskExtension* DesktopWindowTreeHostLinux::GetDeskExtension() const { + return ui::GetDeskExtension(*(platform_window())); } void DesktopWindowTreeHostLinux::Init(const Widget::InitParams& params) { @@ -216,11 +227,6 @@ Widget::MoveLoopResult DesktopWindowTreeHostLinux::RunMoveLoop( } void DesktopWindowTreeHostLinux::DispatchEvent(ui::Event* event) { - // The input can be disabled and the widget marked as non-active in case of - // opened file-dialogs. - if (event->IsKeyEvent() && !native_widget_delegate()->AsWidget()->IsActive()) - return; - // In Windows, the native events sent to chrome are separated into client // and non-client versions of events, which we record on our LocatedEvent // structures. On X11/Wayland, we emulate the concept of non-client. Before we @@ -295,11 +301,13 @@ void DesktopWindowTreeHostLinux::OnActivationChanged(bool active) { } ui::X11Extension* DesktopWindowTreeHostLinux::GetX11Extension() { - return ui::GetX11Extension(*(platform_window())); + return platform_window() ? ui::GetX11Extension(*(platform_window())) + : nullptr; } const ui::X11Extension* DesktopWindowTreeHostLinux::GetX11Extension() const { - return ui::GetX11Extension(*(platform_window())); + return platform_window() ? ui::GetX11Extension(*(platform_window())) + : nullptr; } #if BUILDFLAG(USE_ATK) @@ -312,7 +320,7 @@ bool DesktopWindowTreeHostLinux::OnAtkKeyEvent(AtkKeyEventStruct* atk_event, } #endif -bool DesktopWindowTreeHostLinux::IsOverrideRedirect(bool is_tiling_wm) const { +bool DesktopWindowTreeHostLinux::IsOverrideRedirect() const { // BrowserDesktopWindowTreeHostLinux implements this for browser windows. return false; } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h index 49c2776892f..dec3dd21f77 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h @@ -24,6 +24,7 @@ class ScopedWindowTargeter; } // namespace aura namespace ui { +class DeskExtension; class X11Extension; class WaylandExtension; } // namespace ui @@ -73,6 +74,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux ui::WaylandExtension* GetWaylandExtension(); const ui::WaylandExtension* GetWaylandExtension() const; + ui::DeskExtension* GetDeskExtension(); + const ui::DeskExtension* GetDeskExtension() const; + protected: // Overridden from DesktopWindowTreeHost: void Init(const Widget::InitParams& params) override; @@ -115,7 +119,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux #if BUILDFLAG(USE_ATK) bool OnAtkKeyEvent(AtkKeyEventStruct* atk_key_event, bool transient) override; #endif - bool IsOverrideRedirect(bool is_tiling_wm) const override; + bool IsOverrideRedirect() const override; // Enables event listening after closing |dialog|. void EnableEventListening(); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc index 6567106c963..fc19ea7df85 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc @@ -45,7 +45,6 @@ bool IsNonClientComponent(int hittest) { default: return false; } - return true; } #if defined(USE_X11) @@ -72,10 +71,12 @@ void DispatchMouseMotionEvent(DesktopWindowTreeHostLinux* desktop_host, .detail = x11::Motion::Normal, .root = connection->default_root(), .event = static_cast<x11::Window>(desktop_host->GetAcceleratedWidget()), - .root_x = point_in_screen.x(), - .root_y = point_in_screen.y(), - .event_x = point_in_screen.x() - bounds_in_screen.x(), - .event_y = point_in_screen.y() - bounds_in_screen.y(), + .root_x = static_cast<int16_t>(point_in_screen.x()), + .root_y = static_cast<int16_t>(point_in_screen.y()), + .event_x = + static_cast<int16_t>(point_in_screen.x() - bounds_in_screen.x()), + .event_y = + static_cast<int16_t>(point_in_screen.y() - bounds_in_screen.y()), .same_screen = true, }; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc index a250b77813f..51c32303d2f 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc @@ -129,10 +129,9 @@ ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties( ui::OzonePlatform::GetInstance() ->GetPlatformProperties() .set_parent_for_non_top_level_windows) { - // If the parent has not been provided, but there is context, use the - // context's widget as the parent of a new platform window. - if (params.context && params.context->GetHost() && - !properties.parent_widget) { + // If context has been set, use that as the parent_widget so that Wayland + // creates a correct hierarchy of windows. + if (params.context && params.context->GetHost()) { properties.parent_widget = params.context->GetHost()->GetAcceleratedWidget(); } @@ -221,9 +220,8 @@ void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) { // Disable compositing on tooltips as a workaround for // https://crbug.com/442111. - CreateCompositor(viz::FrameSinkId(), - params.force_software_compositing || - params.type == Widget::InitParams::TYPE_TOOLTIP); + CreateCompositor(params.force_software_compositing || + params.type == Widget::InitParams::TYPE_TOOLTIP); WindowTreeHost::OnAcceleratedWidgetAvailable(); InitHost(); @@ -748,8 +746,9 @@ void DesktopWindowTreeHostPlatform::OnClosed() { } void DesktopWindowTreeHostPlatform::OnWindowStateChanged( + ui::PlatformWindowState old_state, ui::PlatformWindowState new_state) { - bool was_minimized = old_state_ == ui::PlatformWindowState::kMinimized; + bool was_minimized = old_state == ui::PlatformWindowState::kMinimized; bool is_minimized = new_state == ui::PlatformWindowState::kMinimized; // Propagate minimization/restore to compositor to avoid drawing 'blank' @@ -765,8 +764,6 @@ void DesktopWindowTreeHostPlatform::OnWindowStateChanged( } } - old_state_ = new_state; - // Now that we have different window properties, we may need to relayout the // window. (The windows code doesn't need this because their window change is // synchronous.) @@ -810,6 +807,10 @@ SkPath DesktopWindowTreeHostPlatform::GetWindowMaskForWindowShapeInPixels() { return window_mask; } +absl::optional<ui::MenuType> DesktopWindowTreeHostPlatform::GetMenuType() { + return GetContentWindow()->GetProperty(aura::client::kMenuType); +} + void DesktopWindowTreeHostPlatform::OnWorkspaceChanged() { OnHostWorkspaceChanged(); } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h index b904b4f41cc..d1e8528638c 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h @@ -119,13 +119,15 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform // PlatformWindowDelegate: void OnClosed() override; - void OnWindowStateChanged(ui::PlatformWindowState new_state) override; + void OnWindowStateChanged(ui::PlatformWindowState old_state, + ui::PlatformWindowState new_state) override; void OnCloseRequest() override; void OnWillDestroyAcceleratedWidget() override; void OnActivationChanged(bool active) override; absl::optional<gfx::Size> GetMinimumSizeForWindow() override; absl::optional<gfx::Size> GetMaximumSizeForWindow() override; SkPath GetWindowMaskForWindowShapeInPixels() override; + absl::optional<ui::MenuType> GetMenuType() override; // ui::WorkspaceExtensionDelegate: void OnWorkspaceChanged() override; @@ -140,8 +142,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform return desktop_native_widget_aura_; } - ui::PlatformWindowState window_show_state() { return old_state_; } - // These are not general purpose methods and must be used with care. Please // make sure you understand the rounding direction before using. gfx::Rect ToDIPRect(const gfx::Rect& rect_in_pixels) const; @@ -180,11 +180,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform DesktopWindowTreeHostPlatform* window_parent_ = nullptr; std::set<DesktopWindowTreeHostPlatform*> window_children_; - // Keep track of PlatformWindow state so that we would react correctly and set - // visibility only if the window was minimized or was unminimized from the - // normal state. - ui::PlatformWindowState old_state_ = ui::PlatformWindowState::kUnknown; - // Used for tab dragging in move loop requests. WindowMoveClientPlatform window_move_client_; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc index 51cbb691d8e..40dff77d828 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc @@ -162,12 +162,14 @@ TEST_F(DesktopWindowTreeHostPlatformTest, EXPECT_TRUE(widget->GetNativeWindow()->IsVisible()); // Pretend a PlatformWindow enters the minimized state. - host_platform->OnWindowStateChanged(ui::PlatformWindowState::kMinimized); + host_platform->OnWindowStateChanged(ui::PlatformWindowState::kUnknown, + ui::PlatformWindowState::kMinimized); EXPECT_FALSE(widget->GetNativeWindow()->IsVisible()); // Pretend a PlatformWindow exits the minimized state. - host_platform->OnWindowStateChanged(ui::PlatformWindowState::kNormal); + host_platform->OnWindowStateChanged(ui::PlatformWindowState::kMinimized, + ui::PlatformWindowState::kNormal); EXPECT_TRUE(widget->GetNativeWindow()->IsVisible()); } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc index fb8bbb639f6..042fb2b5d16 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc @@ -66,6 +66,14 @@ namespace views { namespace { +// While the mouse is locked we want the invisible mouse to stay within the +// confines of the screen so we keep it in a capture region the size of the +// screen. However, on windows when the mouse hits the edge of the screen some +// events trigger and cause strange issues to occur. To stop those events from +// occurring we add a small border around the edge of the capture region. +// This constant controls how many pixels wide that border is. +const int kMouseCaptureRegionBorder = 5; + gfx::Size GetExpandedWindowSize(bool is_translucent, gfx::Size size) { if (!is_translucent || !ui::win::IsAeroGlassEnabled()) return size; @@ -80,6 +88,24 @@ void InsetBottomRight(gfx::Rect* rect, const gfx::Vector2d& vector) { rect->Inset(0, 0, vector.x(), vector.y()); } +// Updates the cursor clip region. Used for mouse locking. +void UpdateMouseLockRegion(aura::Window* window, bool locked) { + if (!locked) { + ::ClipCursor(nullptr); + return; + } + + RECT window_rect = + display::Screen::GetScreen() + ->DIPToScreenRectInWindow(window, window->GetBoundsInScreen()) + .ToRECT(); + window_rect.left += kMouseCaptureRegionBorder; + window_rect.right -= kMouseCaptureRegionBorder; + window_rect.top += kMouseCaptureRegionBorder; + window_rect.bottom -= kMouseCaptureRegionBorder; + ::ClipCursor(&window_rect); +} + } // namespace DEFINE_UI_CLASS_PROPERTY_KEY(aura::Window*, kContentWindowForRootWindow, NULL) @@ -124,10 +150,20 @@ aura::Window* DesktopWindowTreeHostWin::GetContentWindowForHWND(HWND hwnd) { return host ? host->window()->GetProperty(kContentWindowForRootWindow) : NULL; } -void DesktopWindowTreeHostWin::SetInTouchDrag(bool in_touch_drag) { - in_touch_drag_ = in_touch_drag; +void DesktopWindowTreeHostWin::StartTouchDrag(gfx::Point screen_point) { + // Send a mouse down and mouse move before do drag drop runs its own event + // loop. This is required for ::DoDragDrop to start the drag. + ui::SendMouseEvent(screen_point, MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE); + ui::SendMouseEvent(screen_point, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE); + in_touch_drag_ = true; } +void DesktopWindowTreeHostWin::FinishTouchDrag(gfx::Point screen_point) { + if (in_touch_drag_) { + in_touch_drag_ = false; + ui::SendMouseEvent(screen_point, MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE); + } +} //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostWin, DesktopWindowTreeHost implementation: @@ -155,7 +191,7 @@ void DesktopWindowTreeHostWin::Init(const Widget::InitParams& params) { gfx::Rect pixel_bounds = display::win::ScreenWin::DIPToScreenRect(nullptr, params.bounds); message_handler_->Init(parent_hwnd, pixel_bounds); - CreateCompositor(viz::FrameSinkId(), params.force_software_compositing); + CreateCompositor(params.force_software_compositing); OnAcceleratedWidgetAvailable(); InitHost(); window()->Show(); @@ -663,6 +699,16 @@ DesktopWindowTreeHostWin::RequestUnadjustedMovement() { return message_handler_->RegisterUnadjustedMouseEvent(); } +void DesktopWindowTreeHostWin::LockMouse(aura::Window* window) { + UpdateMouseLockRegion(window, true /*locked*/); + WindowTreeHost::LockMouse(window); +} + +void DesktopWindowTreeHostWin::UnlockMouse(aura::Window* window) { + UpdateMouseLockRegion(window, false /*locked*/); + WindowTreeHost::UnlockMouse(window); +} + //////////////////////////////////////////////////////////////////////////////// // DesktopWindowTreeHostWin, wm::AnimationHost implementation: @@ -892,10 +938,6 @@ void DesktopWindowTreeHostWin::HandleWorkAreaChanged() { GetWidget()->widget_delegate()->OnWorkAreaChanged(); } -void DesktopWindowTreeHostWin::HandleVisibilityChanging(bool visible) { - native_widget_delegate_->OnNativeWidgetVisibilityChanging(visible); -} - void DesktopWindowTreeHostWin::HandleVisibilityChanged(bool visible) { native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible); } @@ -987,7 +1029,6 @@ void DesktopWindowTreeHostWin::HandleTouchEvent(ui::TouchEvent* event) { // by the time we attempt to process them. if (!GetWidget()->GetNativeView()) return; - if (in_touch_drag_) { POINT event_point; event_point.x = event->location().x(); @@ -999,10 +1040,19 @@ void DesktopWindowTreeHostWin::HandleTouchEvent(ui::TouchEvent* event) { if (event->type() == ui::ET_TOUCH_MOVED) { ui::SendMouseEvent(screen_point, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE); } else if (event->type() == ui::ET_TOUCH_RELEASED) { - ui::SendMouseEvent(screen_point, - MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE); + FinishTouchDrag(screen_point); } } + // TODO(crbug.com/229301) Calling ::SetCursorPos for ui::ET_TOUCH_PRESSED + // events here would fix web ui tab strip drags when the cursor is not over + // the Chrome window - The TODO is to figure out if that's reasonable, since + // it would change the cursor pos on every touch event. Or figure out if there + // is a less intrusive way of fixing the cursor position. If we can do that, + // we can remove the call to ::SetCursorPos in + // DesktopDragDropClientWin::StartDragAndDrop. Note that calling SetCursorPos + // at the start of StartDragAndDrop breaks touch drag and drop, so it has to + // be called some time before we get to StartDragAndDrop. + // Currently we assume the window that has capture gets touch events too. aura::WindowTreeHost* host = aura::WindowTreeHost::GetForAcceleratedWidget(GetCapture()); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h index 07078cbdf22..db129908916 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h @@ -59,11 +59,35 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin // A way of converting an HWND into a content window. static aura::Window* GetContentWindowForHWND(HWND hwnd); - // Set to true when DesktopDragDropClientWin starts a touch-initiated drag - // drop and false when it finishes. While in touch drag, if pointer events are - // received, the equivalent mouse events are generated, because ole32 - // ::DoDragDrop does not seem to handle pointer events. - void SetInTouchDrag(bool in_touch_drag); + // When DesktopDragDropClientWin starts a touch-initiated drag, it calls + // this method to record that we're in touch drag mode, and synthesizes + // right mouse button down and move events to get ::DoDragDrop started. + void StartTouchDrag(gfx::Point screen_point); + + // If in touch drag mode, this method synthesizes a left mouse button up + // event to match the left mouse button down event in StartTouchDrag. It + // also restores the cursor pos to where the drag started, to avoid leaving + // the cursor outside the Chrome window doing the drag drop. This allows + // subsequent touch drag drops to succeed. Touch drag drop requires that + // the cursor be over the same window as the touch drag point. + // This needs to be called in two cases: + // 1. The normal case is that ::DoDragDrop starts, we get touch move events, + // which we turn into mouse move events, and then we get a touch release + // event. Calling FinishTouchDragIfInDrag generates a mouse up, which stops + // the drag drop. + // 2. ::DoDragDrop exits immediately, w/o us handling any touch events. In + // this case, FinishTouchDragIfInDrag makes sure we have a mouse button up to + // match the mouse button down, because we won't get a touch release event. We + // don't know for sure if ::DoDragDrop exited immediately, other than by + // checking if `in_touch_drag_` has been set to false. + // + // So, we always call FinishTouchDragIfInDrag after ::DoDragDrop exits, to + // make sure it gets called, and we make it handle getting called multiple + // times. Most of the time, FinishTouchDrag will have already been called when + // we get a touch release event, in which case the second call needs to be a + // noop, which is accomplished by checking if `in_touch_drag_` is already + // false. + void FinishTouchDrag(gfx::Point screen_point); protected: // Overridden from DesktopWindowTreeHost: @@ -152,6 +176,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin const gfx::Point& location_in_pixels) override; std::unique_ptr<aura::ScopedEnableUnadjustedMouseEvents> RequestUnadjustedMovement() override; + void LockMouse(aura::Window* window) override; + void UnlockMouse(aura::Window* window) override; // Overridden from aura::client::AnimationHost void SetHostTransitionOffsets( @@ -200,7 +226,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin void HandleEndWMSizeMove() override; void HandleMove() override; void HandleWorkAreaChanged() override; - void HandleVisibilityChanging(bool visible) override; void HandleVisibilityChanged(bool visible) override; void HandleWindowMinimizedOrRestored(bool restored) override; void HandleClientSizeChanged(const gfx::Size& new_size) override; @@ -316,6 +341,12 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin // when that stat is no longer tracked. gfx::Point occluded_window_mouse_event_loc_; + // Set to true when DesktopDragDropClientWin starts a touch-initiated drag + // drop and false when it finishes. While in touch drag, if touch move events + // are received, the equivalent mouse events are generated, because ole32 + // ::DoDragDrop does not seem to handle touch events. WinRT drag drop does + // support touch, but we've been unable to use it in Chrome. See + // https://crbug.com/1236783 for more info. bool in_touch_drag_ = false; // The z-order level of the window; the window exhibits "always on top" diff --git a/chromium/ui/views/widget/drop_helper.cc b/chromium/ui/views/widget/drop_helper.cc index ce8f2d7741a..207276dee55 100644 --- a/chromium/ui/views/widget/drop_helper.cc +++ b/chromium/ui/views/widget/drop_helper.cc @@ -6,6 +6,7 @@ #include <memory> #include <set> +#include <utility> #include "base/bind.h" #include "base/callback.h" @@ -14,6 +15,7 @@ #include "build/build_config.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" +#include "ui/views/view.h" #include "ui/views/widget/widget.h" namespace views { @@ -102,7 +104,7 @@ DragOperation DropHelper::OnDrop(const OSExchangeData& data, return drop_view->OnPerformDrop(drop_event); } -View::DropCallback DropHelper::GetDropCallback( +DropHelper::DropCallback DropHelper::GetDropCallback( const OSExchangeData& data, const gfx::Point& root_view_location, int drag_operation) { @@ -121,7 +123,15 @@ View::DropCallback DropHelper::GetDropCallback( View::ConvertPointToTarget(root_view, drop_view, &view_location); ui::DropTargetEvent drop_event(data, gfx::PointF(view_location), gfx::PointF(view_location), drag_operation); - return drop_view->GetDropCallback(drop_event); + + auto drop_view_cb = drop_view->GetDropCallback(drop_event); + return base::BindOnce( + [](View::DropCallback drop_cb, const ui::DropTargetEvent& event, + std::unique_ptr<ui::OSExchangeData> data, + ui::mojom::DragOperation& output_drag_op) { + std::move(drop_cb).Run(event, output_drag_op); + }, + std::move(drop_view_cb)); } View* DropHelper::CalculateTargetView(const gfx::Point& root_view_location, diff --git a/chromium/ui/views/widget/drop_helper.h b/chromium/ui/views/widget/drop_helper.h index f361de1408a..d991dc129e5 100644 --- a/chromium/ui/views/widget/drop_helper.h +++ b/chromium/ui/views/widget/drop_helper.h @@ -5,6 +5,7 @@ #ifndef UI_VIEWS_WIDGET_DROP_HELPER_H_ #define UI_VIEWS_WIDGET_DROP_HELPER_H_ +#include <memory> #include "base/callback_forward.h" #include "base/macros.h" @@ -32,6 +33,11 @@ class RootView; // then either OnDragExit or OnDrop when the drop is done. class VIEWS_EXPORT DropHelper { public: + using DropCallback = + base::OnceCallback<void(const ui::DropTargetEvent& event, + std::unique_ptr<ui::OSExchangeData> data, + ui::mojom::DragOperation& output_drag_op)>; + explicit DropHelper(View* root_view); ~DropHelper(); @@ -76,9 +82,9 @@ class VIEWS_EXPORT DropHelper { // Invoked when the user drops data on the root view during a drag and drop // operation, but the drop is held because of DataTransferPolicController. - View::DropCallback GetDropCallback(const OSExchangeData& data, - const gfx::Point& root_view_location, - int drag_operation); + DropCallback GetDropCallback(const OSExchangeData& data, + const gfx::Point& root_view_location, + int drag_operation); // Calculates the target view for a drop given the specified location in // the coordinate system of the rootview. This tries to avoid continually diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc index 3b63e2b9883..c2ca1c6bf4a 100644 --- a/chromium/ui/views/widget/native_widget_aura.cc +++ b/chromium/ui/views/widget/native_widget_aura.cc @@ -256,7 +256,7 @@ void NativeWidgetAura::InitNativeWidget(Widget::InitParams params) { // Wait to set the bounds until we have a parent. That way we can know our // true state/bounds (the LayoutManager may enforce a particular // state/bounds). - if (IsMaximized()) + if (IsMaximized() || IsMinimized()) SetRestoreBounds(window_, window_bounds); else SetBounds(window_bounds); @@ -456,6 +456,14 @@ void NativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon, AssignIconToAuraWindow(window_, window_icon, app_icon); } +const gfx::ImageSkia* NativeWidgetAura::GetWindowIcon() { + return window_->GetProperty(aura::client::kWindowIconKey); +} + +const gfx::ImageSkia* NativeWidgetAura::GetWindowAppIcon() { + return window_->GetProperty(aura::client::kAppIconKey); +} + void NativeWidgetAura::InitModalType(ui::ModalType modal_type) { if (modal_type != ui::MODAL_TYPE_NONE) window_->SetProperty(aura::client::kModalKey, modal_type); @@ -597,8 +605,11 @@ void NativeWidgetAura::Show(ui::WindowShowState show_state, if (!window_) return; - if (show_state == ui::SHOW_STATE_MAXIMIZED && !restore_bounds.IsEmpty()) + if ((show_state == ui::SHOW_STATE_MAXIMIZED || + show_state == ui::SHOW_STATE_MINIMIZED) && + !restore_bounds.IsEmpty()) { SetRestoreBounds(window_, restore_bounds); + } if (show_state == ui::SHOW_STATE_MAXIMIZED || show_state == ui::SHOW_STATE_FULLSCREEN) { window_->SetProperty(aura::client::kShowStateKey, show_state); @@ -700,7 +711,8 @@ void NativeWidgetAura::Restore() { window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); } -void NativeWidgetAura::SetFullscreen(bool fullscreen) { +void NativeWidgetAura::SetFullscreen(bool fullscreen, + const base::TimeDelta& delay) { if (!window_ || IsFullscreen() == fullscreen) return; // Nothing to do. @@ -723,10 +735,8 @@ void NativeWidgetAura::SetOpacity(float opacity) { void NativeWidgetAura::SetAspectRatio(const gfx::SizeF& aspect_ratio) { DCHECK(!aspect_ratio.IsEmpty()); if (window_) { - // aura::client::kAspectRatio is owned, which allows for passing in this - // raw pointer. - window_->SetProperty(aura::client::kAspectRatio, - new gfx::SizeF(aspect_ratio)); + // aura::client::kAspectRatio is owned, which allows for passing by value. + window_->SetProperty(aura::client::kAspectRatio, gfx::SizeF(aspect_ratio)); } } @@ -1103,9 +1113,9 @@ ui::mojom::DragOperation NativeWidgetAura::OnPerformDrop( aura::client::DragDropDelegate::DropCallback NativeWidgetAura::GetDropCallback( const ui::DropTargetEvent& event) { - // TODO(crbug.com/1197506): Return async drop callback function. - NOTIMPLEMENTED(); - return base::NullCallback(); + DCHECK(drop_helper_); + return drop_helper_->GetDropCallback(event.data(), event.location(), + last_drop_operation_); } //////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h index db6effaafce..fac71091f08 100644 --- a/chromium/ui/views/widget/native_widget_aura.h +++ b/chromium/ui/views/widget/native_widget_aura.h @@ -23,7 +23,7 @@ #include "ui/wm/public/activation_delegate.h" #if defined(OS_MAC) -#error This file must not be included on macOS; Chromium Mac doesn't use Aura. +#error "This file must not be included on macOS; Chromium Mac doesn't use Aura." #endif namespace aura { @@ -97,6 +97,8 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate, bool SetWindowTitle(const std::u16string& title) override; void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) override; + const gfx::ImageSkia* GetWindowIcon() override; + const gfx::ImageSkia* GetWindowAppIcon() override; void InitModalType(ui::ModalType modal_type) override; gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; @@ -126,7 +128,7 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate, bool IsMaximized() const override; bool IsMinimized() const override; void Restore() override; - void SetFullscreen(bool fullscreen) override; + void SetFullscreen(bool fullscreen, const base::TimeDelta& delay) override; bool IsFullscreen() const override; void SetCanAppearInExistingFullscreenSpaces( bool can_appear_in_existing_fullscreen_spaces) override; diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc index 4f442a6697e..a1f27a016fb 100644 --- a/chromium/ui/views/widget/native_widget_aura_unittest.cc +++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc @@ -793,5 +793,30 @@ TEST_F(NativeWidgetAuraTest, TransientChildModalWindowVisibility) { EXPECT_TRUE(child.IsVisible()); } +// Tests that widgets that are created minimized have the correct restore +// bounds. +TEST_F(NativeWidgetAuraTest, MinimizedWidgetRestoreBounds) { + const gfx::Rect restore_bounds(300, 300); + + Widget widget; + Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); + params.context = root_window(); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.show_state = ui::SHOW_STATE_MINIMIZED; + params.bounds = restore_bounds; + + widget.Init(std::move(params)); + widget.Show(); + + aura::Window* window = widget.GetNativeWindow(); + EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, + window->GetProperty(aura::client::kShowStateKey)); + EXPECT_EQ(restore_bounds, + *window->GetProperty(aura::client::kRestoreBoundsKey)); + + widget.Restore(); + EXPECT_EQ(restore_bounds, window->bounds()); +} + } // namespace } // namespace views diff --git a/chromium/ui/views/widget/native_widget_delegate.h b/chromium/ui/views/widget/native_widget_delegate.h index 12e70210788..fbfefa1e8e5 100644 --- a/chromium/ui/views/widget/native_widget_delegate.h +++ b/chromium/ui/views/widget/native_widget_delegate.h @@ -49,9 +49,6 @@ class VIEWS_EXPORT NativeWidgetDelegate { // Returns true if the window can be activated. virtual bool CanActivate() const = 0; - // Returns true if the window should paint as active. - virtual bool ShouldPaintAsActive() const = 0; - // Returns true if the native widget has been initialized. virtual bool IsNativeWidgetInitialized() const = 0; @@ -63,9 +60,6 @@ class VIEWS_EXPORT NativeWidgetDelegate { virtual void OnNativeFocus() = 0; virtual void OnNativeBlur() = 0; - // Called when the window is about to be shown/hidden. - virtual void OnNativeWidgetVisibilityChanging(bool visible) = 0; - // Called when the window is shown/hidden. virtual void OnNativeWidgetVisibilityChanged(bool visible) = 0; diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h index 088c98a89b7..ae792308167 100644 --- a/chromium/ui/views/widget/native_widget_mac.h +++ b/chromium/ui/views/widget/native_widget_mac.h @@ -8,7 +8,6 @@ #include <memory> #include <string> -#include "base/macros.h" #include "ui/base/ime/input_method_delegate.h" #include "ui/base/window_open_disposition.h" #include "ui/gfx/native_widget_types.h" @@ -26,16 +25,17 @@ class CreateWindowParams; class NativeWidgetNSWindow; class ValidateUserInterfaceItemResult; } // namespace mojom + class ApplicationHost; class NativeWidgetNSWindowBridge; } // namespace remote_cocoa namespace views { namespace test { -class HitTestNativeWidgetMac; class MockNativeWidgetMac; -class WidgetTest; +class NativeWidgetMacTest; } // namespace test + class NativeWidgetMacNSWindowHost; class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate, @@ -43,6 +43,8 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate, public ui::internal::InputMethodDelegate { public: explicit NativeWidgetMac(internal::NativeWidgetDelegate* delegate); + NativeWidgetMac(const NativeWidgetMac&) = delete; + NativeWidgetMac& operator=(const NativeWidgetMac&) = delete; ~NativeWidgetMac() override; // Informs |delegate_| that the native widget is about to be destroyed. @@ -128,6 +130,8 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate, bool SetWindowTitle(const std::u16string& title) override; void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) override; + const gfx::ImageSkia* GetWindowIcon() override; + const gfx::ImageSkia* GetWindowAppIcon() override; void InitModalType(ui::ModalType modal_type) override; gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; @@ -157,7 +161,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate, bool IsMaximized() const override; bool IsMinimized() const override; void Restore() override; - void SetFullscreen(bool fullscreen) override; + void SetFullscreen(bool fullscreen, const base::TimeDelta& delay) override; bool IsFullscreen() const override; void SetCanAppearInExistingFullscreenSpaces( bool can_appear_in_existing_fullscreen_spaces) override; @@ -256,8 +260,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate, private: friend class test::MockNativeWidgetMac; - friend class test::HitTestNativeWidgetMac; - friend class views::test::WidgetTest; + friend class views::test::NativeWidgetMacTest; class ZoomFocusMonitor; internal::NativeWidgetDelegate* delegate_; @@ -279,8 +282,6 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate, std::unique_ptr<ZoomFocusMonitor> zoom_focus_monitor_; // Held while this widget is active if it's a child. std::unique_ptr<Widget::PaintAsActiveLock> parent_key_lock_; - - DISALLOW_COPY_AND_ASSIGN(NativeWidgetMac); }; } // namespace views diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm index 51358d11989..1a066e4e40c 100644 --- a/chromium/ui/views/widget/native_widget_mac.mm +++ b/chromium/ui/views/widget/native_widget_mac.mm @@ -11,24 +11,24 @@ #include <utility> #include "base/base64.h" -#include "base/bind.h" +#include "base/callback.h" #include "base/mac/scoped_nsobject.h" #include "base/no_destructor.h" #include "base/strings/sys_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" #include "components/crash/core/common/crash_key.h" #import "components/remote_cocoa/app_shim/bridged_content_view.h" #import "components/remote_cocoa/app_shim/native_widget_mac_nswindow.h" #import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h" #import "components/remote_cocoa/app_shim/views_nswindow_delegate.h" -#import "ui/base/cocoa/constrained_window/constrained_window_animation.h" #import "ui/base/cocoa/window_size_constants.h" #include "ui/base/ime/init/input_method_factory.h" #include "ui/base/ime/input_method.h" #include "ui/compositor/layer.h" #include "ui/display/display.h" #include "ui/display/screen.h" +#include "ui/events/gestures/gesture_recognizer.h" #include "ui/events/gestures/gesture_recognizer_impl_mac.h" +#include "ui/events/gestures/gesture_types.h" #include "ui/gfx/font_list.h" #import "ui/gfx/mac/coordinate_conversion.h" #include "ui/native_theme/native_theme.h" @@ -37,6 +37,7 @@ #import "ui/views/cocoa/native_widget_mac_ns_window_host.h" #include "ui/views/cocoa/text_input_host.h" #include "ui/views/widget/drop_helper.h" +#include "ui/views/widget/native_widget_delegate.h" #include "ui/views/widget/widget_aura_utils.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/window/native_frame_view.h" @@ -158,14 +159,6 @@ void NativeWidgetMac::OnWindowKeyStatusChanged( if (is_key) { widget->OnNativeFocus(); widget->GetFocusManager()->RestoreFocusedView(); - if (NativeWidgetMacNSWindowHost* parent_host = ns_window_host_->parent()) { - // Unclear under what circumstances this would be null, but speculatively - // working around https://crbug/1050430 - if (Widget* top_widget = - parent_host->native_widget_mac()->GetTopLevelWidget()) { - parent_key_lock_ = top_widget->LockPaintAsActive(); - } - } } else { widget->OnNativeBlur(); widget->GetFocusManager()->StoreFocusedView(true); @@ -412,6 +405,15 @@ void NativeWidgetMac::InitModalType(ui::ModalType modal_type) { // Everything happens upon show. } +const gfx::ImageSkia* NativeWidgetMac::GetWindowIcon() { + NOTIMPLEMENTED_LOG_ONCE(); + return nullptr; +} +const gfx::ImageSkia* NativeWidgetMac::GetWindowAppIcon() { + NOTIMPLEMENTED_LOG_ONCE(); + return nullptr; +} + gfx::Rect NativeWidgetMac::GetWindowBoundsInScreen() const { return ns_window_host_ ? ns_window_host_->GetWindowBoundsInScreen() : gfx::Rect(); @@ -644,10 +646,11 @@ void NativeWidgetMac::Restore() { GetNSWindowMojo()->SetMiniaturized(false); } -void NativeWidgetMac::SetFullscreen(bool fullscreen) { +void NativeWidgetMac::SetFullscreen(bool fullscreen, + const base::TimeDelta& delay) { if (!ns_window_host_) return; - ns_window_host_->SetFullscreen(fullscreen); + ns_window_host_->SetFullscreen(fullscreen, delay); } bool NativeWidgetMac::IsFullscreen() const { @@ -899,9 +902,10 @@ void NativeWidgetMac::OnDidChangeFocus(View* focused_before, ui::TextInputClient* new_text_input_client = input_method->GetTextInputClient(); - // Sanity check: When focus moves away from the widget (i.e. |focused_now| - // is nil), then the textInputClient will be cleared. - DCHECK(!!focused_now || !new_text_input_client); + // Sanity check: For a top level widget, when focus moves away from the widget + // (i.e. |focused_now| is nil), then the textInputClient will be cleared. + DCHECK(!!focused_now || !new_text_input_client || + !GetWidget()->is_top_level()); if (ns_window_host_) { ns_window_host_->text_input_host()->SetTextInputClient( new_text_input_client); diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm index cb78da742ed..4ff63b522fb 100644 --- a/chromium/ui/views/widget/native_widget_mac_unittest.mm +++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm @@ -198,6 +198,10 @@ class NativeWidgetMacTest : public WidgetTest { return widget; } + FocusManager* GetFocusManager(NativeWidgetMac* native_widget) const { + return native_widget->focus_manager_; + } + private: DISALLOW_COPY_AND_ASSIGN(NativeWidgetMacTest); }; @@ -2354,6 +2358,23 @@ TEST_F(NativeWidgetMacTest, InitCallback) { widget_c->CloseNow(); } +TEST_F(NativeWidgetMacTest, FocusManagerChangeOnReparentNativeView) { + WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget()); + Widget* child = CreateChildPlatformWidget(toplevel->GetNativeView()); + WidgetAutoclosePtr target_toplevel(CreateTopLevelPlatformWidget()); + EXPECT_EQ(child->GetFocusManager(), toplevel->GetFocusManager()); + EXPECT_NE(child->GetFocusManager(), target_toplevel->GetFocusManager()); + NativeWidgetMac* child_native_widget = + static_cast<NativeWidgetMac*>(child->native_widget()); + EXPECT_EQ(GetFocusManager(child_native_widget), child->GetFocusManager()); + + Widget::ReparentNativeView(child->GetNativeView(), + target_toplevel->GetNativeView()); + EXPECT_EQ(child->GetFocusManager(), target_toplevel->GetFocusManager()); + EXPECT_NE(child->GetFocusManager(), toplevel->GetFocusManager()); + EXPECT_EQ(GetFocusManager(child_native_widget), child->GetFocusManager()); +} + } // namespace test } // namespace views diff --git a/chromium/ui/views/widget/native_widget_private.h b/chromium/ui/views/widget/native_widget_private.h index 5738ffb8604..80635de4196 100644 --- a/chromium/ui/views/widget/native_widget_private.h +++ b/chromium/ui/views/widget/native_widget_private.h @@ -160,6 +160,8 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget { // app switching UI. virtual void SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) = 0; + virtual const gfx::ImageSkia* GetWindowIcon() = 0; + virtual const gfx::ImageSkia* GetWindowAppIcon() = 0; // Initializes the modal type of the window to |modal_type|. Called from // NativeWidgetDelegate::OnNativeWidgetCreated() before the widget is @@ -195,7 +197,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget { virtual bool IsMaximized() const = 0; virtual bool IsMinimized() const = 0; virtual void Restore() = 0; - virtual void SetFullscreen(bool fullscreen) = 0; + virtual void SetFullscreen(bool fullscreen, const base::TimeDelta& delay) = 0; virtual bool IsFullscreen() const = 0; virtual void SetCanAppearInExistingFullscreenSpaces( bool can_appear_in_existing_fullscreen_spaces) = 0; diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc index 14e2830ae4d..48ec8693ef5 100644 --- a/chromium/ui/views/widget/root_view.cc +++ b/chromium/ui/views/widget/root_view.cc @@ -209,7 +209,7 @@ RootView::RootView(Widget* widget) RootView::~RootView() { // If we have children remove them explicitly so to make sure a remove // notification is sent for each one of them. - RemoveAllChildViews(true); + RemoveAllChildViews(); } // Tree operations ------------------------------------------------------------- @@ -221,7 +221,7 @@ void RootView::SetContentsView(View* contents_view) { // Widget pointer is valid. SetUseDefaultFillLayout(true); if (!children().empty()) - RemoveAllChildViews(true); + RemoveAllChildViews(); AddChildView(contents_view); } diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc index 0dcab77ec0d..37047c631af 100644 --- a/chromium/ui/views/widget/widget.cc +++ b/chromium/ui/views/widget/widget.cc @@ -8,6 +8,7 @@ #include <utility> #include "base/auto_reset.h" +#include "base/bind.h" #include "base/check_op.h" #include "base/containers/adapters.h" #include "base/feature_list.h" @@ -22,6 +23,7 @@ #include "ui/base/ime/input_method.h" #include "ui/base/l10n/l10n_font_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/color/color_provider_manager.h" #include "ui/compositor/compositor.h" @@ -35,6 +37,7 @@ #include "ui/views/focus/focus_manager.h" #include "ui/views/focus/focus_manager_factory.h" #include "ui/views/focus/widget_focus_manager.h" +#include "ui/views/image_model_utils.h" #include "ui/views/views_delegate.h" #include "ui/views/views_features.h" #include "ui/views/widget/any_widget_observer_singleton.h" @@ -186,15 +189,23 @@ Widget::Widget(InitParams params) { Widget::~Widget() { if (widget_delegate_) widget_delegate_->WidgetDestroying(); - DestroyRootView(); if (ownership_ == InitParams::WIDGET_OWNS_NATIVE_WIDGET) { delete native_widget_; + DCHECK(native_widget_destroyed_); } else { // TODO(crbug.com/937381): Revert to DCHECK once we figure out the reason. CHECK(native_widget_destroyed_) << "Destroying a widget with a live native widget. " << "Widget probably should use WIDGET_OWNS_NATIVE_WIDGET ownership."; } + // Destroy RootView after the native widget, so in case the WidgetDelegate is + // a View in the RootView hierarchy it gets destroyed as a WidgetDelegate + // first. + // This makes destruction order for WidgetDelegate consistent between + // different Widget/NativeWidget ownership models (WidgetDelegate is always + // deleted before here, which may have removed it as a View from the + // View hierarchy). + DestroyRootView(); } // static @@ -276,8 +287,26 @@ void Widget::ReparentNativeView(gfx::NativeView native_view, Widget* child_widget = GetWidgetForNativeView(native_view); Widget* parent_widget = new_parent ? GetWidgetForNativeView(new_parent) : nullptr; - if (child_widget) + if (child_widget) { child_widget->parent_ = parent_widget; + + // Release the paint-as-active lock on the old parent. + bool has_lock_on_parent = !!child_widget->parent_paint_as_active_lock_; + child_widget->parent_paint_as_active_lock_.reset(); + child_widget->parent_paint_as_active_subscription_ = + base::CallbackListSubscription(); + + // Lock and subscribe to parent's paint-as-active. + if (parent_widget) { + if (has_lock_on_parent) + child_widget->parent_paint_as_active_lock_ = + parent_widget->LockPaintAsActive(); + child_widget->parent_paint_as_active_subscription_ = + parent_widget->RegisterPaintAsActiveChangedCallback( + base::BindRepeating(&Widget::OnParentShouldPaintAsActiveChanged, + base::Unretained(child_widget))); + } + } } // static @@ -321,6 +350,14 @@ void Widget::Init(InitParams params) { parent_ = params.parent ? GetWidgetForNativeView(params.parent) : nullptr; + // Subscripbe to parent's paint-as-active change. + if (parent_) { + parent_paint_as_active_subscription_ = + parent_->RegisterPaintAsActiveChangedCallback( + base::BindRepeating(&Widget::OnParentShouldPaintAsActiveChanged, + base::Unretained(this))); + } + params.child |= (params.type == InitParams::TYPE_CONTROL); is_top_level_ = !params.child; @@ -425,10 +462,14 @@ void Widget::ShowEmojiPanel() { // Unconverted methods (see header) -------------------------------------------- gfx::NativeView Widget::GetNativeView() const { + if (native_widget_destroyed_) + return gfx::kNullNativeView; return native_widget_->GetNativeView(); } gfx::NativeWindow Widget::GetNativeWindow() const { + if (native_widget_destroyed_) + return gfx::kNullNativeWindow; return native_widget_->GetNativeWindow(); } @@ -469,7 +510,8 @@ void Widget::ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) { FocusManager* focus_manager = GetFocusManager(); if (focus_manager) focus_manager->ViewRemoved(details.child); - native_widget_->ViewRemoved(details.child); + if (!native_widget_destroyed_) + native_widget_->ViewRemoved(details.child); } } @@ -480,11 +522,11 @@ void Widget::NotifyNativeViewHierarchyWillChange() { // to avoid these redundant steps and to avoid accessing deleted views // that may have been in focus. ClearFocusFromWidget(); - native_widget_->OnNativeViewHierarchyChanged(); + native_widget_->OnNativeViewHierarchyWillChange(); } void Widget::NotifyNativeViewHierarchyChanged() { - native_widget_->OnNativeViewHierarchyWillChange(); + native_widget_->OnNativeViewHierarchyChanged(); root_view_->NotifyNativeViewHierarchyChanged(); } @@ -505,7 +547,10 @@ const Widget* Widget::GetTopLevelWidget() const { // 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(); + if (is_top_level()) + return this; + return native_widget_destroyed_ ? nullptr + : native_widget_->GetTopLevelWidget(); } Widget* Widget::GetPrimaryWindowWidget() { @@ -769,12 +814,12 @@ bool Widget::IsMinimized() const { return native_widget_->IsMinimized(); } -void Widget::SetFullscreen(bool fullscreen) { +void Widget::SetFullscreen(bool fullscreen, base::TimeDelta delay) { if (IsFullscreen() == fullscreen) return; auto weak_ptr = GetWeakPtr(); - native_widget_->SetFullscreen(fullscreen); + native_widget_->SetFullscreen(fullscreen, delay); if (!weak_ptr) return; @@ -826,15 +871,13 @@ const ui::ThemeProvider* Widget::GetThemeProvider() const { const ui::ColorProvider* Widget::GetColorProvider() const { auto color_scheme = GetNativeTheme()->GetDefaultSystemColorScheme(); - auto theme_name = GetNativeTheme()->GetNativeThemeName(); return ui::ColorProviderManager::Get().GetColorProviderFor( {(color_scheme == ui::NativeTheme::ColorScheme::kDark) ? ui::ColorProviderManager::ColorMode::kDark : ui::ColorProviderManager::ColorMode::kLight, (color_scheme == ui::NativeTheme::ColorScheme::kPlatformHighContrast) ? ui::ColorProviderManager::ContrastMode::kHigh - : ui::ColorProviderManager::ContrastMode::kNormal, - std::move(theme_name)}); + : ui::ColorProviderManager::ContrastMode::kNormal}); } FocusManager* Widget::GetFocusManager() { @@ -895,6 +938,11 @@ void Widget::RunShellDrag(View* view, } void Widget::SchedulePaintInRect(const gfx::Rect& rect) { + // This happens when DestroyRootView removes all children from the + // RootView which triggers a SchedulePaint that ends up here. This happens + // after in ~Widget after native_widget_ is destroyed. + if (native_widget_destroyed_) + return; native_widget_->SchedulePaintInRect(rect); } @@ -935,8 +983,32 @@ void Widget::UpdateWindowTitle() { void Widget::UpdateWindowIcon() { if (non_client_view_) non_client_view_->UpdateWindowIcon(); - native_widget_->SetWindowIcons(widget_delegate_->GetWindowIcon(), - widget_delegate_->GetWindowAppIcon()); + + gfx::ImageSkia window_icon = GetImageSkiaFromImageModel( + widget_delegate_->GetWindowIcon(), GetNativeTheme()); + + // In general, icon information is read from a |widget_delegate_| and then + // passed to |native_widget_|. On ChromeOS, for lacros-chrome to support the + // initial window state as minimized state, a valid icon is added to + // |native_widget_| earlier stage of widget initialization. See + // https://crbug.com/1189981. As only lacros-chrome on ChromeOS supports this + // behavior other overrides of |native_widget_| will always have no icon + // information. This is also true for |app_icon| referred below. + if (window_icon.isNull()) { + const gfx::ImageSkia* icon = native_widget_->GetWindowIcon(); + if (icon && !icon->isNull()) + window_icon = *icon; + } + + gfx::ImageSkia app_icon = GetImageSkiaFromImageModel( + widget_delegate_->GetWindowAppIcon(), GetNativeTheme()); + if (app_icon.isNull()) { + const gfx::ImageSkia* icon = native_widget_->GetWindowAppIcon(); + if (icon && !icon->isNull()) + app_icon = *icon; + } + + native_widget_->SetWindowIcons(window_icon, app_icon); } FocusTraversable* Widget::GetFocusTraversable() { @@ -1009,14 +1081,20 @@ void Widget::FrameTypeChanged() { } const ui::Compositor* Widget::GetCompositor() const { + if (native_widget_destroyed_) + return nullptr; return native_widget_->GetCompositor(); } const ui::Layer* Widget::GetLayer() const { + if (native_widget_destroyed_) + return nullptr; return native_widget_->GetLayer(); } void Widget::ReorderNativeViews() { + if (native_widget_destroyed_) + return; native_widget_->ReorderNativeViews(); } @@ -1059,6 +1137,8 @@ bool Widget::HasCapture() { } TooltipManager* Widget::GetTooltipManager() { + if (native_widget_destroyed_) + return nullptr; return native_widget_->GetTooltipManager(); } @@ -1117,8 +1197,11 @@ base::CallbackListSubscription Widget::RegisterPaintAsActiveChangedCallback( std::unique_ptr<Widget::PaintAsActiveLock> Widget::LockPaintAsActive() { const bool was_paint_as_active = ShouldPaintAsActive(); ++paint_as_active_refcount_; - if (ShouldPaintAsActive() != was_paint_as_active) + if (ShouldPaintAsActive() != was_paint_as_active) { paint_as_active_callbacks_.Notify(); + if (parent() && !parent_paint_as_active_lock_) + parent_paint_as_active_lock_ = parent()->LockPaintAsActive(); + } return std::make_unique<PaintAsActiveLockImpl>( weak_ptr_factory_.GetWeakPtr()); } @@ -1128,7 +1211,32 @@ base::WeakPtr<Widget> Widget::GetWeakPtr() { } bool Widget::ShouldPaintAsActive() const { - return native_widget_active_ || paint_as_active_refcount_; + // A transient bubble hits this code path when it loses focus. + // Return false after Close() is called. + if (widget_closed_) + return false; + + return native_widget_active_ || paint_as_active_refcount_ || + (parent() && parent()->ShouldPaintAsActive()); +} + +void Widget::OnParentShouldPaintAsActiveChanged() { + DCHECK(parent()); + // |native_widget_| has already been deleted and |this| is being deleted so + // that we don't have to handle the event and also it's unsafe to reference + // |native_widget_| in this case. + if (native_widget_destroyed_) + return; + + // |native_widget_active| is being updated in + // OnNativeWidgetActivationChanged(). Notification will be handled there. + if (native_widget_active_ != native_widget_->IsActive()) + return; + + // this->ShouldPaintAsActive() changes iff the native widget is + // inactive and there's no lock on this widget. + if (!(native_widget_active_ || paint_as_active_refcount_)) + paint_as_active_callbacks_.Notify(); } void Widget::SetNativeTheme(ui::NativeTheme* native_theme) { @@ -1136,7 +1244,7 @@ void Widget::SetNativeTheme(ui::NativeTheme* native_theme) { native_theme_observation_.Reset(); if (native_theme) native_theme_observation_.Observe(native_theme); - PropagateNativeThemeChanged(); + ThemeChanged(); } int Widget::GetX() const { @@ -1239,7 +1347,18 @@ bool Widget::OnNativeWidgetActivationChanged(bool active) { observer.OnWidgetActivationChanged(this, active); const bool was_paint_as_active = ShouldPaintAsActive(); + + // Widgets in a widget tree should share the same ShouldPaintAsActive(). + // Lock the parent as paint-as-active when this widget becomes active. + if (!active && !paint_as_active_refcount_) + parent_paint_as_active_lock_.reset(); + else if (parent()) + parent_paint_as_active_lock_ = parent()->LockPaintAsActive(); + native_widget_active_ = active; + + // Notify controls (e.g. LabelButton) and children widgets about the + // paint-as-active change. if (ShouldPaintAsActive() != was_paint_as_active) paint_as_active_callbacks_.Notify(); @@ -1254,11 +1373,6 @@ void Widget::OnNativeBlur() { WidgetFocusManager::GetInstance()->OnNativeFocusChanged(nullptr); } -void Widget::OnNativeWidgetVisibilityChanging(bool visible) { - for (WidgetObserver& observer : observers_) - observer.OnWidgetVisibilityChanging(this, visible); -} - void Widget::OnNativeWidgetVisibilityChanged(bool visible) { View* root = GetRootView(); if (root) @@ -1297,6 +1411,9 @@ void Widget::OnNativeWidgetDestroyed() { widget_delegate_->can_delete_this_ = true; widget_delegate_->DeleteDelegate(); widget_delegate_ = nullptr; + // TODO(pbos): Replace this with native_widget_ = nullptr; and nullptr + // checking. This currently breaks on reentrant calls to CloseNow() that I'm + // too scared to fix right now. native_widget_destroyed_ = true; } @@ -1626,16 +1743,12 @@ View* Widget::GetFocusTraversableParentView() { void Widget::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) { TRACE_EVENT0("ui", "Widget::OnNativeThemeUpdated"); - PropagateNativeThemeChanged(); + ThemeChanged(); } //////////////////////////////////////////////////////////////////////////////// // Widget, protected: -void Widget::PropagateNativeThemeChanged() { - root_view_->PropagateThemeChanged(); -} - internal::RootView* Widget::CreateRootView() { return new internal::RootView(this); } @@ -1647,7 +1760,7 @@ void Widget::DestroyRootView() { // Remove all children before the unique_ptr reset so that // GetWidget()->GetRootView() doesn't return nullptr while the views hierarchy // is being torn down. - root_view_->RemoveAllChildViews(true); + root_view_->RemoveAllChildViews(); root_view_.reset(); } @@ -1779,6 +1892,10 @@ void Widget::UnlockPaintAsActive() { const bool was_paint_as_active = ShouldPaintAsActive(); DCHECK_GT(paint_as_active_refcount_, 0U); --paint_as_active_refcount_; + + if (!paint_as_active_refcount_ && !native_widget_active_) + parent_paint_as_active_lock_.reset(); + if (ShouldPaintAsActive() != was_paint_as_active) paint_as_active_callbacks_.Notify(); } diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h index ef3892d66fa..6ab943e4b73 100644 --- a/chromium/ui/views/widget/widget.h +++ b/chromium/ui/views/widget/widget.h @@ -10,6 +10,7 @@ #include <string> #include <vector> +#include "base/callback_list.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" @@ -686,7 +687,11 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, bool IsMinimized() const; // Accessors for fullscreen state. - void SetFullscreen(bool fullscreen); + // If `delay` is given, some underlying implementations will set their target + // fullscreen state and then post a delayed task to request the actual window + // transition, in order to handle some platform-specific quirks in specific + // fullscreen scenarios. See crbug.com/1210548 and crbug.com/1034783. + void SetFullscreen(bool fullscreen, base::TimeDelta delay = {}); bool IsFullscreen() const; // macOS: Sets whether the window can share fullscreen windows' spaces. @@ -970,18 +975,25 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // returned lock can safely outlive the associated widget. std::unique_ptr<PaintAsActiveLock> LockPaintAsActive(); + // Undoes LockPaintAsActive(). Called by PaintAsActiveLock destructor. + void UnlockPaintAsActive(); + + // Returns true if the window should paint as active. + bool ShouldPaintAsActive() const; + + // Called when the ShouldPaintAsActive() of parent changes. + void OnParentShouldPaintAsActiveChanged(); + base::WeakPtr<Widget> GetWeakPtr(); // Overridden from NativeWidgetDelegate: bool IsModal() const override; bool IsDialogBox() const override; bool CanActivate() const override; - bool ShouldPaintAsActive() const override; bool IsNativeWidgetInitialized() const override; bool OnNativeWidgetActivationChanged(bool active) override; void OnNativeFocus() override; void OnNativeBlur() override; - void OnNativeWidgetVisibilityChanging(bool visible) override; void OnNativeWidgetVisibilityChanged(bool visible) override; void OnNativeWidgetCreated() override; void OnNativeWidgetDestroying() override; @@ -1032,10 +1044,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, } protected: - // Call this to propagate native theme changes to the root view. Subclasses - // may override this to customize how native theme updates are propagated. - virtual void PropagateNativeThemeChanged(); - // Creates the RootView to be used within this Widget. Subclasses may override // to create custom RootViews that do specialized event processing. // TODO(beng): Investigate whether or not this is needed. @@ -1122,9 +1130,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // layer. const View::Views& GetViewsWithLayers(); - // Undoes LockPaintAsActive(). Called by PaintAsActiveLock destructor. - void UnlockPaintAsActive(); - // If a descendent of |root_view_| is focused, then clear the focus. void ClearFocusFromWidget(); @@ -1137,8 +1142,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, base::ObserverList<WidgetRemovalsObserver>::Unchecked removals_observers_; - PaintAsActiveCallbackList paint_as_active_callbacks_; - // Non-owned pointer to the Widget's delegate. If a NULL delegate is supplied // to Init() a default WidgetDelegate is created. WidgetDelegate* widget_delegate_ = nullptr; @@ -1182,9 +1185,19 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Tracks whether the native widget is active. bool native_widget_active_ = false; - // Tracks locks on the paint-as-active behavior. See LockPaintAsActive(). + // Count of paint-as-active locks on this widget. See LockPaintAsActive(). size_t paint_as_active_refcount_ = 0; + // Callbacks to notify when the ShouldPaintAsActive() changes. + PaintAsActiveCallbackList paint_as_active_callbacks_; + + // Lock on the parent widget when this widget is active. + // When this widget is destroyed, the lock is automatically released. + std::unique_ptr<PaintAsActiveLock> parent_paint_as_active_lock_; + + // Subscription to parent's ShouldPaintAsActive() change. + base::CallbackListSubscription parent_paint_as_active_subscription_; + // Set to true if the widget is in the process of closing. bool widget_closed_ = false; diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc index b4fa10a853f..a25d32d5cef 100644 --- a/chromium/ui/views/widget/widget_delegate.cc +++ b/chromium/ui/views/widget/widget_delegate.cc @@ -12,6 +12,7 @@ #include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/gfx/image/image_skia.h" @@ -48,8 +49,7 @@ WidgetDelegate::Params::Params() = default; WidgetDelegate::Params::~Params() = default; WidgetDelegate::WidgetDelegate() - : widget_initializing_callbacks_(std::make_unique<ClosureVector>()), - widget_initialized_callbacks_(std::make_unique<ClosureVector>()), + : widget_initialized_callbacks_(std::make_unique<ClosureVector>()), client_view_factory_( base::BindOnce(&CreateDefaultClientView, base::Unretained(this))), non_client_frame_view_factory_( @@ -143,17 +143,17 @@ bool WidgetDelegate::ShouldShowCloseButton() const { return params_.show_close_button; } -gfx::ImageSkia WidgetDelegate::GetWindowAppIcon() { +ui::ImageModel WidgetDelegate::GetWindowAppIcon() { // Prefer app icon if available. if (!params_.app_icon.isNull()) - return params_.app_icon; + return ui::ImageModel::FromImageSkia(params_.app_icon); // Fall back to the window icon. return GetWindowIcon(); } // Returns the icon to be displayed in the window. -gfx::ImageSkia WidgetDelegate::GetWindowIcon() { - return params_.icon; +ui::ImageModel WidgetDelegate::GetWindowIcon() { + return ui::ImageModel::FromImageSkia(params_.icon); } bool WidgetDelegate::ShouldShowWindowIcon() const { @@ -194,10 +194,6 @@ bool WidgetDelegate::GetSavedWindowPlacement( void WidgetDelegate::WidgetInitializing(Widget* widget) { widget_ = widget; - for (auto&& callback : *widget_initializing_callbacks_) - std::move(callback).Run(); - widget_initializing_callbacks_.reset(); - OnWidgetInitializing(); } void WidgetDelegate::WidgetInitialized() { @@ -401,12 +397,6 @@ void WidgetDelegate::SetHasWindowSizeControls(bool has_controls) { SetCanResize(has_controls); } -void WidgetDelegate::RegisterWidgetInitializingCallback( - base::OnceClosure callback) { - DCHECK(widget_initializing_callbacks_); - widget_initializing_callbacks_->emplace_back(std::move(callback)); -} - void WidgetDelegate::RegisterWidgetInitializedCallback( base::OnceClosure callback) { DCHECK(widget_initialized_callbacks_); @@ -443,13 +433,11 @@ void WidgetDelegate::SetOverlayViewFactory(OverlayViewFactory factory) { overlay_view_factory_ = std::move(factory); } -void WidgetDelegate::SetContentsViewImpl(View* contents) { - // Note: DCHECKing the ownership of contents is done in the public setters, - // which are inlined in the header. +void WidgetDelegate::SetContentsViewImpl(std::unique_ptr<View> contents) { + DCHECK(!contents->owned_by_client()); DCHECK(!unowned_contents_view_); - if (!contents->owned_by_client()) - owned_contents_view_ = base::WrapUnique(contents); - unowned_contents_view_ = contents; + owned_contents_view_ = std::move(contents); + unowned_contents_view_ = owned_contents_view_.get(); } //////////////////////////////////////////////////////////////////////////////// @@ -457,7 +445,6 @@ void WidgetDelegate::SetContentsViewImpl(View* contents) { WidgetDelegateView::WidgetDelegateView() { // A WidgetDelegate should be deleted on DeleteDelegate. - set_owned_by_client(); SetOwnedByWidget(true); } diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h index a53c8102301..16245ed7e0b 100644 --- a/chromium/ui/views/widget/widget_delegate.h +++ b/chromium/ui/views/widget/widget_delegate.h @@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <utility> #include <vector> #include "base/macros.h" @@ -22,6 +23,10 @@ class ImageSkia; class Rect; } // namespace gfx +namespace ui { +class ImageModel; +} // namespace ui + namespace views { class BubbleDialogDelegate; class ClientView; @@ -138,10 +143,6 @@ class VIEWS_EXPORT WidgetDelegate { // menu bars, etc.) changes in size. virtual void OnWorkAreaChanged(); - // Called when the widget's initialization is beginning, right after the - // ViewsDelegate decides to use this WidgetDelegate for a Widget. - virtual void OnWidgetInitializing() {} - // Called when the widget's initialization is complete. virtual void OnWidgetInitialized() {} @@ -163,7 +164,7 @@ class VIEWS_EXPORT WidgetDelegate { virtual DialogDelegate* AsDialogDelegate(); // Returns true if the window can be resized. - virtual bool CanResize() const; + bool CanResize() const; // Returns true if the window can be maximized. virtual bool CanMaximize() const; @@ -194,10 +195,10 @@ class VIEWS_EXPORT WidgetDelegate { // Returns the app icon for the window. On Windows, this is the ICON_BIG used // in Alt-Tab list and Win7's taskbar. - virtual gfx::ImageSkia GetWindowAppIcon(); + virtual ui::ImageModel GetWindowAppIcon(); // Returns the icon to be displayed in the window. - virtual gfx::ImageSkia GetWindowIcon(); + virtual ui::ImageModel GetWindowIcon(); // Returns true if a window icon should be shown. bool ShouldShowWindowIcon() const; @@ -242,11 +243,15 @@ class VIEWS_EXPORT WidgetDelegate { // of these methods. virtual void WindowClosing(); - // It should not be necessary to override this method in new code; instead, - // consider using either SetOwnedByWidget() if you need that ownership - // behavior, or RegisterDeleteDelegateCallback() if you need to attach - // behavior before deletion but want the default deletion behavior. - virtual void DeleteDelegate(); + // Called when removed from a Widget. This first runs callbacks registered + // through RegisterDeleteDelegateCallback() and then either deletes `this` or + // not depending on SetOwnedByWidget(). If `this` is owned by Widget then the + // delegate is destructed at the end. + // + // WARNING: Use SetOwnedByWidget(true) and use delete-delegate callbacks to do + // pre-destruction cleanup instead of using self-deleting callbacks. The + // latter may become a DCHECK in the future. + void DeleteDelegate(); // Called when the user begins/ends to change the bounds of the window. virtual void OnWindowBeginUserBoundsChange() {} @@ -348,24 +353,15 @@ class VIEWS_EXPORT WidgetDelegate { template <typename T> T* SetContentsView(std::unique_ptr<T> contents) { - DCHECK(!contents->owned_by_client()); T* raw_contents = contents.get(); - SetContentsViewImpl(contents.release()); + SetContentsViewImpl(std::move(contents)); return raw_contents; } - template <typename T> - T* SetContentsView(T* contents) { - DCHECK(contents->owned_by_client()); - SetContentsViewImpl(contents); - return contents; - } - // A convenience wrapper that does all three of SetCanMaximize, // SetCanMinimize, and SetCanResize. void SetHasWindowSizeControls(bool has_controls); - void RegisterWidgetInitializingCallback(base::OnceClosure callback); void RegisterWidgetInitializedCallback(base::OnceClosure callback); void RegisterWindowWillCloseCallback(base::OnceClosure callback); void RegisterWindowClosingCallback(base::OnceClosure callback); @@ -402,7 +398,7 @@ class VIEWS_EXPORT WidgetDelegate { friend class Widget; - void SetContentsViewImpl(View* contents); + void SetContentsViewImpl(std::unique_ptr<View> contents); // The Widget that was initialized with this instance as its WidgetDelegate, // if any. @@ -423,10 +419,9 @@ class VIEWS_EXPORT WidgetDelegate { // WidgetDelegate if the client has given ownership to the Widget. bool* destructor_ran_ = nullptr; - // The first two are stored as unique_ptrs to make it easier to check in the + // This is stored as a unique_ptr to make it easier to check in the // registration methods whether a callback is being registered too late in the // WidgetDelegate's lifecycle. - std::unique_ptr<ClosureVector> widget_initializing_callbacks_; std::unique_ptr<ClosureVector> widget_initialized_callbacks_; ClosureVector window_will_close_callbacks_; ClosureVector window_closing_callbacks_; diff --git a/chromium/ui/views/widget/widget_delegate_unittest.cc b/chromium/ui/views/widget/widget_delegate_unittest.cc index 80209ee9d0a..3b9cc7b73e2 100644 --- a/chromium/ui/views/widget/widget_delegate_unittest.cc +++ b/chromium/ui/views/widget/widget_delegate_unittest.cc @@ -7,8 +7,10 @@ #include <utility> #include "base/test/bind.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_unittest_util.h" +#include "ui/views/image_model_utils.h" #include "ui/views/test/views_test_base.h" #include "ui/views/view.h" #include "ui/views/view_tracker.h" @@ -18,20 +20,6 @@ namespace { using WidgetDelegateTest = views::ViewsTestBase; -TEST_F(WidgetDelegateTest, ClientOwnedContentsViewOwnershipNotHeld) { - std::unique_ptr<View> view = std::make_unique<View>(); - view->set_owned_by_client(); - ViewTracker tracker(view.get()); - - auto delegate = std::make_unique<WidgetDelegate>(); - delegate->SetContentsView(view.get()); - delegate.reset(); - - ASSERT_TRUE(tracker.view()); - view.reset(); - EXPECT_FALSE(tracker.view()); -} - TEST_F(WidgetDelegateTest, ContentsViewOwnershipHeld) { std::unique_ptr<View> view = std::make_unique<View>(); ViewTracker tracker(view.get()); @@ -122,8 +110,10 @@ TEST_F(WidgetDelegateTest, AppIconCanDifferFromWindowIcon) { delegate->SetIcon(window_icon); gfx::ImageSkia app_icon = gfx::test::CreateImageSkia(48, 48); delegate->SetAppIcon(app_icon); - EXPECT_TRUE(delegate->GetWindowIcon().BackedBySameObjectAs(window_icon)); - EXPECT_TRUE(delegate->GetWindowAppIcon().BackedBySameObjectAs(app_icon)); + EXPECT_TRUE(GetImageSkiaFromImageModel(delegate->GetWindowIcon(), nullptr) + .BackedBySameObjectAs(window_icon)); + EXPECT_TRUE(GetImageSkiaFromImageModel(delegate->GetWindowAppIcon(), nullptr) + .BackedBySameObjectAs(app_icon)); } TEST_F(WidgetDelegateTest, AppIconFallsBackToWindowIcon) { @@ -132,7 +122,8 @@ TEST_F(WidgetDelegateTest, AppIconFallsBackToWindowIcon) { gfx::ImageSkia window_icon = gfx::test::CreateImageSkia(16, 16); delegate->SetIcon(window_icon); // Don't set an independent app icon. - EXPECT_TRUE(delegate->GetWindowAppIcon().BackedBySameObjectAs(window_icon)); + EXPECT_TRUE(GetImageSkiaFromImageModel(delegate->GetWindowAppIcon(), nullptr) + .BackedBySameObjectAs(window_icon)); } } // namespace diff --git a/chromium/ui/views/widget/widget_hwnd_utils.cc b/chromium/ui/views/widget/widget_hwnd_utils.cc index e07a1291859..c23259757d9 100644 --- a/chromium/ui/views/widget/widget_hwnd_utils.cc +++ b/chromium/ui/views/widget/widget_hwnd_utils.cc @@ -109,8 +109,7 @@ void CalculateWindowStylesFromInitParams( break; case Widget::InitParams::TYPE_MENU: *style |= WS_POPUP; - if (::features::IsFormControlsRefreshEnabled() && - params.remove_standard_frame) { + if (params.remove_standard_frame) { // If the platform doesn't support drop shadow, decorate the Window // with just a border. if (ui::win::IsAeroGlassEnabled()) diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc index c9480f71a98..7c91221838f 100644 --- a/chromium/ui/views/widget/widget_interactive_uitest.cc +++ b/chromium/ui/views/widget/widget_interactive_uitest.cc @@ -533,7 +533,13 @@ TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) { } // Test z-order of child widgets relative to their parent. -TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) { +// TODO(crbug.com/1227009): Disabled on Mac due to flake +#if defined(OS_MAC) +#define MAYBE_ChildStackedRelativeToParent DISABLED_ChildStackedRelativeToParent +#else +#define MAYBE_ChildStackedRelativeToParent ChildStackedRelativeToParent +#endif +TEST_F(WidgetTestInteractive, MAYBE_ChildStackedRelativeToParent) { WidgetAutoclosePtr parent(CreateTopLevelPlatformWidget()); Widget* child = CreateChildPlatformWidget(parent->GetNativeView()); @@ -1040,6 +1046,19 @@ TEST_F(WidgetTestInteractive, ShowAfterShowInactive) { EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL); } +TEST_F(WidgetTestInteractive, WidgetShouldBeActiveWhenShow) { + // TODO(crbug/1217331): This test fails if put under NativeWidgetAuraTest. + WidgetAutoclosePtr anchor_widget(CreateTopLevelNativeWidget()); + + test::WidgetActivationWaiter waiter(anchor_widget.get(), true); + anchor_widget->Show(); + waiter.Wait(); + EXPECT_TRUE(anchor_widget->IsActive()); +#if !defined(OS_MAC) + EXPECT_TRUE(anchor_widget->GetNativeWindow()->HasFocus()); +#endif +} + #if BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MAC) TEST_F(WidgetTestInteractive, InactiveWidgetDoesNotGrabActivation) { WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget()); diff --git a/chromium/ui/views/widget/widget_observer.h b/chromium/ui/views/widget/widget_observer.h index 4050dd33db5..32a27d0e034 100644 --- a/chromium/ui/views/widget/widget_observer.h +++ b/chromium/ui/views/widget/widget_observer.h @@ -41,7 +41,6 @@ class VIEWS_EXPORT WidgetObserver : public base::CheckedObserver { virtual void OnWidgetDragWillStart(Widget* widget) {} virtual void OnWidgetDragComplete(Widget* widget) {} - virtual void OnWidgetVisibilityChanging(Widget* widget, bool visible) {} virtual void OnWidgetVisibilityChanged(Widget* widget, bool visible) {} virtual void OnWidgetActivationChanged(Widget* widget, bool active) {} diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc index 8b107c8a08d..32fffc05f1b 100644 --- a/chromium/ui/views/widget/widget_unittest.cc +++ b/chromium/ui/views/widget/widget_unittest.cc @@ -30,6 +30,7 @@ #include "ui/views/controls/textfield/textfield.h" #include "ui/views/event_monitor.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/style/platform_style.h" #include "ui/views/test/native_widget_factory.h" #include "ui/views/test/test_views.h" #include "ui/views/test/test_widget_observer.h" @@ -69,6 +70,7 @@ #if defined(USE_OZONE) #include "ui/base/ui_base_features.h" #include "ui/ozone/public/ozone_platform.h" +#include "ui/ozone/public/platform_gl_egl_utility.h" #endif namespace views { @@ -753,6 +755,9 @@ TEST_F(WidgetOwnsNativeWidgetTest, WidgetDelegateView) { using WidgetWithDestroyedNativeViewTest = ViewsTestBaseWithNativeWidgetType; TEST_P(WidgetWithDestroyedNativeViewTest, Test) { + // TODO(pbos): Add a version of this that tests with params that use + // NATIVE_WIDGET_OWNS_WIDGET. A lot of these implementations look like they + // call `native_widget_->` which should be illegal after CloseNow(). std::unique_ptr<Widget> widget = CreateTestWidget(); widget->Show(); @@ -2099,6 +2104,90 @@ TEST_F(WidgetTest, LockPaintAsActive_BecomesActive) { EXPECT_TRUE(widget->ShouldPaintAsActive()); } +class PaintAsActiveCallbackCounter { + public: + explicit PaintAsActiveCallbackCounter(Widget* widget) { + // Subscribe to |widget|'s paint-as-active change. + paint_as_active_subscription_ = + widget->RegisterPaintAsActiveChangedCallback(base::BindRepeating( + &PaintAsActiveCallbackCounter::Call, base::Unretained(this))); + } + void Call() { count_++; } + int CallCount() { return count_; } + + private: + int count_ = 0; + base::CallbackListSubscription paint_as_active_subscription_; +}; + +TEST_F(WidgetTest, LockParentPaintAsActive) { + if (!PlatformStyle::kInactiveWidgetControlsAppearDisabled) + return; + + WidgetAutoclosePtr parent(CreateTopLevelPlatformWidget()); + WidgetAutoclosePtr child(CreateChildPlatformWidget(parent->GetNativeView())); + WidgetAutoclosePtr grandchild( + CreateChildPlatformWidget(child->GetNativeView())); + WidgetAutoclosePtr other(CreateTopLevelPlatformWidget()); + child->widget_delegate()->SetCanActivate(true); + grandchild->widget_delegate()->SetCanActivate(true); + + PaintAsActiveCallbackCounter parent_control(parent.get()); + PaintAsActiveCallbackCounter child_control(child.get()); + PaintAsActiveCallbackCounter grandchild_control(grandchild.get()); + PaintAsActiveCallbackCounter other_control(other.get()); + + parent->Show(); + EXPECT_TRUE(parent->ShouldPaintAsActive()); + EXPECT_TRUE(child->ShouldPaintAsActive()); + EXPECT_TRUE(grandchild->ShouldPaintAsActive()); + EXPECT_FALSE(other->ShouldPaintAsActive()); + EXPECT_EQ(parent_control.CallCount(), 1); + EXPECT_EQ(child_control.CallCount(), 1); + EXPECT_EQ(grandchild_control.CallCount(), 1); + EXPECT_EQ(other_control.CallCount(), 0); + + other->Show(); + EXPECT_FALSE(parent->ShouldPaintAsActive()); + EXPECT_FALSE(child->ShouldPaintAsActive()); + EXPECT_FALSE(grandchild->ShouldPaintAsActive()); + EXPECT_TRUE(other->ShouldPaintAsActive()); + EXPECT_EQ(parent_control.CallCount(), 2); + EXPECT_EQ(child_control.CallCount(), 2); + EXPECT_EQ(grandchild_control.CallCount(), 2); + EXPECT_EQ(other_control.CallCount(), 1); + + child->Show(); + EXPECT_TRUE(parent->ShouldPaintAsActive()); + EXPECT_TRUE(child->ShouldPaintAsActive()); + EXPECT_TRUE(grandchild->ShouldPaintAsActive()); + EXPECT_FALSE(other->ShouldPaintAsActive()); + EXPECT_EQ(parent_control.CallCount(), 3); + EXPECT_EQ(child_control.CallCount(), 3); + EXPECT_EQ(grandchild_control.CallCount(), 3); + EXPECT_EQ(other_control.CallCount(), 2); + + other->Show(); + EXPECT_FALSE(parent->ShouldPaintAsActive()); + EXPECT_FALSE(child->ShouldPaintAsActive()); + EXPECT_FALSE(grandchild->ShouldPaintAsActive()); + EXPECT_TRUE(other->ShouldPaintAsActive()); + EXPECT_EQ(parent_control.CallCount(), 4); + EXPECT_EQ(child_control.CallCount(), 4); + EXPECT_EQ(grandchild_control.CallCount(), 4); + EXPECT_EQ(other_control.CallCount(), 3); + + grandchild->Show(); + EXPECT_TRUE(parent->ShouldPaintAsActive()); + EXPECT_TRUE(child->ShouldPaintAsActive()); + EXPECT_TRUE(grandchild->ShouldPaintAsActive()); + EXPECT_FALSE(other->ShouldPaintAsActive()); + EXPECT_EQ(parent_control.CallCount(), 5); + EXPECT_EQ(child_control.CallCount(), 5); + EXPECT_EQ(grandchild_control.CallCount(), 5); + EXPECT_EQ(other_control.CallCount(), 4); +} + // Widget used to destroy itself when OnNativeWidgetDestroyed is called. class TestNativeWidgetDestroyedWidget : public Widget { public: @@ -4049,9 +4138,9 @@ namespace { bool CanHaveCompositingManager() { #if defined(USE_OZONE) if (features::IsUsingOzonePlatform()) { - const auto* const egl_utility = + auto* const egl_utility = ui::OzonePlatform::GetInstance()->GetPlatformGLEGLUtility(); - return egl_utility != nullptr; + return (egl_utility != nullptr) && egl_utility->HasVisualManager(); } #endif #if defined(USE_X11) diff --git a/chromium/ui/views/widget/window_reorderer.cc b/chromium/ui/views/widget/window_reorderer.cc index 0992ed1828c..cb5b0ac2393 100644 --- a/chromium/ui/views/widget/window_reorderer.cc +++ b/chromium/ui/views/widget/window_reorderer.cc @@ -56,7 +56,7 @@ void GetOrderOfViewsWithLayers( order->push_back(view); } - for (views::View* child : view->children()) + for (views::View* child : view->GetChildrenInZOrder()) GetOrderOfViewsWithLayers(child, parent_layer, hosts, order); } |