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