chromium/components/exo/wayland/zcr_remote_shell_impl.h

// Copyright 2021 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_WAYLAND_ZCR_REMOTE_SHELL_IMPL_H_
#define COMPONENTS_EXO_WAYLAND_ZCR_REMOTE_SHELL_IMPL_H_

#include <remote-shell-unstable-v1-server-protocol.h>
#include <remote-shell-unstable-v2-server-protocol.h>

#include "ash/wm/window_state.h"
#include "base/memory/raw_ptr.h"
#include "components/exo/client_controlled_shell_surface.h"
#include "components/exo/input_method_surface.h"
#include "components/exo/notification_surface.h"
#include "components/exo/seat.h"
#include "components/exo/seat_observer.h"
#include "components/exo/surface.h"
#include "components/exo/toast_surface.h"
#include "components/exo/wayland/wayland_display_observer.h"
#include "components/exo/wayland/zcr_remote_shell.h"
#include "components/exo/wayland/zcr_remote_shell_event_mapping.h"
#include "ui/display/display_observer.h"
#include "ui/display/manager/display_manager_observer.h"

namespace exo {
namespace wayland {

using chromeos::WindowStateType;

class WaylandRemoteOutput : public WaylandDisplayObserver {
 public:
  WaylandRemoteOutput(wl_resource* resource,
                      WaylandRemoteOutputEventMapping event_mapping,
                      WaylandDisplayHandler* display_handler);
  WaylandRemoteOutput(const WaylandRemoteOutput&) = delete;
  WaylandRemoteOutput& operator=(const WaylandRemoteOutput&) = delete;
  ~WaylandRemoteOutput() override;

  // Overridden from WaylandDisplayObserver:
  bool SendDisplayMetrics(const display::Display& display,
                          uint32_t changed_metrics) override;
  void SendActiveDisplay() override;
  void OnOutputDestroyed() override;

 private:
  const raw_ptr<wl_resource> resource_;

  bool initial_config_sent_ = false;

  WaylandRemoteOutputEventMapping const event_mapping_;

  raw_ptr<WaylandDisplayHandler> display_handler_;
};

// Implements remote shell interface and monitors workspace state needed
// for the remote shell interface.
class WaylandRemoteShell : public display::DisplayObserver,
                           public SeatObserver,
                           public display::DisplayManagerObserver {
 public:
  using OutputResourceProvider = base::RepeatingCallback<wl_resource*(int64_t)>;

  WaylandRemoteShell(Display* display,
                     wl_resource* remote_shell_resource,
                     OutputResourceProvider output_provider,
                     WaylandRemoteShellEventMapping event_mapping,
                     bool use_default_scale_cancellation_default);

  WaylandRemoteShell(const WaylandRemoteShell&) = delete;

  WaylandRemoteShell& operator=(const WaylandRemoteShell&) = delete;

  ~WaylandRemoteShell() override;

  std::unique_ptr<ClientControlledShellSurface> CreateShellSurface(
      Surface* surface,
      int container);

  std::unique_ptr<ClientControlledShellSurface::Delegate>
  CreateShellSurfaceDelegate(wl_resource* resource);
  std::unique_ptr<NotificationSurface> CreateNotificationSurface(
      Surface* surface,
      const std::string& notification_key);

  std::unique_ptr<InputMethodSurface> CreateInputMethodSurface(
      Surface* surface);

  std::unique_ptr<ToastSurface> CreateToastSurface(Surface* surface);

  void SetUseDefaultScaleCancellation(bool use_default_scale);

  void OnRemoteSurfaceDestroyed(wl_resource* resource);

  // Overridden from display::DisplayObserver:
  void OnDisplayAdded(const display::Display& new_display) override;
  void OnDisplaysRemoved(const display::Displays& removed_displays) override;
  void OnDisplayTabletStateChanged(display::TabletState state) override;
  void OnDisplayMetricsChanged(const display::Display& display,
                               uint32_t changed_metrics) override;

  // display::DisplayManagerObserver:
  void OnWillProcessDisplayChanges() override;
  void OnDidProcessDisplayChanges(
      const DisplayConfigurationChange& configuration_change) override;

  // Overridden from SeatObserver:
  void OnSurfaceFocused(Surface* gained_focus,
                        Surface* lost_focus,
                        bool has_focused_surface) override;

  WaylandRemoteShellEventMapping const event_mapping_;

 private:
  friend class WaylandRemoteShellTest;

  void ScheduleSendDisplayMetrics(int delay_ms);

  // Returns the transform that a display's output is currently adjusted for.
  wl_output_transform DisplayTransform(display::Display::Rotation rotation);

  void SendDisplayMetrics();

  void FocusedSurfaceChanged(Surface* gained_active_surface,
                             Surface* lost_active_surface,
                             bool has_focused_client);

  void OnRemoteSurfaceBoundsChanged(wl_resource* resource,
                                    WindowStateType current_state,
                                    WindowStateType requested_state,
                                    int64_t display_id,
                                    const gfx::Rect& bounds_in_display,
                                    bool resize,
                                    int bounds_change,
                                    bool is_adjusted_bounds);

  void SendBoundsChanged(wl_resource* resource,
                         int64_t display_id,
                         const gfx::Rect& bounds_in_display,
                         uint32_t reason);

  void OnRemoteSurfaceStateChanged(wl_resource* resource,
                                   WindowStateType old_state_type,
                                   WindowStateType new_state_type);

  void OnRemoteSurfaceChangeZoomLevel(wl_resource* resource, ZoomChange change);

  void OnRemoteSurfaceGeometryChanged(wl_resource* resource,
                                      const gfx::Rect& geometry);
  struct BoundsChangeData {
    int64_t display_id;
    gfx::Rect bounds_in_display;
    uint32_t reason;
    BoundsChangeData(int64_t display_id,
                     const gfx::Rect& bounds,
                     uint32_t reason)
        : display_id(display_id), bounds_in_display(bounds), reason(reason) {}
  };

  // The exo display instance. Not owned.
  const raw_ptr<Display> display_;

  // The remote shell resource associated with observer.
  const raw_ptr<wl_resource> remote_shell_resource_;

  // Callback to get the wl_output resource for a given display_id.
  OutputResourceProvider const output_provider_;

  // When true, the compositor should use the default_device_scale_factor to
  // undo the scaling on the client buffers. When false, the compositor should
  // use the device_scale_factor for the display for this scaling cancellation.
  // in v2 this is always false.
  bool use_default_scale_cancellation_;

  bool in_display_update_ = false;
  bool needs_send_display_metrics_ = true;

  int layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;

  base::flat_map<wl_resource*, BoundsChangeData> pending_bounds_changes_;

  bool last_has_focused_client_ = false;

  display::ScopedDisplayObserver display_observer_{this};

  base::ScopedObservation<display::DisplayManager,
                          display::DisplayManagerObserver>
      display_manager_observation_{this};

  const raw_ptr<Seat> seat_;

  base::WeakPtrFactory<WaylandRemoteShell> weak_ptr_factory_{this};

  friend class WaylandRemoteSurfaceDelegate;
};

class WaylandRemoteSurfaceDelegate
    : public ClientControlledShellSurface::Delegate {
 public:
  WaylandRemoteSurfaceDelegate(base::WeakPtr<WaylandRemoteShell> shell,
                               wl_resource* resource,
                               WaylandRemoteShellEventMapping event_mapping);
  ~WaylandRemoteSurfaceDelegate() override;
  WaylandRemoteSurfaceDelegate(const WaylandRemoteSurfaceDelegate&) = delete;
  WaylandRemoteSurfaceDelegate& operator=(const WaylandRemoteSurfaceDelegate&) =
      delete;

 private:
  // ClientControlledShellSurfaceDelegate:
  void OnGeometryChanged(const gfx::Rect& geometry) override;
  void OnStateChanged(chromeos::WindowStateType old_state_type,
                      chromeos::WindowStateType new_state_type) override;
  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,
                       bool is_adjusted_bounds) override;
  void OnDragStarted(int component) override;
  void OnDragFinished(int x, int y, bool canceled) override;
  void OnZoomLevelChanged(ZoomChange zoom_change) override;

  base::WeakPtr<WaylandRemoteShell> shell_;
  raw_ptr<wl_resource> resource_;
  WaylandRemoteShellEventMapping const event_mapping_;
};

namespace zcr_remote_shell {

double GetDefaultDeviceScaleFactor();

gfx::Rect ScaleBoundsToPixelSnappedToParent(
    const gfx::Size& parent_size_in_pixel,
    const gfx::Size& parent_size,
    float device_scale_factor,
    const gfx::Rect& child_bounds);

void remote_surface_destroy(wl_client* client, wl_resource* resource);
void remote_surface_set_app_id(wl_client* client,
                               wl_resource* resource,
                               const char* app_id);
void remote_surface_set_window_geometry(wl_client* client,
                                        wl_resource* resource,
                                        int32_t x,
                                        int32_t y,
                                        int32_t width,
                                        int32_t height);
void remote_surface_set_orientation(wl_client* client,
                                    wl_resource* resource,
                                    int32_t orientation);

void remote_surface_set_title(wl_client* client,
                              wl_resource* resource,
                              const char* title);
void remote_surface_set_top_inset(wl_client* client,
                                  wl_resource* resource,
                                  int32_t height);

void remote_surface_maximize(wl_client* client, wl_resource* resource);
void remote_surface_minimize(wl_client* client, wl_resource* resource);
void remote_surface_restore(wl_client* client, wl_resource* resource);

void remote_surface_fullscreen(wl_client* client, wl_resource* resource);

void remote_surface_pin(wl_client* client,
                        wl_resource* resource,
                        int32_t trusted);

void remote_surface_unpin(wl_client* client, wl_resource* resource);
void remote_surface_set_system_modal(wl_client* client, wl_resource* resource);

void remote_surface_unset_system_modal(wl_client* client,
                                       wl_resource* resource);

void remote_surface_set_rectangular_surface_shadow(wl_client* client,
                                                   wl_resource* resource,
                                                   int32_t x,
                                                   int32_t y,
                                                   int32_t width,
                                                   int32_t height);
void remote_surface_set_systemui_visibility(wl_client* client,
                                            wl_resource* resource,
                                            uint32_t visibility);
void remote_surface_set_always_on_top(wl_client* client, wl_resource* resource);
void remote_surface_unset_always_on_top(wl_client* client,
                                        wl_resource* resource);

void remote_surface_start_move(wl_client* client,
                               wl_resource* resource,
                               int32_t x,
                               int32_t y);
void remote_surface_set_can_maximize(wl_client* client, wl_resource* resource);
void remote_surface_unset_can_maximize(wl_client* client,
                                       wl_resource* resource);
void remote_surface_set_min_size(wl_client* client,
                                 wl_resource* resource,
                                 int32_t width,
                                 int32_t height);
void remote_surface_set_max_size(wl_client* client,
                                 wl_resource* resource,
                                 int32_t width,
                                 int32_t height);
void remote_surface_set_aspect_ratio(wl_client* client,
                                     wl_resource* resource,
                                     int32_t aspect_ratio_width,
                                     int32_t aspect_ratio_height);
void remote_surface_set_snapped_to_left(wl_client* client,
                                        wl_resource* resource);

void remote_surface_set_snapped_to_right(wl_client* client,
                                         wl_resource* resource);
void remote_surface_start_resize(wl_client* client,
                                 wl_resource* resource,
                                 uint32_t direction,
                                 int32_t x,
                                 int32_t y);
void remote_surface_set_frame(wl_client* client,
                              wl_resource* resource,
                              uint32_t type);
void remote_surface_set_frame_buttons(wl_client* client,
                                      wl_resource* resource,
                                      uint32_t visible_button_mask,
                                      uint32_t enabled_button_mask);
void remote_surface_set_extra_title(wl_client* client,
                                    wl_resource* resource,
                                    const char* extra_title);
void remote_surface_set_orientation_lock(wl_client* client,
                                         wl_resource* resource,
                                         uint32_t orientation_lock);
void remote_surface_pip(wl_client* client, wl_resource* resource);
void remote_surface_set_bounds(wl_client* client,
                               wl_resource* resource,
                               uint32_t display_id_hi,
                               uint32_t display_id_lo,
                               int32_t x,
                               int32_t y,
                               int32_t width,
                               int32_t height);

void remote_surface_set_accessibility_id_DEPRECATED(wl_client* client,
                                                    wl_resource* resource,
                                                    int32_t accessibility_id);
void remote_surface_set_pip_original_window(wl_client* client,
                                            wl_resource* resource);
void remote_surface_unset_pip_original_window(wl_client* client,
                                              wl_resource* resource);

void remote_surface_set_system_gesture_exclusion(wl_client* client,
                                                 wl_resource* resource,
                                                 wl_resource* region_resource);
void remote_surface_set_resize_lock(wl_client* client, wl_resource* resource);
void remote_surface_unset_resize_lock(wl_client* client, wl_resource* resource);

void remote_surface_set_bounds_in_output(wl_client* client,
                                         wl_resource* resource,
                                         wl_resource* output_resource,
                                         int32_t x,
                                         int32_t y,
                                         int32_t width,
                                         int32_t height);

void remote_surface_set_resize_lock_type(wl_client* client,
                                         wl_resource* resource,
                                         uint32_t mode);

void remote_surface_set_scale_factor(wl_client* client,
                                     wl_resource* resource,
                                     uint mode);

void remote_surface_set_window_corner_radii(wl_client* client,
                                            wl_resource* resource,
                                            uint32_t upper_left_radius,
                                            uint32_t upper_right_radius,
                                            uint32_t lower_right_radius,
                                            uint32_t lower_left_radius);

void remote_surface_set_shadow_corner_radii(wl_client* client,
                                            wl_resource* resource,
                                            uint32_t upper_left_radius,
                                            uint32_t upper_right_radius,
                                            uint32_t lower_right_radius,
                                            uint32_t lower_left_radius);

void remote_surface_set_float(wl_client* client, wl_resource* resource);

void remote_surface_block_ime(wl_client* client, wl_resource* resource);

void remote_surface_unblock_ime(wl_client* client, wl_resource* resource);

void remote_surface_set_window_type(wl_client* client,
                                    wl_resource* resource,
                                    uint32_t type);

void remote_surface_set_scale(wl_client* client,
                              wl_resource* resource,
                              wl_fixed_t scale);

void remote_surface_activate(wl_client* client,
                             wl_resource* resource,
                             uint32_t serial);

void remote_surface_unfullscreen(wl_client* client, wl_resource* resource);

void remote_surface_fullscreen(wl_client* client, wl_resource* resource);

void remote_surface_ack_configure_DEPRECATED(wl_client* client,
                                             wl_resource* resource,
                                             uint32_t serial);

void remote_surface_move_DEPRECATED(wl_client* client, wl_resource* resource);

void remote_surface_resize_DEPRECATED(wl_client* client, wl_resource* resource);

void remote_surface_set_resize_outset_DEPRECATED(wl_client* client,
                                                 wl_resource* resource,
                                                 int32_t outset);

void remote_surface_set_rectangular_shadow_DEPRECATED(wl_client* client,
                                                      wl_resource* resource,
                                                      int32_t x,
                                                      int32_t y,
                                                      int32_t width,
                                                      int32_t height);

void remote_surface_set_rectangular_shadow_background_opacity_DEPRECATED(
    wl_client* client,
    wl_resource* resource,
    wl_fixed_t opacity);

////////////////////////////////////////////////////////////////////////////////
// notification_surface_interface:

void notification_surface_set_app_id(wl_client* client,
                                     wl_resource* resource,
                                     const char* app_id);

////////////////////////////////////////////////////////////////////////////////
// input_method_surface_interface:

void input_method_surface_set_bounds_in_output(wl_client* client,
                                               wl_resource* resource,
                                               wl_resource* output_resource,
                                               int32_t x,
                                               int32_t y,
                                               int32_t width,
                                               int32_t height);

void input_method_surface_set_bounds(wl_client* client,
                                     wl_resource* resource,
                                     uint32_t display_id_hi,
                                     uint32_t display_id_lo,
                                     int32_t x,
                                     int32_t y,
                                     int32_t width,
                                     int32_t height);

////////////////////////////////////////////////////////////////////////////////
// toast_surface_interface:

void toast_surface_set_bounds_in_output(wl_client* client,
                                        wl_resource* resource,
                                        wl_resource* output_resource,
                                        int32_t x,
                                        int32_t y,
                                        int32_t width,
                                        int32_t height);

void toast_surface_set_position(wl_client* client,
                                wl_resource* resource,
                                uint32_t display_id_hi,
                                uint32_t display_id_lo,
                                int32_t x,
                                int32_t y);

void toast_surface_set_size(wl_client* client,
                            wl_resource* resource,
                            int32_t width,
                            int32_t height);

void toast_surface_set_bounds_in_output(wl_client* client,
                                        wl_resource* resource,
                                        wl_resource* output_resource,
                                        int32_t x,
                                        int32_t y,
                                        int32_t width,
                                        int32_t height);

void toast_surface_set_scale_factor(wl_client* client,
                                    wl_resource* resource,
                                    uint scale_factor_as_uint);

////////////////////////////////////////////////////////////////////////////////
// remote_shell_interface:

void remote_shell_set_use_default_scale_cancellation(
    wl_client*,
    wl_resource* resource,
    int32_t use_default_scale_cancellation);

}  // namespace zcr_remote_shell
}  // namespace wayland
}  // namespace exo

#endif  // COMPONENTS_EXO_WAYLAND_ZCR_REMOTE_SHELL_IMPL_H_