// 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 #include #include "ash/display/screen_orientation_controller.h" #include "ash/wm/client_controlled_state.h" #include "base/callback.h" #include "base/macros.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 RoundedCornerDecorator; class WideFrameView; namespace mojom { enum class WindowPinType; } } // 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: ClientControlledShellSurface(Surface* surface, bool can_minimize, int container, bool default_scale_cancellation); ~ClientControlledShellSurface() override; using GeometryChangedCallback = base::RepeatingCallback; void set_geometry_changed_callback(const GeometryChangedCallback& callback) { geometry_changed_callback_ = callback; } 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); // Called when the client was snapped to left. void SetSnappedToLeft(); // Called when the client was snapped to right. void SetSnappedToRight(); // Called when the client was set to PIP. void SetPip(); // Set the callback to run when the surface state changed. using StateChangedCallback = base::RepeatingCallback; void set_state_changed_callback( const StateChangedCallback& state_changed_callback) { state_changed_callback_ = state_changed_callback; } // Set the callback to run when the surface bounds changed. using BoundsChangedCallback = base::RepeatingCallback; void set_bounds_changed_callback( const BoundsChangedCallback& bounds_changed_callback) { bounds_changed_callback_ = bounds_changed_callback; } bool has_bounds_changed_callback() const { return static_cast(bounds_changed_callback_); } // Set the callback to run when the drag operation started. using DragStartedCallback = base::RepeatingCallback; void set_drag_started_callback(const DragStartedCallback& callback) { drag_started_callback_ = callback; } // Set the callback to run when the drag operation finished. using DragFinishedCallback = base::RepeatingCallback; void set_drag_finished_callback(const DragFinishedCallback& callback) { drag_finished_callback_ = callback; } // Set callback to run when user requests to change a zoom level. using ChangeZoomLevelCallback = base::RepeatingCallback; void set_change_zoom_level_callback(const ChangeZoomLevelCallback& callback) { change_zoom_level_callback_ = callback; } // 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); // Sets the IME to be blocked so that all events are forwarded by Exo. void SetImeBlocked(bool ime_blocked); // 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); // Set resize outset for surface. void SetResizeOutset(int outset); // 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 base::string16& extra_title); // Set specific orientation lock for this surface. When this surface is in // foreground and the display can be rotated (e.g. tablet mode), apply the // behavior defined by |orientation_lock|. See more details in // //ash/display/screen_orientation_controller.h. void SetOrientationLock(ash::OrientationLockType orientation_lock); // 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); // 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; // Overridden from views::WidgetDelegate: bool CanMaximize() const override; std::unique_ptr 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(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; protected: // Overridden from ShellSurfaceBase: float GetScale() const override; private: 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; base::Optional 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; GeometryChangedCallback geometry_changed_callback_; 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; StateChangedCallback state_changed_callback_; BoundsChangedCallback bounds_changed_callback_; DragStartedCallback drag_started_callback_; DragFinishedCallback drag_finished_callback_; ChangeZoomLevelCallback change_zoom_level_callback_; // 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; chromeos::WindowPinType current_pin_; bool can_maximize_ = true; std::unique_ptr immersive_fullscreen_controller_; std::unique_ptr wide_frame_; std::unique_ptr decorator_; std::unique_ptr orientation_compositor_lock_; // The orientation to be applied when widget is being created. Only set when // widget is not created yet orientation lock is being set. ash::OrientationLockType initial_orientation_lock_ = ash::OrientationLockType::kAny; // The extra title to be applied when widget is being created. base::string16 initial_extra_title_ = base::string16(); 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 accelerator_target_; // Accessibility ID provided by client. base::Optional client_accessibility_id_; DISALLOW_COPY_AND_ASSIGN(ClientControlledShellSurface); }; } // namespace exo #endif // COMPONENTS_EXO_CLIENT_CONTROLLED_SHELL_SURFACE_H_