| // Copyright 2017 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. |
| |
| #ifndef COMPONENTS_EXO_CLIENT_CONTROLLED_SHELL_SURFACE_H_ |
| #define COMPONENTS_EXO_CLIENT_CONTROLLED_SHELL_SURFACE_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| #include "ash/display/screen_orientation_controller.h" |
| #include "ash/public/cpp/arc_resize_lock_type.h" |
| #include "ash/wm/client_controlled_state.h" |
| #include "base/callback.h" |
| #include "base/gtest_prod_util.h" |
| #include "components/exo/client_controlled_accelerators.h" |
| #include "components/exo/shell_surface_base.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/compositor/compositor_lock.h" |
| |
| namespace ash { |
| class NonClientFrameViewAsh; |
| class WideFrameView; |
| } // namespace ash |
| |
| namespace chromeos { |
| class ImmersiveFullscreenController; |
| } // namespace chromeos |
| |
| namespace exo { |
| class Surface; |
| class ClientControlledAcceleratorTarget; |
| |
| enum class Orientation { PORTRAIT, LANDSCAPE }; |
| enum class ZoomChange { IN, OUT, RESET }; |
| |
| // This class implements a ShellSurface whose window state and bounds are |
| // controlled by a remote shell client rather than the window manager. The |
| // position specified as part of the geometry is relative to the origin of |
| // the screen coordinate system. |
| class ClientControlledShellSurface : public ShellSurfaceBase, |
| public ui::CompositorLockClient { |
| public: |
| // TODO(mukai): integrate this with ShellSurfaceBase's callback. |
| class Delegate { |
| public: |
| virtual ~Delegate() = default; |
| virtual void OnGeometryChanged(const gfx::Rect& geometry) = 0; |
| virtual void OnStateChanged(chromeos::WindowStateType old_state_type, |
| chromeos::WindowStateType new_state_type) = 0; |
| virtual void OnBoundsChanged(chromeos::WindowStateType current_state, |
| chromeos::WindowStateType requested_state, |
| int64_t display_id, |
| const gfx::Rect& bounds_in_display, |
| bool is_resize, |
| int bounds_change) = 0; |
| virtual void OnDragStarted(int component) = 0; |
| virtual void OnDragFinished(int x, int y, bool canceled) = 0; |
| virtual void OnZoomLevelChanged(ZoomChange zoom_change) = 0; |
| }; |
| |
| ClientControlledShellSurface(Surface* surface, |
| bool can_minimize, |
| int container, |
| bool default_scale_cancellation); |
| |
| ClientControlledShellSurface(const ClientControlledShellSurface&) = delete; |
| ClientControlledShellSurface& operator=(const ClientControlledShellSurface&) = |
| delete; |
| |
| ~ClientControlledShellSurface() override; |
| |
| Delegate* set_delegate(std::unique_ptr<Delegate> delegate) { |
| delegate_ = std::move(delegate); |
| return delegate_.get(); |
| } |
| |
| void set_server_reparent_window(bool reparent) { |
| server_reparent_window_ = reparent; |
| } |
| |
| // Set bounds in root window coordinates relative to the given display. |
| void SetBounds(int64_t display_id, const gfx::Rect& bounds); |
| |
| // Set origin of bounds for surface while preserving the size. |
| void SetBoundsOrigin(const gfx::Point& origin); |
| |
| // Set size of bounds for surface while preserving the origin. |
| void SetBoundsSize(const gfx::Size& size); |
| |
| // Called when the client was maximized. |
| void SetMaximized(); |
| |
| // Called when the client was minimized. |
| void SetMinimized(); |
| |
| // Called when the client was restored. |
| void SetRestored(); |
| |
| // Called when the client changed the fullscreen state. |
| void SetFullscreen(bool fullscreen); |
| |
| // Returns true if this shell surface is currently being dragged. |
| bool IsDragging(); |
| |
| // Pin/unpin the surface. Pinned surface cannot be switched to |
| // other windows unless its explicitly unpinned. |
| void SetPinned(chromeos::WindowPinType type); |
| |
| // Sets the surface to be on top of all other windows. |
| void SetAlwaysOnTop(bool always_on_top); |
| |
| // Controls the visibility of the system UI when this surface is active. |
| void SetSystemUiVisibility(bool autohide); |
| |
| // Set orientation for surface. |
| void SetOrientation(Orientation orientation); |
| |
| // Set shadow bounds in surface coordinates. Empty bounds disable the shadow. |
| void SetShadowBounds(const gfx::Rect& bounds); |
| |
| // Set the pending scale. |
| void SetScale(double scale); |
| |
| // Commit the pending scale if it was changed. The scale set by SetScale() is |
| // otherwise committed by OnPostWidgetCommit(). |
| void CommitPendingScale(); |
| |
| // Set top inset for surface. |
| void SetTopInset(int height); |
| |
| // Sends the request to change the zoom level to the client. |
| void ChangeZoomLevel(ZoomChange change); |
| |
| // Sends the window state change event to client. |
| void OnWindowStateChangeEvent(chromeos::WindowStateType old_state, |
| chromeos::WindowStateType next_state); |
| |
| // Sends the window bounds change event to client. |display_id| specifies in |
| // which display the surface should live in. |drag_bounds_change| is |
| // a masked value of ash::WindowResizer::kBoundsChange_Xxx, and specifies |
| // how the bounds was changed. The bounds change event may also come from a |
| // snapped window state change |requested_state|. |
| void OnBoundsChangeEvent(chromeos::WindowStateType current_state, |
| chromeos::WindowStateType requested_state, |
| int64_t display_id, |
| const gfx::Rect& bounds, |
| int drag_bounds_change); |
| |
| // Sends the window drag events to client. |
| void OnDragStarted(int component); |
| void OnDragFinished(bool cancel, const gfx::PointF& location); |
| |
| // Starts the drag operation. |
| void StartDrag(int component, const gfx::PointF& location); |
| |
| // Set if the surface can be maximzied. |
| void SetCanMaximize(bool can_maximize); |
| |
| // Update the auto hide frame state. |
| void UpdateAutoHideFrame(); |
| |
| // Set the frame button state. The |visible_button_mask| and |
| // |enabled_button_mask| is a bit mask whose position is defined |
| // in views::CaptionButtonIcon enum. |
| void SetFrameButtons(uint32_t frame_visible_button_mask, |
| uint32_t frame_enabled_button_mask); |
| |
| // Set the extra title for the surface. |
| void SetExtraTitle(const std::u16string& extra_title); |
| |
| // Set the accessibility ID provided by client for the surface. If |
| // |accessibility_id| is negative value, it will unset the ID. |
| void SetClientAccessibilityId(int32_t accessibility_id); |
| |
| // Rebind a surface as the root surface of the shell surface. |
| void RebindRootSurface(Surface* root_surface, |
| bool can_minimize, |
| int container, |
| bool default_scale_cancellation); |
| |
| // Overridden from SurfaceTreeHost: |
| void DidReceiveCompositorFrameAck() override; |
| |
| // Overridden from SurfaceDelegate: |
| bool IsInputEnabled(Surface* surface) const override; |
| void OnSetFrame(SurfaceFrameType type) override; |
| void OnSetFrameColors(SkColor active_color, SkColor inactive_color) override; |
| void SetSnappedToPrimary() override; |
| void SetSnappedToSecondary() override; |
| void SetPip() override; |
| void UnsetPip() override; |
| |
| // Overridden from views::WidgetDelegate: |
| bool CanMaximize() const override; |
| std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView( |
| views::Widget* widget) override; |
| void SaveWindowPlacement(const gfx::Rect& bounds, |
| ui::WindowShowState show_state) override; |
| bool GetSavedWindowPlacement(const views::Widget* widget, |
| gfx::Rect* bounds, |
| ui::WindowShowState* show_state) const override; |
| |
| // Overridden from views::View: |
| gfx::Size GetMaximumSize() const override; |
| void OnDeviceScaleFactorChanged(float old_dsf, float new_dsf) override; |
| |
| // Overridden from aura::WindowObserver: |
| void OnWindowAddedToRootWindow(aura::Window* window) override; |
| |
| // Overridden from display::DisplayObserver: |
| void OnDisplayMetricsChanged(const display::Display& display, |
| uint32_t changed_metrics) override; |
| |
| // Overridden from ui::CompositorLockClient: |
| void CompositorLockTimedOut() override; |
| |
| // A factory callback to create ClientControlledState::Delegate. |
| using DelegateFactoryCallback = base::RepeatingCallback< |
| std::unique_ptr<ash::ClientControlledState::Delegate>(void)>; |
| |
| // Set the factory callback for unit test. |
| static void SetClientControlledStateDelegateFactoryForTest( |
| const DelegateFactoryCallback& callback); |
| |
| ash::WideFrameView* wide_frame_for_test() { return wide_frame_.get(); } |
| |
| // Exposed for testing. Returns the effective scale as opposed to |
| // |pending_scale_|. |
| double scale() const { return scale_; } |
| |
| // Used to scale incoming coordinates from the client to DP. |
| float GetClientToDpScale() const; |
| |
| // Sets the resize lock type to the surface. |
| void SetResizeLockType(ash::ArcResizeLockType resize_lock_type); |
| |
| // Update the resizability based on the resize lock type. |
| void UpdateResizability() override; |
| |
| protected: |
| // Overridden from ShellSurfaceBase: |
| float GetScale() const override; |
| |
| private: |
| FRIEND_TEST_ALL_PREFIXES(ClientControlledShellSurfaceTest, |
| OverlayShadowBounds); |
| class ScopedSetBoundsLocally; |
| class ScopedLockedToRoot; |
| |
| // Overridden from ShellSurfaceBase: |
| void SetWidgetBounds(const gfx::Rect& bounds) override; |
| gfx::Rect GetShadowBounds() const override; |
| void InitializeWindowState(ash::WindowState* window_state) override; |
| absl::optional<gfx::Rect> GetWidgetBounds() const override; |
| gfx::Point GetSurfaceOrigin() const override; |
| bool OnPreWidgetCommit() override; |
| void OnPostWidgetCommit() override; |
| void OnSurfaceDestroying(Surface* surface) override; |
| void OnContentSizeChanged(Surface* surface) override; |
| |
| // Update frame status. This may create (or destroy) a wide frame |
| // that spans the full work area width if the surface didn't cover |
| // the work area. |
| void UpdateFrame(); |
| |
| void UpdateCaptionButtonModel(); |
| |
| void UpdateBackdrop(); |
| |
| void UpdateFrameWidth(); |
| |
| void UpdateFrameType() override; |
| |
| void AttemptToStartDrag(int component, const gfx::PointF& location); |
| |
| // Lock the compositor if it's not already locked, or extends the |
| // lock timeout if it's already locked. |
| // TODO(reveman): Remove this when using configure callbacks for orientation. |
| // crbug.com/765954 |
| void EnsureCompositorIsLockedForOrientationChange(); |
| |
| ash::WindowState* GetWindowState(); |
| ash::NonClientFrameViewAsh* GetFrameView(); |
| const ash::NonClientFrameViewAsh* GetFrameView() const; |
| |
| void EnsurePendingScale(); |
| float GetClientToDpPendingScale() const; |
| |
| gfx::Rect GetClientBoundsForWindowBoundsAndWindowState( |
| const gfx::Rect& window_bounds, |
| chromeos::WindowStateType window_state) const; |
| |
| int top_inset_height_ = 0; |
| int pending_top_inset_height_ = 0; |
| |
| double scale_ = 1.0; |
| // The pending scale is initialized to 0.0 to indicate that the scale is not |
| // yet initialized. |
| double pending_scale_ = 0.0; |
| |
| uint32_t frame_visible_button_mask_ = 0; |
| uint32_t frame_enabled_button_mask_ = 0; |
| |
| std::unique_ptr<Delegate> delegate_; |
| |
| // TODO(reveman): Use configure callbacks for orientation. crbug.com/765954 |
| Orientation pending_orientation_ = Orientation::LANDSCAPE; |
| Orientation orientation_ = Orientation::LANDSCAPE; |
| Orientation expected_orientation_ = Orientation::LANDSCAPE; |
| |
| ash::ClientControlledState* client_controlled_state_ = nullptr; |
| |
| chromeos::WindowStateType pending_window_state_ = |
| chromeos::WindowStateType::kNormal; |
| |
| bool pending_always_on_top_ = false; |
| |
| SurfaceFrameType pending_frame_type_ = SurfaceFrameType::NONE; |
| |
| bool can_maximize_ = true; |
| |
| std::unique_ptr<chromeos::ImmersiveFullscreenController> |
| immersive_fullscreen_controller_; |
| |
| std::unique_ptr<ash::WideFrameView> wide_frame_; |
| |
| std::unique_ptr<ui::CompositorLock> orientation_compositor_lock_; |
| |
| // The extra title to be applied when widget is being created. |
| std::u16string initial_extra_title_ = std::u16string(); |
| |
| bool preserve_widget_bounds_ = false; |
| |
| // Checking DragDetails is not sufficient to determine if a bounds |
| // request happened during a drag move or resize. If the window resizer |
| // requests a bounds update after completing the drag but before the |
| // drag details are cleaned up, we want to consider that as a regular |
| // bounds update, not a drag move/resize update. |
| bool in_drag_ = false; |
| |
| // N uses older protocol which expects that server will reparent the window. |
| // TODO(oshima): Remove this once all boards are migrated to P or above. |
| bool server_reparent_window_ = false; |
| |
| bool ignore_bounds_change_request_ = false; |
| |
| bool display_rotating_with_pip_ = false; |
| |
| // True if the window state has changed during the commit. |
| bool state_changed_ = false; |
| |
| // When false, the client handles all display scale changes, so the |
| // buffer should be re-scaled to undo any scaling added by exo so that the |
| // 1:1 correspondence between the pixels is maintained. |
| bool use_default_scale_cancellation_ = false; |
| |
| // Client controlled specific accelerator target. |
| std::unique_ptr<ClientControlledAcceleratorTarget> accelerator_target_; |
| |
| // Accessibility ID provided by client. |
| absl::optional<int32_t> client_accessibility_id_; |
| |
| ash::ArcResizeLockType pending_resize_lock_type_ = |
| ash::ArcResizeLockType::NONE; |
| }; |
| |
| } // namespace exo |
| |
| #endif // COMPONENTS_EXO_CLIENT_CONTROLLED_SHELL_SURFACE_H_ |