[go: nahoru, domu]

blob: f70ffe675af3a142860105fb6a78a7ac9092e4c3 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_EXO_SHELL_SURFACE_H_
#define COMPONENTS_EXO_SHELL_SURFACE_H_
#include <optional>
#include "ash/focus_cycler.h"
#include "ash/wm/toplevel_window_event_handler.h"
#include "ash/wm/window_state_observer.h"
#include "base/containers/circular_deque.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "components/exo/shell_surface_base.h"
#include "components/exo/shell_surface_observer.h"
#include "ui/base/ui_base_types.h"
namespace ash {
class ScopedAnimationDisabler;
} // namespace ash
namespace ui {
class CompositorLock;
class Layer;
} // namespace ui
namespace exo {
class Surface;
// This class implements toplevel surface for which position and state are
// managed by the shell.
class ShellSurface : public ShellSurfaceBase, public ash::WindowStateObserver {
public:
// The |origin| is the initial position in screen coordinates. The position
// specified as part of the geometry is relative to the shell surface.
ShellSurface(Surface* surface,
const gfx::Point& origin,
bool can_minimize,
int container);
explicit ShellSurface(Surface* surface);
ShellSurface(const ShellSurface&) = delete;
ShellSurface& operator=(const ShellSurface&) = delete;
~ShellSurface() override;
// Set the callback to run when the client is asked to configure the surface.
// The size is a hint, in the sense that the client is free to ignore it if
// it doesn't resize, pick a smaller size (to satisfy aspect ratio or resize
// in steps of NxM pixels).
using ConfigureCallback = base::RepeatingCallback<uint32_t(
const gfx::Rect& bounds,
chromeos::WindowStateType state_type,
bool resizing,
bool activated,
const gfx::Vector2d& origin_offset,
float raster_scale,
aura::Window::OcclusionState occlusion_state,
std::optional<chromeos::WindowStateType> restore_state_type)>;
using OriginChangeCallback =
base::RepeatingCallback<void(const gfx::Point& origin)>;
using RotateFocusCallback =
base::RepeatingCallback<uint32_t(ash::FocusCycler::Direction direction,
bool restart)>;
using OverviewChangeCallback =
base::RepeatingCallback<void(bool in_overview)>;
void set_configure_callback(const ConfigureCallback& configure_callback) {
configure_callback_ = configure_callback;
}
void set_origin_change_callback(
const OriginChangeCallback& origin_change_callback) {
origin_change_callback_ = origin_change_callback;
}
void set_rotate_focus_callback(const RotateFocusCallback callback) {
rotate_focus_callback_ = callback;
}
void set_overview_change_callback(const OverviewChangeCallback callback) {
overview_change_callback_ = callback;
}
// When the client is asked to configure the surface, it should acknowledge
// the configure request sometime before the commit. |serial| is the serial
// from the configure callback.
void AcknowledgeConfigure(uint32_t serial);
// Set the "parent" of this surface. This window should be stacked above a
// parent.
void SetParent(ShellSurface* parent);
bool CanMaximize() const override;
// Maximizes the shell surface.
void Maximize();
// Minimize the shell surface.
void Minimize();
// Restore the shell surface.
void Restore();
// Set fullscreen state for shell surface. When `fullscreen` is true,
// `display_id` indicates the id of the display where the surface should be
// shown on, otherwise it gets ignored. When `display::kInvalidDisplayId` is
// specified the current display will be used.
void SetFullscreen(bool fullscreen, int64_t display_id);
// Make the shell surface popup type.
void SetPopup();
// Invokes when the surface has reached the end of its own focus rotation.
// This signals ash to to continue its own focus rotation.
void AckRotateFocus(uint32_t serial, bool handled);
// Set event grab on the surface.
void Grab();
// Start an interactive resize of surface. |component| is one of the windows
// HT constants (see ui/base/hit_test.h) and describes in what direction the
// surface should be resized.
bool StartResize(int component);
// Start an interactive move of surface.
bool StartMove();
// Sends a wayland request to the surface to rotate focus within itself. If
// the client was able to rotate, it will return a "handled" response,
// otherwise it will respond with a "not handled" response.
// If the client does not support the wayland event, the base class'
// impl is invoked. In practice, this means that the surface will be focused,
// but it will not rotate focus within its panes.
bool RotatePaneFocusFromView(views::View* focused_view,
bool forward,
bool enable_wrapping) override;
// Return the initial show state for this surface.
ui::WindowShowState initial_show_state() { return initial_show_state_; }
void AddObserver(ShellSurfaceObserver* observer);
void RemoveObserver(ShellSurfaceObserver* observer);
void MaybeSetCompositorLockForNextConfigure(int milliseconds);
// Overridden from SurfaceDelegate:
void OnSetFrame(SurfaceFrameType type) override;
void OnSetParent(Surface* parent, const gfx::Point& position) override;
// Overridden from SurfaceTreeHost:
void MaybeActivateSurface() override;
ui::Layer* GetCommitTargetLayer() override;
const ui::Layer* GetCommitTargetLayer() const override;
// Overridden from ShellSurfaceBase:
void InitializeWindowState(ash::WindowState* window_state) override;
std::optional<gfx::Rect> GetWidgetBounds() const override;
gfx::Point GetSurfaceOrigin() const override;
void SetUseImmersiveForFullscreen(bool value) override;
void OnDidProcessDisplayChanges(
const DisplayConfigurationChange& configuration_change) override;
// Overridden from aura::WindowObserver:
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override;
void OnWindowAddedToRootWindow(aura::Window* window) override;
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old_value) override;
// Overridden from ash::WindowStateObserver:
void OnPreWindowStateTypeChange(ash::WindowState* window_state,
chromeos::WindowStateType old_type) override;
void OnPostWindowStateTypeChange(ash::WindowState* window_state,
chromeos::WindowStateType old_type) override;
// Overridden from wm::ActivationChangeObserver:
void OnWindowActivated(ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override;
// Overridden from ShellSurfaceBase:
gfx::Rect ComputeAdjustedBounds(const gfx::Rect& bounds) const override;
void SetWidgetBounds(const gfx::Rect& bounds,
bool adjusted_by_server) override;
bool OnPreWidgetCommit() override;
std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
views::Widget* widget) override;
void SetRootSurface(Surface* root_surface) override;
// Overridden from ui::LayerOwner::Observer:
void OnLayerRecreated(ui::Layer* old_layer) override;
void EndDrag();
int resize_component_for_test() const { return resize_component_; }
private:
struct Config;
// Helper class used to coalesce a number of changes into one "configure"
// callback. Callbacks are suppressed while an instance of this class is
// instantiated and instead called when the instance is destroyed.
// If |force_configure_| is true ShellSurface::Configure() will be called
// even if no changes to shell surface took place during the lifetime of the
// ScopedConfigure instance.
class ScopedConfigure {
public:
ScopedConfigure(ShellSurface* shell_surface, bool force_configure);
ScopedConfigure(const ScopedConfigure&) = delete;
ScopedConfigure& operator=(const ScopedConfigure&) = delete;
~ScopedConfigure();
void set_needs_configure() { needs_configure_ = true; }
private:
const raw_ptr<ShellSurface> shell_surface_;
const bool force_configure_;
bool needs_configure_ = false;
};
class OcclusionObserver : public aura::WindowObserver {
public:
explicit OcclusionObserver(ShellSurface* shell_surface,
aura::Window* window);
~OcclusionObserver() override;
aura::Window::OcclusionState state() const { return state_; }
aura::Window::OcclusionState GetInitialStateForConfigure(
chromeos::WindowStateType state_type);
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
void OnWindowOcclusionChanged(aura::Window* window) override;
private:
void MaybeConfigure(aura::Window* window);
// Keeps track of what the current state should be. During initialization,
// we want to defer sending occlusion messages until everything is ready,
// so this may be different to the current occlusion state.
aura::Window::OcclusionState state_;
const raw_ptr<ShellSurface> shell_surface_;
base::ScopedObservation<aura::Window, aura::WindowObserver>
window_observation_{this};
};
// Set the parent window of this surface.
void SetParentWindow(aura::Window* parent);
// Sets up a transient window manager for this window if it can (i.e. if the
// surface has a widget with a parent).
void MaybeMakeTransient();
// Asks the client to configure its surface. Optionally, the user can override
// the behaviour to check for window dragging by setting ends_drag to true.
void Configure(bool ends_drag = false);
bool GetCanResizeFromSizeConstraints() const override;
bool AttemptToStartDrag(int component);
// Utility methods to resolve the initial bounds for the first commit.
gfx::Rect GetInitialBoundsForState(
const chromeos::WindowStateType state) const;
display::Display GetDisplayForInitialBounds() const;
void UpdateLayerSurfaceRange(ui::Layer* layer,
const viz::LocalSurfaceId& current_lsi);
// Called when the widget window's position in screen coordinates may have
// changed.
// TODO(tluk): Screen position changes should be merged into Configure().
void OnWidgetScreenPositionChanged();
std::unique_ptr<ash::ScopedAnimationDisabler> animations_disabler_;
std::optional<OcclusionObserver> occlusion_observer_;
// Temporarily stores the `host_window()`'s layer when it's recreated for
// animation. Client-side commits may be directed towards the `old_layer_`
// instead of `host_window()->layer()` due to the asynchronous config/ack
// flow.
base::WeakPtr<ui::Layer> old_layer_;
std::unique_ptr<ui::CompositorLock> configure_compositor_lock_;
ConfigureCallback configure_callback_;
OriginChangeCallback origin_change_callback_;
RotateFocusCallback rotate_focus_callback_;
OverviewChangeCallback overview_change_callback_;
raw_ptr<ScopedConfigure> scoped_configure_ = nullptr;
base::circular_deque<std::unique_ptr<Config>> pending_configs_;
// Stores the config which is acked but not yet committed. This will keep the
// compositor locked until reset after Commit() is called.
std::unique_ptr<Config> config_waiting_for_commit_;
// Window resizing is an asynchronous operation. See
// https://crbug.com/1336706#c22 for a more detailed explanation.
// |origin_offset_| is typically (0,0). During an asynchronous resizing
// |origin_offset_| is set to a non-zero value such that it appears as though
// the ExoShellSurfaceHost has not moved even though ExoShellSurface has
// already been moved and resized to the new position.
gfx::Vector2d origin_offset_;
gfx::Vector2d pending_origin_offset_;
gfx::Vector2d pending_origin_offset_accumulator_;
gfx::Rect old_screen_bounds_for_pending_move_;
int resize_component_ = HTCAPTION; // HT constant (see ui/base/hit_test.h)
int pending_resize_component_ = HTCAPTION;
// TODO(oshima): Use WindowStateType instead.
ui::WindowShowState initial_show_state_ = ui::SHOW_STATE_DEFAULT;
bool notify_bounds_changes_ = true;
bool window_state_is_changing_ = false;
float pending_raster_scale_ = 1.0;
struct InflightFocusRotateRequest {
uint32_t serial;
ash::FocusCycler::Direction direction;
};
std::queue<InflightFocusRotateRequest> rotate_focus_inflight_requests_;
base::ObserverList<ShellSurfaceObserver> observers_;
};
} // namespace exo
#endif // COMPONENTS_EXO_SHELL_SURFACE_H_