1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef COMPONENTS_EXO_CLIENT_CONTROLLED_SHELL_SURFACE_H_
6 #define COMPONENTS_EXO_CLIENT_CONTROLLED_SHELL_SURFACE_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "ash/display/screen_orientation_controller.h"
12 #include "ash/wm/client_controlled_state.h"
13 #include "base/callback.h"
14 #include "base/macros.h"
15 #include "components/exo/client_controlled_accelerators.h"
16 #include "components/exo/shell_surface_base.h"
17 #include "ui/base/hit_test.h"
18 #include "ui/compositor/compositor_lock.h"
19 
20 namespace ash {
21 class NonClientFrameViewAsh;
22 class RoundedCornerDecorator;
23 class WideFrameView;
24 
25 namespace mojom {
26 enum class WindowPinType;
27 }
28 }  // namespace ash
29 
30 namespace chromeos {
31 class ImmersiveFullscreenController;
32 }  // namespace chromeos
33 
34 namespace exo {
35 class Surface;
36 class ClientControlledAcceleratorTarget;
37 
38 enum class Orientation { PORTRAIT, LANDSCAPE };
39 enum class ZoomChange { IN, OUT, RESET };
40 
41 // This class implements a ShellSurface whose window state and bounds are
42 // controlled by a remote shell client rather than the window manager. The
43 // position specified as part of the geometry is relative to the origin of
44 // the screen coordinate system.
45 class ClientControlledShellSurface : public ShellSurfaceBase,
46                                      public ui::CompositorLockClient {
47  public:
48   ClientControlledShellSurface(Surface* surface,
49                                bool can_minimize,
50                                int container,
51                                bool default_scale_cancellation);
52   ~ClientControlledShellSurface() override;
53 
54   using GeometryChangedCallback =
55       base::RepeatingCallback<void(const gfx::Rect& geometry)>;
56 
set_geometry_changed_callback(const GeometryChangedCallback & callback)57   void set_geometry_changed_callback(const GeometryChangedCallback& callback) {
58     geometry_changed_callback_ = callback;
59   }
60 
set_server_reparent_window(bool reparent)61   void set_server_reparent_window(bool reparent) {
62     server_reparent_window_ = reparent;
63   }
64 
65   // Set bounds in root window coordinates relative to the given display.
66   void SetBounds(int64_t display_id, const gfx::Rect& bounds);
67 
68   // Set origin of bounds for surface while preserving the size.
69   void SetBoundsOrigin(const gfx::Point& origin);
70 
71   // Set size of bounds for surface while preserving the origin.
72   void SetBoundsSize(const gfx::Size& size);
73 
74   // Called when the client was maximized.
75   void SetMaximized();
76 
77   // Called when the client was minimized.
78   void SetMinimized();
79 
80   // Called when the client was restored.
81   void SetRestored();
82 
83   // Called when the client changed the fullscreen state.
84   void SetFullscreen(bool fullscreen);
85 
86   // Called when the client was snapped to left.
87   void SetSnappedToLeft();
88 
89   // Called when the client was snapped to right.
90   void SetSnappedToRight();
91 
92   // Called when the client was set to PIP.
93   void SetPip();
94 
95   // Set the callback to run when the surface state changed.
96   using StateChangedCallback =
97       base::RepeatingCallback<void(chromeos::WindowStateType old_state_type,
98                                    chromeos::WindowStateType new_state_type)>;
set_state_changed_callback(const StateChangedCallback & state_changed_callback)99   void set_state_changed_callback(
100       const StateChangedCallback& state_changed_callback) {
101     state_changed_callback_ = state_changed_callback;
102   }
103 
104   // Set the callback to run when the surface bounds changed.
105   using BoundsChangedCallback =
106       base::RepeatingCallback<void(chromeos::WindowStateType current_state,
107                                    chromeos::WindowStateType requested_state,
108                                    int64_t display_id,
109                                    const gfx::Rect& bounds_in_display,
110                                    bool is_resize,
111                                    int bounds_change)>;
set_bounds_changed_callback(const BoundsChangedCallback & bounds_changed_callback)112   void set_bounds_changed_callback(
113       const BoundsChangedCallback& bounds_changed_callback) {
114     bounds_changed_callback_ = bounds_changed_callback;
115   }
116 
has_bounds_changed_callback()117   bool has_bounds_changed_callback() const {
118     return static_cast<bool>(bounds_changed_callback_);
119   }
120 
121   // Set the callback to run when the drag operation started.
122   using DragStartedCallback = base::RepeatingCallback<void(int direction)>;
set_drag_started_callback(const DragStartedCallback & callback)123   void set_drag_started_callback(const DragStartedCallback& callback) {
124     drag_started_callback_ = callback;
125   }
126 
127   // Set the callback to run when the drag operation finished.
128   using DragFinishedCallback = base::RepeatingCallback<void(int, int, bool)>;
set_drag_finished_callback(const DragFinishedCallback & callback)129   void set_drag_finished_callback(const DragFinishedCallback& callback) {
130     drag_finished_callback_ = callback;
131   }
132 
133   // Set callback to run when user requests to change a zoom level.
134   using ChangeZoomLevelCallback = base::RepeatingCallback<void(ZoomChange)>;
set_change_zoom_level_callback(const ChangeZoomLevelCallback & callback)135   void set_change_zoom_level_callback(const ChangeZoomLevelCallback& callback) {
136     change_zoom_level_callback_ = callback;
137   }
138 
139   // Returns true if this shell surface is currently being dragged.
140   bool IsDragging();
141 
142   // Pin/unpin the surface. Pinned surface cannot be switched to
143   // other windows unless its explicitly unpinned.
144   void SetPinned(chromeos::WindowPinType type);
145 
146   // Sets the surface to be on top of all other windows.
147   void SetAlwaysOnTop(bool always_on_top);
148 
149   // Sets the IME to be blocked so that all events are forwarded by Exo.
150   void SetImeBlocked(bool ime_blocked);
151 
152   // Controls the visibility of the system UI when this surface is active.
153   void SetSystemUiVisibility(bool autohide);
154 
155   // Set orientation for surface.
156   void SetOrientation(Orientation orientation);
157 
158   // Set shadow bounds in surface coordinates. Empty bounds disable the shadow.
159   void SetShadowBounds(const gfx::Rect& bounds);
160 
161   // Set the pending scale.
162   void SetScale(double scale);
163 
164   // Commit the pending scale if it was changed. The scale set by SetScale() is
165   // otherwise committed by OnPostWidgetCommit().
166   void CommitPendingScale();
167 
168   // Set top inset for surface.
169   void SetTopInset(int height);
170 
171   // Set resize outset for surface.
172   void SetResizeOutset(int outset);
173 
174   // Sends the request to change the zoom level to the client.
175   void ChangeZoomLevel(ZoomChange change);
176 
177   // Sends the window state change event to client.
178   void OnWindowStateChangeEvent(chromeos::WindowStateType old_state,
179                                 chromeos::WindowStateType next_state);
180 
181   // Sends the window bounds change event to client. |display_id| specifies in
182   // which display the surface should live in. |drag_bounds_change| is
183   // a masked value of ash::WindowResizer::kBoundsChange_Xxx, and specifies
184   // how the bounds was changed. The bounds change event may also come from a
185   // snapped window state change |requested_state|.
186   void OnBoundsChangeEvent(chromeos::WindowStateType current_state,
187                            chromeos::WindowStateType requested_state,
188                            int64_t display_id,
189                            const gfx::Rect& bounds,
190                            int drag_bounds_change);
191 
192   // Sends the window drag events to client.
193   void OnDragStarted(int component);
194   void OnDragFinished(bool cancel, const gfx::PointF& location);
195 
196   // Starts the drag operation.
197   void StartDrag(int component, const gfx::PointF& location);
198 
199   // Set if the surface can be maximzied.
200   void SetCanMaximize(bool can_maximize);
201 
202   // Update the auto hide frame state.
203   void UpdateAutoHideFrame();
204 
205   // Set the frame button state. The |visible_button_mask| and
206   // |enabled_button_mask| is a bit mask whose position is defined
207   // in views::CaptionButtonIcon enum.
208   void SetFrameButtons(uint32_t frame_visible_button_mask,
209                        uint32_t frame_enabled_button_mask);
210 
211   // Set the extra title for the surface.
212   void SetExtraTitle(const base::string16& extra_title);
213 
214   // Set specific orientation lock for this surface. When this surface is in
215   // foreground and the display can be rotated (e.g. tablet mode), apply the
216   // behavior defined by |orientation_lock|. See more details in
217   // //ash/display/screen_orientation_controller.h.
218   void SetOrientationLock(ash::OrientationLockType orientation_lock);
219 
220   // Set the accessibility ID provided by client for the surface. If
221   // |accessibility_id| is negative value, it will unset the ID.
222   void SetClientAccessibilityId(int32_t accessibility_id);
223 
224   // Overridden from SurfaceTreeHost:
225   void DidReceiveCompositorFrameAck() override;
226 
227   // Overridden from SurfaceDelegate:
228   bool IsInputEnabled(Surface* surface) const override;
229   void OnSetFrame(SurfaceFrameType type) override;
230   void OnSetFrameColors(SkColor active_color, SkColor inactive_color) override;
231 
232   // Overridden from views::WidgetDelegate:
233   bool CanMaximize() const override;
234   std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
235       views::Widget* widget) override;
236   void SaveWindowPlacement(const gfx::Rect& bounds,
237                            ui::WindowShowState show_state) override;
238   bool GetSavedWindowPlacement(const views::Widget* widget,
239                                gfx::Rect* bounds,
240                                ui::WindowShowState* show_state) const override;
241 
242   // Overridden from views::View:
243   gfx::Size GetMaximumSize() const override;
244   void OnDeviceScaleFactorChanged(float old_dsf, float new_dsf) override;
245 
246   // Overridden from aura::WindowObserver:
247   void OnWindowAddedToRootWindow(aura::Window* window) override;
248 
249   // Overridden from display::DisplayObserver:
250   void OnDisplayMetricsChanged(const display::Display& display,
251                                uint32_t changed_metrics) override;
252 
253   // Overridden from ui::CompositorLockClient:
254   void CompositorLockTimedOut() override;
255 
256   // A factory callback to create ClientControlledState::Delegate.
257   using DelegateFactoryCallback = base::RepeatingCallback<
258       std::unique_ptr<ash::ClientControlledState::Delegate>(void)>;
259 
260   // Set the factory callback for unit test.
261   static void SetClientControlledStateDelegateFactoryForTest(
262       const DelegateFactoryCallback& callback);
263 
wide_frame_for_test()264   ash::WideFrameView* wide_frame_for_test() { return wide_frame_.get(); }
265 
266   // Exposed for testing. Returns the effective scale as opposed to
267   // |pending_scale_|.
scale()268   double scale() const { return scale_; }
269 
270   // Used to scale incoming coordinates from the client to DP.
271   float GetClientToDpScale() const;
272 
273  protected:
274   // Overridden from ShellSurfaceBase:
275   float GetScale() const override;
276 
277  private:
278   class ScopedSetBoundsLocally;
279   class ScopedLockedToRoot;
280 
281   // Overridden from ShellSurfaceBase:
282   void SetWidgetBounds(const gfx::Rect& bounds) override;
283   gfx::Rect GetShadowBounds() const override;
284   void InitializeWindowState(ash::WindowState* window_state) override;
285   base::Optional<gfx::Rect> GetWidgetBounds() const override;
286   gfx::Point GetSurfaceOrigin() const override;
287   bool OnPreWidgetCommit() override;
288   void OnPostWidgetCommit() override;
289   void OnSurfaceDestroying(Surface* surface) override;
290   void OnContentSizeChanged(Surface* surface) override;
291 
292   // Update frame status. This may create (or destroy) a wide frame
293   // that spans the full work area width if the surface didn't cover
294   // the work area.
295   void UpdateFrame();
296 
297   void UpdateCaptionButtonModel();
298 
299   void UpdateBackdrop();
300 
301   void UpdateFrameWidth();
302 
303   void UpdateFrameType() override;
304 
305   void AttemptToStartDrag(int component, const gfx::PointF& location);
306 
307   // Lock the compositor if it's not already locked, or extends the
308   // lock timeout if it's already locked.
309   // TODO(reveman): Remove this when using configure callbacks for orientation.
310   // crbug.com/765954
311   void EnsureCompositorIsLockedForOrientationChange();
312 
313   ash::WindowState* GetWindowState();
314   ash::NonClientFrameViewAsh* GetFrameView();
315   const ash::NonClientFrameViewAsh* GetFrameView() const;
316 
317   void EnsurePendingScale();
318   float GetClientToDpPendingScale() const;
319 
320   gfx::Rect GetClientBoundsForWindowBoundsAndWindowState(
321       const gfx::Rect& window_bounds,
322       chromeos::WindowStateType window_state) const;
323 
324   GeometryChangedCallback geometry_changed_callback_;
325 
326   int top_inset_height_ = 0;
327   int pending_top_inset_height_ = 0;
328 
329   double scale_ = 1.0;
330   // The pending scale is initialized to 0.0 to indicate that the scale is not
331   // yet initialized.
332   double pending_scale_ = 0.0;
333 
334   uint32_t frame_visible_button_mask_ = 0;
335   uint32_t frame_enabled_button_mask_ = 0;
336 
337   StateChangedCallback state_changed_callback_;
338   BoundsChangedCallback bounds_changed_callback_;
339   DragStartedCallback drag_started_callback_;
340   DragFinishedCallback drag_finished_callback_;
341   ChangeZoomLevelCallback change_zoom_level_callback_;
342 
343   // TODO(reveman): Use configure callbacks for orientation. crbug.com/765954
344   Orientation pending_orientation_ = Orientation::LANDSCAPE;
345   Orientation orientation_ = Orientation::LANDSCAPE;
346   Orientation expected_orientation_ = Orientation::LANDSCAPE;
347 
348   ash::ClientControlledState* client_controlled_state_ = nullptr;
349 
350   chromeos::WindowStateType pending_window_state_ =
351       chromeos::WindowStateType::kNormal;
352 
353   bool pending_always_on_top_ = false;
354 
355   SurfaceFrameType pending_frame_type_ = SurfaceFrameType::NONE;
356 
357   chromeos::WindowPinType current_pin_;
358 
359   bool can_maximize_ = true;
360 
361   std::unique_ptr<chromeos::ImmersiveFullscreenController>
362       immersive_fullscreen_controller_;
363 
364   std::unique_ptr<ash::WideFrameView> wide_frame_;
365 
366   std::unique_ptr<ash::RoundedCornerDecorator> decorator_;
367 
368   std::unique_ptr<ui::CompositorLock> orientation_compositor_lock_;
369 
370   // The orientation to be applied when widget is being created. Only set when
371   // widget is not created yet orientation lock is being set.
372   ash::OrientationLockType initial_orientation_lock_ =
373       ash::OrientationLockType::kAny;
374   // The extra title to be applied when widget is being created.
375   base::string16 initial_extra_title_ = base::string16();
376 
377   bool preserve_widget_bounds_ = false;
378 
379   // Checking DragDetails is not sufficient to determine if a bounds
380   // request happened during a drag move or resize. If the window resizer
381   // requests a bounds update after completing the drag but before the
382   // drag details are cleaned up, we want to consider that as a regular
383   // bounds update, not a drag move/resize update.
384   bool in_drag_ = false;
385 
386   // N uses older protocol which expects that server will reparent the window.
387   // TODO(oshima): Remove this once all boards are migrated to P or above.
388   bool server_reparent_window_ = false;
389 
390   bool ignore_bounds_change_request_ = false;
391 
392   bool display_rotating_with_pip_ = false;
393 
394   // True if the window state has changed during the commit.
395   bool state_changed_ = false;
396 
397   // When false, the client handles all display scale changes, so the
398   // buffer should be re-scaled to undo any scaling added by exo so that the
399   // 1:1 correspondence between the pixels is maintained.
400   bool use_default_scale_cancellation_ = false;
401 
402   // Client controlled specific accelerator target.
403   std::unique_ptr<ClientControlledAcceleratorTarget> accelerator_target_;
404 
405   // Accessibility ID provided by client.
406   base::Optional<int32_t> client_accessibility_id_;
407 
408   DISALLOW_COPY_AND_ASSIGN(ClientControlledShellSurface);
409 };
410 
411 }  // namespace exo
412 
413 #endif  // COMPONENTS_EXO_CLIENT_CONTROLLED_SHELL_SURFACE_H_
414