1 // Copyright 2018 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 #include "components/exo/wayland/zcr_remote_shell.h"
6 
7 #include <remote-shell-unstable-v1-server-protocol.h>
8 #include <wayland-server-core.h>
9 #include <wayland-server-protocol-core.h>
10 
11 #include "ash/public/cpp/shell_window_ids.h"
12 #include "ash/public/cpp/tablet_mode_observer.h"
13 #include "ash/public/cpp/window_pin_type.h"
14 #include "ash/public/cpp/window_properties.h"
15 #include "ash/shelf/shelf.h"
16 #include "ash/shelf/shelf_layout_manager.h"
17 #include "ash/shell.h"
18 #include "ash/wm/desks/desks_util.h"
19 #include "ash/wm/window_resizer.h"
20 #include "ash/wm/window_state.h"
21 #include "ash/wm/work_area_insets.h"
22 #include "base/bind.h"
23 #include "base/command_line.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "components/exo/client_controlled_shell_surface.h"
27 #include "components/exo/display.h"
28 #include "components/exo/input_method_surface.h"
29 #include "components/exo/notification_surface.h"
30 #include "components/exo/shell_surface.h"
31 #include "components/exo/shell_surface_base.h"
32 #include "components/exo/shell_surface_util.h"
33 #include "components/exo/surface_delegate.h"
34 #include "components/exo/wayland/server_util.h"
35 #include "components/exo/wm_helper_chromeos.h"
36 #include "ui/display/display_observer.h"
37 #include "ui/display/screen.h"
38 #include "ui/views/widget/widget.h"
39 #include "ui/views/window/caption_button_types.h"
40 #include "ui/wm/core/coordinate_conversion.h"
41 #include "ui/wm/core/window_animations.h"
42 #include "ui/wm/public/activation_change_observer.h"
43 
44 namespace exo {
45 namespace wayland {
46 
47 namespace {
48 
49 namespace switches {
50 
51 // This flag can be used to emulate device scale factor for remote shell.
52 constexpr char kForceRemoteShellScale[] = "force-remote-shell-scale";
53 
54 }  // namespace switches
55 
56 // We don't send configure immediately after tablet mode switch
57 // because layout can change due to orientation lock state or accelerometer.
58 constexpr int kConfigureDelayAfterLayoutSwitchMs = 300;
59 
60 // Convert to 8.24 fixed format.
To8_24Fixed(double value)61 int32_t To8_24Fixed(double value) {
62   constexpr int kDecimalBits = 24;
63   return static_cast<int32_t>(value * (1 << kDecimalBits));
64 }
65 
ResizeDirection(int component)66 uint32_t ResizeDirection(int component) {
67   switch (component) {
68     case HTCAPTION:
69       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE;
70     case HTTOP:
71       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOP;
72     case HTTOPRIGHT:
73       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPRIGHT;
74     case HTRIGHT:
75       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_RIGHT;
76     case HTBOTTOMRIGHT:
77       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMRIGHT;
78     case HTBOTTOM:
79       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOM;
80     case HTBOTTOMLEFT:
81       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMLEFT;
82     case HTLEFT:
83       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_LEFT;
84     case HTTOPLEFT:
85       return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPLEFT;
86     default:
87       LOG(ERROR) << "Unknown component:" << component;
88       break;
89   }
90   NOTREACHED();
91   return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE;
92 }
93 
94 // Returns the scale factor to be used by remote shell clients.
GetDefaultDeviceScaleFactor()95 double GetDefaultDeviceScaleFactor() {
96   // A flag used by VM to emulate a device scale for a particular board.
97   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
98   if (command_line->HasSwitch(switches::kForceRemoteShellScale)) {
99     std::string value =
100         command_line->GetSwitchValueASCII(switches::kForceRemoteShellScale);
101     double scale = 1.0;
102     if (base::StringToDouble(value, &scale))
103       return std::max(1.0, scale);
104   }
105   return WMHelper::GetInstance()->GetDefaultDeviceScaleFactor();
106 }
107 
108 // Scale the |child_bounds| in such a way that if it should fill the
109 // |parent_size|'s width/height, it returns the |parent_size_in_pixel|'s
110 // width/height.
ScaleBoundsToPixelSnappedToParent(const gfx::Size & parent_size_in_pixel,const gfx::Size & parent_size,float device_scale_factor,const gfx::Rect & child_bounds)111 gfx::Rect ScaleBoundsToPixelSnappedToParent(
112     const gfx::Size& parent_size_in_pixel,
113     const gfx::Size& parent_size,
114     float device_scale_factor,
115     const gfx::Rect& child_bounds) {
116   int right = child_bounds.right();
117   int bottom = child_bounds.bottom();
118 
119   int new_x = gfx::ToRoundedInt(child_bounds.x() * device_scale_factor);
120   int new_y = gfx::ToRoundedInt(child_bounds.y() * device_scale_factor);
121 
122   int new_right = right == parent_size.width()
123                       ? parent_size_in_pixel.width()
124                       : gfx::ToRoundedInt(right * device_scale_factor);
125 
126   int new_bottom = bottom == parent_size.height()
127                        ? parent_size_in_pixel.height()
128                        : gfx::ToRoundedInt(bottom * device_scale_factor);
129   return gfx::Rect(new_x, new_y, new_right - new_x, new_bottom - new_y);
130 }
131 
132 // Create the insets make sure that work area will be within the chrome's
133 // work area when converted to the pixel on client side.
GetAdjustedInsets(const display::Display & display)134 gfx::Insets GetAdjustedInsets(const display::Display& display) {
135   float scale = display.device_scale_factor();
136   gfx::Size size_in_pixel = display.GetSizeInPixel();
137   gfx::Rect work_area_in_display = display.work_area();
138   work_area_in_display.Offset(-display.bounds().x(), -display.bounds().y());
139   gfx::Rect work_area_in_pixel = ScaleBoundsToPixelSnappedToParent(
140       size_in_pixel, display.bounds().size(), scale, work_area_in_display);
141   gfx::Insets insets_in_pixel =
142       gfx::Rect(size_in_pixel).InsetsFrom(work_area_in_pixel);
143   return gfx::Insets(gfx::ToCeiledInt(insets_in_pixel.top() / scale),
144                      gfx::ToCeiledInt(insets_in_pixel.left() / scale),
145                      gfx::ToCeiledInt(insets_in_pixel.bottom() / scale),
146                      gfx::ToCeiledInt(insets_in_pixel.right() / scale));
147 }
148 
GetShelfLayoutManagerForDisplay(const display::Display & display)149 ash::ShelfLayoutManager* GetShelfLayoutManagerForDisplay(
150     const display::Display& display) {
151   auto* root = ash::Shell::GetRootWindowForDisplayId(display.id());
152   return ash::Shelf::ForWindow(root)->shelf_layout_manager();
153 }
154 
Component(uint32_t direction)155 int Component(uint32_t direction) {
156   switch (direction) {
157     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE:
158       return HTNOWHERE;
159     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOP:
160       return HTTOP;
161     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPRIGHT:
162       return HTTOPRIGHT;
163     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_RIGHT:
164       return HTRIGHT;
165     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMRIGHT:
166       return HTBOTTOMRIGHT;
167     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOM:
168       return HTBOTTOM;
169     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMLEFT:
170       return HTBOTTOMLEFT;
171     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_LEFT:
172       return HTLEFT;
173     case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPLEFT:
174       return HTTOPLEFT;
175     default:
176       VLOG(2) << "Unknown direction:" << direction;
177       break;
178   }
179   return HTNOWHERE;
180 }
181 
CaptionButtonMask(uint32_t mask)182 uint32_t CaptionButtonMask(uint32_t mask) {
183   uint32_t caption_button_icon_mask = 0;
184   if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_BACK)
185     caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_BACK;
186   if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_MENU)
187     caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_MENU;
188   if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_MINIMIZE)
189     caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_MINIMIZE;
190   if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_MAXIMIZE_RESTORE)
191     caption_button_icon_mask |= 1
192                                 << views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE;
193   if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_CLOSE)
194     caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_CLOSE;
195   if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_ZOOM)
196     caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_ZOOM;
197   return caption_button_icon_mask;
198 }
199 
MaybeApplyCTSHack(int layout_mode,const gfx::Size & size_in_pixel,gfx::Insets * insets_in_client_pixel,gfx::Insets * stable_insets_in_client_pixel)200 void MaybeApplyCTSHack(int layout_mode,
201                        const gfx::Size& size_in_pixel,
202                        gfx::Insets* insets_in_client_pixel,
203                        gfx::Insets* stable_insets_in_client_pixel) {
204   constexpr int kBadBottomInsets = 90;
205   if (layout_mode == ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET &&
206       size_in_pixel.width() == 3000 && size_in_pixel.height() == 2000 &&
207       stable_insets_in_client_pixel->bottom() == kBadBottomInsets) {
208     stable_insets_in_client_pixel->set_bottom(kBadBottomInsets + 1);
209     if (insets_in_client_pixel->bottom() == kBadBottomInsets)
210       insets_in_client_pixel->set_bottom(kBadBottomInsets + 1);
211   }
212 }
213 
214 ////////////////////////////////////////////////////////////////////////////////
215 // remote_surface_interface:
216 
RemoteShellSurfaceFrameType(uint32_t frame_type)217 SurfaceFrameType RemoteShellSurfaceFrameType(uint32_t frame_type) {
218   switch (frame_type) {
219     case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_NONE:
220       return SurfaceFrameType::NONE;
221     case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_NORMAL:
222       return SurfaceFrameType::NORMAL;
223     case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_SHADOW:
224       return SurfaceFrameType::SHADOW;
225     case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_AUTOHIDE:
226       return SurfaceFrameType::AUTOHIDE;
227     case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_OVERLAY:
228       return SurfaceFrameType::OVERLAY;
229     default:
230       VLOG(2) << "Unknown remote-shell frame type: " << frame_type;
231       return SurfaceFrameType::NONE;
232   }
233 }
234 
remote_surface_destroy(wl_client * client,wl_resource * resource)235 void remote_surface_destroy(wl_client* client, wl_resource* resource) {
236   wl_resource_destroy(resource);
237 }
238 
remote_surface_set_app_id(wl_client * client,wl_resource * resource,const char * app_id)239 void remote_surface_set_app_id(wl_client* client,
240                                wl_resource* resource,
241                                const char* app_id) {
242   GetUserDataAs<ShellSurfaceBase>(resource)->SetApplicationId(app_id);
243 }
244 
remote_surface_set_window_geometry(wl_client * client,wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)245 void remote_surface_set_window_geometry(wl_client* client,
246                                         wl_resource* resource,
247                                         int32_t x,
248                                         int32_t y,
249                                         int32_t width,
250                                         int32_t height) {
251   GetUserDataAs<ShellSurfaceBase>(resource)->SetGeometry(
252       gfx::Rect(x, y, width, height));
253 }
254 
remote_surface_set_orientation(wl_client * client,wl_resource * resource,int32_t orientation)255 void remote_surface_set_orientation(wl_client* client,
256                                     wl_resource* resource,
257                                     int32_t orientation) {
258   GetUserDataAs<ClientControlledShellSurface>(resource)->SetOrientation(
259       orientation == ZCR_REMOTE_SURFACE_V1_ORIENTATION_PORTRAIT
260           ? Orientation::PORTRAIT
261           : Orientation::LANDSCAPE);
262 }
263 
remote_surface_set_scale(wl_client * client,wl_resource * resource,wl_fixed_t scale)264 void remote_surface_set_scale(wl_client* client,
265                               wl_resource* resource,
266                               wl_fixed_t scale) {
267   GetUserDataAs<ClientControlledShellSurface>(resource)->SetScale(
268       wl_fixed_to_double(scale));
269 }
270 
remote_surface_set_rectangular_shadow_DEPRECATED(wl_client * client,wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)271 void remote_surface_set_rectangular_shadow_DEPRECATED(wl_client* client,
272                                                       wl_resource* resource,
273                                                       int32_t x,
274                                                       int32_t y,
275                                                       int32_t width,
276                                                       int32_t height) {
277   NOTIMPLEMENTED();
278 }
279 
remote_surface_set_rectangular_shadow_background_opacity_DEPRECATED(wl_client * client,wl_resource * resource,wl_fixed_t opacity)280 void remote_surface_set_rectangular_shadow_background_opacity_DEPRECATED(
281     wl_client* client,
282     wl_resource* resource,
283     wl_fixed_t opacity) {
284   NOTIMPLEMENTED();
285 }
286 
remote_surface_set_title(wl_client * client,wl_resource * resource,const char * title)287 void remote_surface_set_title(wl_client* client,
288                               wl_resource* resource,
289                               const char* title) {
290   GetUserDataAs<ShellSurfaceBase>(resource)->SetTitle(
291       base::string16(base::UTF8ToUTF16(title)));
292 }
293 
remote_surface_set_top_inset(wl_client * client,wl_resource * resource,int32_t height)294 void remote_surface_set_top_inset(wl_client* client,
295                                   wl_resource* resource,
296                                   int32_t height) {
297   GetUserDataAs<ClientControlledShellSurface>(resource)->SetTopInset(height);
298 }
299 
remote_surface_activate(wl_client * client,wl_resource * resource,uint32_t serial)300 void remote_surface_activate(wl_client* client,
301                              wl_resource* resource,
302                              uint32_t serial) {
303   ShellSurfaceBase* shell_surface = GetUserDataAs<ShellSurfaceBase>(resource);
304   shell_surface->Activate();
305 }
306 
remote_surface_maximize(wl_client * client,wl_resource * resource)307 void remote_surface_maximize(wl_client* client, wl_resource* resource) {
308   GetUserDataAs<ClientControlledShellSurface>(resource)->SetMaximized();
309 }
310 
remote_surface_minimize(wl_client * client,wl_resource * resource)311 void remote_surface_minimize(wl_client* client, wl_resource* resource) {
312   GetUserDataAs<ClientControlledShellSurface>(resource)->SetMinimized();
313 }
314 
remote_surface_restore(wl_client * client,wl_resource * resource)315 void remote_surface_restore(wl_client* client, wl_resource* resource) {
316   GetUserDataAs<ClientControlledShellSurface>(resource)->SetRestored();
317 }
318 
remote_surface_fullscreen(wl_client * client,wl_resource * resource)319 void remote_surface_fullscreen(wl_client* client, wl_resource* resource) {
320   GetUserDataAs<ClientControlledShellSurface>(resource)->SetFullscreen(true);
321 }
322 
remote_surface_unfullscreen(wl_client * client,wl_resource * resource)323 void remote_surface_unfullscreen(wl_client* client, wl_resource* resource) {
324   GetUserDataAs<ClientControlledShellSurface>(resource)->SetFullscreen(false);
325 }
326 
remote_surface_pin(wl_client * client,wl_resource * resource,int32_t trusted)327 void remote_surface_pin(wl_client* client,
328                         wl_resource* resource,
329                         int32_t trusted) {
330   GetUserDataAs<ClientControlledShellSurface>(resource)->SetPinned(
331       trusted ? ash::WindowPinType::kTrustedPinned
332               : ash::WindowPinType::kPinned);
333 }
334 
remote_surface_unpin(wl_client * client,wl_resource * resource)335 void remote_surface_unpin(wl_client* client, wl_resource* resource) {
336   GetUserDataAs<ClientControlledShellSurface>(resource)->SetPinned(
337       ash::WindowPinType::kNone);
338 }
339 
remote_surface_set_system_modal(wl_client * client,wl_resource * resource)340 void remote_surface_set_system_modal(wl_client* client, wl_resource* resource) {
341   GetUserDataAs<ClientControlledShellSurface>(resource)->SetSystemModal(true);
342 }
343 
remote_surface_unset_system_modal(wl_client * client,wl_resource * resource)344 void remote_surface_unset_system_modal(wl_client* client,
345                                        wl_resource* resource) {
346   GetUserDataAs<ClientControlledShellSurface>(resource)->SetSystemModal(false);
347 }
348 
remote_surface_set_rectangular_surface_shadow(wl_client * client,wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)349 void remote_surface_set_rectangular_surface_shadow(wl_client* client,
350                                                    wl_resource* resource,
351                                                    int32_t x,
352                                                    int32_t y,
353                                                    int32_t width,
354                                                    int32_t height) {
355   ClientControlledShellSurface* shell_surface =
356       GetUserDataAs<ClientControlledShellSurface>(resource);
357   shell_surface->SetShadowBounds(gfx::Rect(x, y, width, height));
358 }
359 
remote_surface_set_systemui_visibility(wl_client * client,wl_resource * resource,uint32_t visibility)360 void remote_surface_set_systemui_visibility(wl_client* client,
361                                             wl_resource* resource,
362                                             uint32_t visibility) {
363   GetUserDataAs<ClientControlledShellSurface>(resource)->SetSystemUiVisibility(
364       visibility != ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE);
365 }
366 
remote_surface_set_always_on_top(wl_client * client,wl_resource * resource)367 void remote_surface_set_always_on_top(wl_client* client,
368                                       wl_resource* resource) {
369   GetUserDataAs<ClientControlledShellSurface>(resource)->SetAlwaysOnTop(true);
370 }
371 
remote_surface_unset_always_on_top(wl_client * client,wl_resource * resource)372 void remote_surface_unset_always_on_top(wl_client* client,
373                                         wl_resource* resource) {
374   GetUserDataAs<ClientControlledShellSurface>(resource)->SetAlwaysOnTop(false);
375 }
376 
remote_surface_ack_configure(wl_client * client,wl_resource * resource,uint32_t serial)377 void remote_surface_ack_configure(wl_client* client,
378                                   wl_resource* resource,
379                                   uint32_t serial) {
380   // DEPRECATED
381 }
382 
remote_surface_move(wl_client * client,wl_resource * resource)383 void remote_surface_move(wl_client* client, wl_resource* resource) {
384   // DEPRECATED
385 }
386 
remote_surface_set_window_type(wl_client * client,wl_resource * resource,uint32_t type)387 void remote_surface_set_window_type(wl_client* client,
388                                     wl_resource* resource,
389                                     uint32_t type) {
390   auto* widget = GetUserDataAs<ShellSurfaceBase>(resource)->GetWidget();
391   if (!widget)
392     return;
393 
394   switch (type) {
395     case ZCR_REMOTE_SURFACE_V1_WINDOW_TYPE_NORMAL:
396       widget->GetNativeWindow()->SetProperty(ash::kHideInOverviewKey, false);
397       break;
398     case ZCR_REMOTE_SURFACE_V1_WINDOW_TYPE_SYSTEM_UI:
399       // TODO(takise): Consider removing this as this window type was added for
400       // the old assistant and is not longer used.
401       widget->GetNativeWindow()->SetProperty(ash::kHideInOverviewKey, true);
402       wm::SetWindowVisibilityAnimationType(
403           widget->GetNativeWindow(), wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
404       break;
405     case ZCR_REMOTE_SURFACE_V1_WINDOW_TYPE_HIDDEN_IN_OVERVIEW:
406       widget->GetNativeWindow()->SetProperty(ash::kHideInOverviewKey, true);
407       break;
408   }
409 }
410 
remote_surface_resize(wl_client * client,wl_resource * resource)411 void remote_surface_resize(wl_client* client, wl_resource* resource) {
412   // DEPRECATED
413 }
414 
remote_surface_set_resize_outset(wl_client * client,wl_resource * resource,int32_t outset)415 void remote_surface_set_resize_outset(wl_client* client,
416                                       wl_resource* resource,
417                                       int32_t outset) {
418   GetUserDataAs<ClientControlledShellSurface>(resource)->SetResizeOutset(
419       outset);
420 }
421 
remote_surface_start_move(wl_client * client,wl_resource * resource,int32_t x,int32_t y)422 void remote_surface_start_move(wl_client* client,
423                                wl_resource* resource,
424                                int32_t x,
425                                int32_t y) {
426   GetUserDataAs<ClientControlledShellSurface>(resource)->StartDrag(
427       HTCAPTION, gfx::PointF(x, y));
428 }
429 
remote_surface_set_can_maximize(wl_client * client,wl_resource * resource)430 void remote_surface_set_can_maximize(wl_client* client, wl_resource* resource) {
431   GetUserDataAs<ClientControlledShellSurface>(resource)->SetCanMaximize(true);
432 }
433 
remote_surface_unset_can_maximize(wl_client * client,wl_resource * resource)434 void remote_surface_unset_can_maximize(wl_client* client,
435                                        wl_resource* resource) {
436   GetUserDataAs<ClientControlledShellSurface>(resource)->SetCanMaximize(false);
437 }
438 
remote_surface_set_min_size(wl_client * client,wl_resource * resource,int32_t width,int32_t height)439 void remote_surface_set_min_size(wl_client* client,
440                                  wl_resource* resource,
441                                  int32_t width,
442                                  int32_t height) {
443   GetUserDataAs<ClientControlledShellSurface>(resource)->SetMinimumSize(
444       gfx::Size(width, height));
445 }
446 
remote_surface_set_max_size(wl_client * client,wl_resource * resource,int32_t width,int32_t height)447 void remote_surface_set_max_size(wl_client* client,
448                                  wl_resource* resource,
449                                  int32_t width,
450                                  int32_t height) {
451   GetUserDataAs<ClientControlledShellSurface>(resource)->SetMaximumSize(
452       gfx::Size(width, height));
453 }
454 
remote_surface_set_aspect_ratio(wl_client * client,wl_resource * resource,int32_t aspect_ratio_width,int32_t aspect_ratio_height)455 void remote_surface_set_aspect_ratio(wl_client* client,
456                                      wl_resource* resource,
457                                      int32_t aspect_ratio_width,
458                                      int32_t aspect_ratio_height) {
459   GetUserDataAs<ClientControlledShellSurface>(resource)->SetAspectRatio(
460       gfx::SizeF(aspect_ratio_width, aspect_ratio_height));
461 }
462 
remote_surface_set_snapped_to_left(wl_client * client,wl_resource * resource)463 void remote_surface_set_snapped_to_left(wl_client* client,
464                                         wl_resource* resource) {
465   GetUserDataAs<ClientControlledShellSurface>(resource)->SetSnappedToLeft();
466 }
467 
remote_surface_set_snapped_to_right(wl_client * client,wl_resource * resource)468 void remote_surface_set_snapped_to_right(wl_client* client,
469                                          wl_resource* resource) {
470   GetUserDataAs<ClientControlledShellSurface>(resource)->SetSnappedToRight();
471 }
472 
remote_surface_start_resize(wl_client * client,wl_resource * resource,uint32_t direction,int32_t x,int32_t y)473 void remote_surface_start_resize(wl_client* client,
474                                  wl_resource* resource,
475                                  uint32_t direction,
476                                  int32_t x,
477                                  int32_t y) {
478   GetUserDataAs<ClientControlledShellSurface>(resource)->StartDrag(
479       Component(direction), gfx::PointF(x, y));
480 }
481 
remote_surface_set_frame(wl_client * client,wl_resource * resource,uint32_t type)482 void remote_surface_set_frame(wl_client* client,
483                               wl_resource* resource,
484                               uint32_t type) {
485   ClientControlledShellSurface* shell_surface =
486       GetUserDataAs<ClientControlledShellSurface>(resource);
487   shell_surface->root_surface()->SetFrame(RemoteShellSurfaceFrameType(type));
488 }
489 
remote_surface_set_frame_buttons(wl_client * client,wl_resource * resource,uint32_t visible_button_mask,uint32_t enabled_button_mask)490 void remote_surface_set_frame_buttons(wl_client* client,
491                                       wl_resource* resource,
492                                       uint32_t visible_button_mask,
493                                       uint32_t enabled_button_mask) {
494   GetUserDataAs<ClientControlledShellSurface>(resource)->SetFrameButtons(
495       CaptionButtonMask(visible_button_mask),
496       CaptionButtonMask(enabled_button_mask));
497 }
498 
remote_surface_set_extra_title(wl_client * client,wl_resource * resource,const char * extra_title)499 void remote_surface_set_extra_title(wl_client* client,
500                                     wl_resource* resource,
501                                     const char* extra_title) {
502   GetUserDataAs<ClientControlledShellSurface>(resource)->SetExtraTitle(
503       base::string16(base::UTF8ToUTF16(extra_title)));
504 }
505 
OrientationLock(uint32_t orientation_lock)506 ash::OrientationLockType OrientationLock(uint32_t orientation_lock) {
507   switch (orientation_lock) {
508     case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_NONE:
509       return ash::OrientationLockType::kAny;
510     case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_CURRENT:
511       return ash::OrientationLockType::kCurrent;
512     case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT:
513       return ash::OrientationLockType::kPortrait;
514     case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE:
515       return ash::OrientationLockType::kLandscape;
516     case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT_PRIMARY:
517       return ash::OrientationLockType::kPortraitPrimary;
518     case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT_SECONDARY:
519       return ash::OrientationLockType::kPortraitSecondary;
520     case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE_PRIMARY:
521       return ash::OrientationLockType::kLandscapePrimary;
522     case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE_SECONDARY:
523       return ash::OrientationLockType::kLandscapeSecondary;
524   }
525   VLOG(2) << "Unexpected value of orientation_lock: " << orientation_lock;
526   return ash::OrientationLockType::kAny;
527 }
528 
remote_surface_set_orientation_lock(wl_client * client,wl_resource * resource,uint32_t orientation_lock)529 void remote_surface_set_orientation_lock(wl_client* client,
530                                          wl_resource* resource,
531                                          uint32_t orientation_lock) {
532   GetUserDataAs<ClientControlledShellSurface>(resource)->SetOrientationLock(
533       OrientationLock(orientation_lock));
534 }
535 
remote_surface_pip(wl_client * client,wl_resource * resource)536 void remote_surface_pip(wl_client* client, wl_resource* resource) {
537   GetUserDataAs<ClientControlledShellSurface>(resource)->SetPip();
538 }
539 
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)540 void remote_surface_set_bounds(wl_client* client,
541                                wl_resource* resource,
542                                uint32_t display_id_hi,
543                                uint32_t display_id_lo,
544                                int32_t x,
545                                int32_t y,
546                                int32_t width,
547                                int32_t height) {
548   GetUserDataAs<ClientControlledShellSurface>(resource)->SetBounds(
549       static_cast<int64_t>(display_id_hi) << 32 | display_id_lo,
550       gfx::Rect(x, y, width, height));
551 }
552 
remote_surface_block_ime(wl_client * client,wl_resource * resource)553 void remote_surface_block_ime(wl_client* client, wl_resource* resource) {
554   GetUserDataAs<ClientControlledShellSurface>(resource)->SetImeBlocked(true);
555 }
556 
remote_surface_unblock_ime(wl_client * client,wl_resource * resource)557 void remote_surface_unblock_ime(wl_client* client, wl_resource* resource) {
558   GetUserDataAs<ClientControlledShellSurface>(resource)->SetImeBlocked(false);
559 }
560 
remote_surface_set_accessibility_id(wl_client * client,wl_resource * resource,int32_t accessibility_id)561 void remote_surface_set_accessibility_id(wl_client* client,
562                                          wl_resource* resource,
563                                          int32_t accessibility_id) {
564   GetUserDataAs<ClientControlledShellSurface>(resource)
565       ->SetClientAccessibilityId(accessibility_id);
566 }
567 
remote_surface_set_pip_original_window(wl_client * client,wl_resource * resource)568 void remote_surface_set_pip_original_window(wl_client* client,
569                                             wl_resource* resource) {
570   auto* widget = GetUserDataAs<ShellSurfaceBase>(resource)->GetWidget();
571   if (!widget) {
572     LOG(ERROR) << "no widget found for setting pip original window";
573     return;
574   }
575 
576   widget->GetNativeWindow()->SetProperty(ash::kPipOriginalWindowKey, true);
577 }
578 
remote_surface_unset_pip_original_window(wl_client * client,wl_resource * resource)579 void remote_surface_unset_pip_original_window(wl_client* client,
580                                               wl_resource* resource) {
581   auto* widget = GetUserDataAs<ShellSurfaceBase>(resource)->GetWidget();
582   if (!widget) {
583     LOG(ERROR) << "no widget found for unsetting pip original window";
584     return;
585   }
586 
587   widget->GetNativeWindow()->SetProperty(ash::kPipOriginalWindowKey, false);
588 }
589 
remote_surface_set_system_gesture_exclusion(wl_client * client,wl_resource * resource,wl_resource * region_resource)590 void remote_surface_set_system_gesture_exclusion(wl_client* client,
591                                                  wl_resource* resource,
592                                                  wl_resource* region_resource) {
593   auto* widget = GetUserDataAs<ShellSurfaceBase>(resource)->GetWidget();
594   if (!widget) {
595     LOG(ERROR) << "no widget found for setting system gesture exclusion";
596     return;
597   }
598 
599   if (region_resource) {
600     widget->GetNativeWindow()->SetProperty(
601         ash::kSystemGestureExclusionKey,
602         new SkRegion(*GetUserDataAs<SkRegion>(region_resource)));
603   } else {
604     widget->GetNativeWindow()->ClearProperty(ash::kSystemGestureExclusionKey);
605   }
606 }
607 
608 const struct zcr_remote_surface_v1_interface remote_surface_implementation = {
609     remote_surface_destroy,
610     remote_surface_set_app_id,
611     remote_surface_set_window_geometry,
612     remote_surface_set_scale,
613     remote_surface_set_rectangular_shadow_DEPRECATED,
614     remote_surface_set_rectangular_shadow_background_opacity_DEPRECATED,
615     remote_surface_set_title,
616     remote_surface_set_top_inset,
617     remote_surface_activate,
618     remote_surface_maximize,
619     remote_surface_minimize,
620     remote_surface_restore,
621     remote_surface_fullscreen,
622     remote_surface_unfullscreen,
623     remote_surface_pin,
624     remote_surface_unpin,
625     remote_surface_set_system_modal,
626     remote_surface_unset_system_modal,
627     remote_surface_set_rectangular_surface_shadow,
628     remote_surface_set_systemui_visibility,
629     remote_surface_set_always_on_top,
630     remote_surface_unset_always_on_top,
631     remote_surface_ack_configure,
632     remote_surface_move,
633     remote_surface_set_orientation,
634     remote_surface_set_window_type,
635     remote_surface_resize,
636     remote_surface_set_resize_outset,
637     remote_surface_start_move,
638     remote_surface_set_can_maximize,
639     remote_surface_unset_can_maximize,
640     remote_surface_set_min_size,
641     remote_surface_set_max_size,
642     remote_surface_set_snapped_to_left,
643     remote_surface_set_snapped_to_right,
644     remote_surface_start_resize,
645     remote_surface_set_frame,
646     remote_surface_set_frame_buttons,
647     remote_surface_set_extra_title,
648     remote_surface_set_orientation_lock,
649     remote_surface_pip,
650     remote_surface_set_bounds,
651     remote_surface_set_aspect_ratio,
652     remote_surface_block_ime,
653     remote_surface_unblock_ime,
654     remote_surface_set_accessibility_id,
655     remote_surface_set_pip_original_window,
656     remote_surface_unset_pip_original_window,
657     remote_surface_set_system_gesture_exclusion};
658 
659 ////////////////////////////////////////////////////////////////////////////////
660 // notification_surface_interface:
661 
notification_surface_destroy(wl_client * client,wl_resource * resource)662 void notification_surface_destroy(wl_client* client, wl_resource* resource) {
663   wl_resource_destroy(resource);
664 }
665 
notification_surface_set_app_id(wl_client * client,wl_resource * resource,const char * app_id)666 void notification_surface_set_app_id(wl_client* client,
667                                      wl_resource* resource,
668                                      const char* app_id) {
669   GetUserDataAs<NotificationSurface>(resource)->SetApplicationId(app_id);
670 }
671 
672 const struct zcr_notification_surface_v1_interface
673     notification_surface_implementation = {notification_surface_destroy,
674                                            notification_surface_set_app_id};
675 
676 ////////////////////////////////////////////////////////////////////////////////
677 // input_method_surface_interface:
678 
input_method_surface_destroy(wl_client * client,wl_resource * resource)679 void input_method_surface_destroy(wl_client* client, wl_resource* resource) {
680   wl_resource_destroy(resource);
681 }
682 
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)683 void input_method_surface_set_bounds(wl_client* client,
684                                      wl_resource* resource,
685                                      uint32_t display_id_hi,
686                                      uint32_t display_id_lo,
687                                      int32_t x,
688                                      int32_t y,
689                                      int32_t width,
690                                      int32_t height) {
691   GetUserDataAs<InputMethodSurface>(resource)->SetBounds(
692       static_cast<int64_t>(display_id_hi) << 32 | display_id_lo,
693       gfx::Rect(x, y, width, height));
694 }
695 
696 const struct zcr_input_method_surface_v1_interface
697     input_method_surface_implementation = {input_method_surface_destroy,
698                                            input_method_surface_set_bounds};
699 
700 ////////////////////////////////////////////////////////////////////////////////
701 // remote_shell_interface:
702 
703 // Implements remote shell interface and monitors workspace state needed
704 // for the remote shell interface.
705 class WaylandRemoteShell : public ash::TabletModeObserver,
706                            public wm::ActivationChangeObserver,
707                            public display::DisplayObserver {
708  public:
WaylandRemoteShell(Display * display,wl_resource * remote_shell_resource)709   WaylandRemoteShell(Display* display, wl_resource* remote_shell_resource)
710       : display_(display), remote_shell_resource_(remote_shell_resource) {
711     WMHelperChromeOS* helper = WMHelperChromeOS::GetInstance();
712     helper->AddTabletModeObserver(this);
713     helper->AddActivationObserver(this);
714     display::Screen::GetScreen()->AddObserver(this);
715 
716     layout_mode_ = helper->InTabletMode()
717                        ? ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET
718                        : ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
719 
720     if (wl_resource_get_version(remote_shell_resource_) >= 8) {
721       double scale_factor = GetDefaultDeviceScaleFactor();
722       int32_t fixed_scale = To8_24Fixed(scale_factor);
723       zcr_remote_shell_v1_send_default_device_scale_factor(
724           remote_shell_resource_, fixed_scale);
725     }
726 
727     SendDisplayMetrics();
728     SendActivated(helper->GetActiveWindow(), nullptr);
729   }
~WaylandRemoteShell()730   ~WaylandRemoteShell() override {
731     WMHelperChromeOS* helper = WMHelperChromeOS::GetInstance();
732     helper->RemoveTabletModeObserver(this);
733     helper->RemoveActivationObserver(this);
734     display::Screen::GetScreen()->RemoveObserver(this);
735   }
736 
CreateShellSurface(Surface * surface,int container,double default_device_scale_factor)737   std::unique_ptr<ClientControlledShellSurface> CreateShellSurface(
738       Surface* surface,
739       int container,
740       double default_device_scale_factor) {
741     return display_->CreateClientControlledShellSurface(
742         surface, container, default_device_scale_factor);
743   }
744 
CreateNotificationSurface(Surface * surface,const std::string & notification_key)745   std::unique_ptr<NotificationSurface> CreateNotificationSurface(
746       Surface* surface,
747       const std::string& notification_key) {
748     return display_->CreateNotificationSurface(surface, notification_key);
749   }
750 
CreateInputMethodSurface(Surface * surface,double default_device_scale_factor)751   std::unique_ptr<InputMethodSurface> CreateInputMethodSurface(
752       Surface* surface,
753       double default_device_scale_factor) {
754     return display_->CreateInputMethodSurface(surface,
755                                               default_device_scale_factor);
756   }
757 
758   // TODO(mukai, oshima): rewrite this through delegate-style instead of
759   // creating callbacks.
760   ClientControlledShellSurface::BoundsChangedCallback
CreateBoundsChangedCallback(wl_resource * resource)761   CreateBoundsChangedCallback(wl_resource* resource) {
762     return base::BindRepeating(
763         &WaylandRemoteShell::HandleRemoteSurfaceBoundsChangedCallback,
764         weak_ptr_factory_.GetWeakPtr(), base::Unretained(resource));
765   }
766 
767   ClientControlledShellSurface::ChangeZoomLevelCallback
CreateChangeZoomLevelCallback(wl_resource * resource)768   CreateChangeZoomLevelCallback(wl_resource* resource) {
769     return base::BindRepeating(
770         &WaylandRemoteShell::HandleRemoteSurfaceChangeZoomLevelCallback,
771         weak_ptr_factory_.GetWeakPtr(), base::Unretained(resource));
772   }
773 
CreateStateChangedCallback(wl_resource * resource)774   ClientControlledShellSurface::StateChangedCallback CreateStateChangedCallback(
775       wl_resource* resource) {
776     return base::BindRepeating(
777         &WaylandRemoteShell::HandleRemoteSurfaceStateChangedCallback,
778         weak_ptr_factory_.GetWeakPtr(), base::Unretained(resource));
779   }
780 
781   ClientControlledShellSurface::GeometryChangedCallback
CreateGeometryChangedCallback(wl_resource * resource)782   CreateGeometryChangedCallback(wl_resource* resource) {
783     return base::BindRepeating(
784         &WaylandRemoteShell::HandleRemoteSurfaceGeometryChangedCallback,
785         weak_ptr_factory_.GetWeakPtr(), base::Unretained(resource));
786   }
787 
788   // Overridden from display::DisplayObserver:
OnDisplayAdded(const display::Display & new_display)789   void OnDisplayAdded(const display::Display& new_display) override {
790     ScheduleSendDisplayMetrics(0);
791   }
792 
OnDisplayRemoved(const display::Display & old_display)793   void OnDisplayRemoved(const display::Display& old_display) override {
794     ScheduleSendDisplayMetrics(0);
795   }
796 
OnDisplayMetricsChanged(const display::Display & display,uint32_t changed_metrics)797   void OnDisplayMetricsChanged(const display::Display& display,
798                                uint32_t changed_metrics) override {
799     // No need to update when a primary display has changed without bounds
800     // change. See WaylandDisplayObserver::OnDisplayMetricsChanged
801     // for more details.
802     if (changed_metrics &
803         (DISPLAY_METRIC_BOUNDS | DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
804          DISPLAY_METRIC_ROTATION | DISPLAY_METRIC_WORK_AREA)) {
805       ScheduleSendDisplayMetrics(0);
806     }
807   }
808 
809   // Overridden from ash::TabletModeObserver:
OnTabletModeStarted()810   void OnTabletModeStarted() override {
811     layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET;
812     ScheduleSendDisplayMetrics(kConfigureDelayAfterLayoutSwitchMs);
813   }
OnTabletModeEnding()814   void OnTabletModeEnding() override {
815     layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
816     ScheduleSendDisplayMetrics(kConfigureDelayAfterLayoutSwitchMs);
817   }
OnTabletModeEnded()818   void OnTabletModeEnded() override {}
819 
820   // Overridden from wm::ActivationChangeObserver:
OnWindowActivated(ActivationReason reason,aura::Window * gained_active,aura::Window * lost_active)821   void OnWindowActivated(ActivationReason reason,
822                          aura::Window* gained_active,
823                          aura::Window* lost_active) override {
824     SendActivated(gained_active, lost_active);
825   }
826 
827  private:
ScheduleSendDisplayMetrics(int delay_ms)828   void ScheduleSendDisplayMetrics(int delay_ms) {
829     needs_send_display_metrics_ = true;
830     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
831         FROM_HERE,
832         base::BindOnce(&WaylandRemoteShell::SendDisplayMetrics,
833                        weak_ptr_factory_.GetWeakPtr()),
834         base::TimeDelta::FromMilliseconds(delay_ms));
835   }
836 
837   // Returns the transform that a display's output is currently adjusted for.
DisplayTransform(display::Display::Rotation rotation)838   wl_output_transform DisplayTransform(display::Display::Rotation rotation) {
839     switch (rotation) {
840       case display::Display::ROTATE_0:
841         return WL_OUTPUT_TRANSFORM_NORMAL;
842       case display::Display::ROTATE_90:
843         return WL_OUTPUT_TRANSFORM_90;
844       case display::Display::ROTATE_180:
845         return WL_OUTPUT_TRANSFORM_180;
846       case display::Display::ROTATE_270:
847         return WL_OUTPUT_TRANSFORM_270;
848     }
849     NOTREACHED();
850     return WL_OUTPUT_TRANSFORM_NORMAL;
851   }
852 
SendDisplayMetrics()853   void SendDisplayMetrics() {
854     if (!needs_send_display_metrics_)
855       return;
856     needs_send_display_metrics_ = false;
857 
858     const display::Screen* screen = display::Screen::GetScreen();
859     double default_dsf = GetDefaultDeviceScaleFactor();
860 
861     for (const auto& display : screen->GetAllDisplays()) {
862       const gfx::Rect& bounds = display.bounds();
863 
864       double device_scale_factor = display.device_scale_factor();
865 
866       uint32_t display_id_hi = static_cast<uint32_t>(display.id() >> 32);
867       uint32_t display_id_lo = static_cast<uint32_t>(display.id());
868       gfx::Size size_in_pixel = display.GetSizeInPixel();
869 
870       wl_array data;
871       wl_array_init(&data);
872 
873       const auto& bytes =
874           WMHelper::GetInstance()->GetDisplayIdentificationData(display.id());
875       for (uint8_t byte : bytes) {
876         uint8_t* ptr =
877             static_cast<uint8_t*>(wl_array_add(&data, sizeof(uint8_t)));
878         DCHECK(ptr);
879         *ptr = byte;
880       }
881 
882       if (wl_resource_get_version(remote_shell_resource_) >= 20) {
883         auto* shelf_layout_manager = GetShelfLayoutManagerForDisplay(display);
884 
885         // Apply the scale factor used on the remote shell client (ARC).
886         const gfx::Rect& bounds = display.bounds();
887 
888         // Note: The origin is used just to identify the workspace on the client
889         // side, and does not account the actual pixel size of other workspace
890         // on the client side.
891         int x_px = gfx::ToRoundedInt(bounds.x() * default_dsf);
892         int y_px = gfx::ToRoundedInt(bounds.y() * default_dsf);
893 
894         float server_to_client_pixel_scale = default_dsf / device_scale_factor;
895 
896         gfx::Size size_in_client_pixel = gfx::ScaleToRoundedSize(
897             size_in_pixel, server_to_client_pixel_scale);
898 
899         gfx::Insets insets_in_client_pixel = GetWorkAreaInsetsInClientPixel(
900             display, default_dsf, size_in_client_pixel, display.work_area());
901 
902         gfx::Insets stable_insets_in_client_pixel =
903             GetWorkAreaInsetsInClientPixel(display, default_dsf,
904                                            size_in_client_pixel,
905                                            GetStableWorkArea(display));
906 
907         // TODO(b/148977363): Fix the issue and remove the hack.
908         MaybeApplyCTSHack(layout_mode_, size_in_pixel, &insets_in_client_pixel,
909                           &stable_insets_in_client_pixel);
910 
911         int systemui_visibility =
912             shelf_layout_manager->visibility_state() == ash::SHELF_AUTO_HIDE
913                 ? ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY
914                 : ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE;
915 
916         zcr_remote_shell_v1_send_workspace_info(
917             remote_shell_resource_, display_id_hi, display_id_lo, x_px, y_px,
918             size_in_client_pixel.width(), size_in_client_pixel.height(),
919             insets_in_client_pixel.left(), insets_in_client_pixel.top(),
920             insets_in_client_pixel.right(), insets_in_client_pixel.bottom(),
921             stable_insets_in_client_pixel.left(),
922             stable_insets_in_client_pixel.top(),
923             stable_insets_in_client_pixel.right(),
924             stable_insets_in_client_pixel.bottom(), systemui_visibility,
925             DisplayTransform(display.rotation()), display.IsInternal(), &data);
926       } else {
927         const gfx::Insets& insets = GetAdjustedInsets(display);
928         zcr_remote_shell_v1_send_workspace(
929             remote_shell_resource_, display_id_hi, display_id_lo, bounds.x(),
930             bounds.y(), bounds.width(), bounds.height(), insets.left(),
931             insets.top(), insets.right(), insets.bottom(),
932             DisplayTransform(display.rotation()),
933             wl_fixed_from_double(device_scale_factor), display.IsInternal());
934 
935         if (wl_resource_get_version(remote_shell_resource_) == 19) {
936           zcr_remote_shell_v1_send_display_info(
937               remote_shell_resource_, display_id_hi, display_id_lo,
938               size_in_pixel.width(), size_in_pixel.height(), &data);
939         }
940       }
941 
942       wl_array_release(&data);
943     }
944 
945     zcr_remote_shell_v1_send_configure(remote_shell_resource_, layout_mode_);
946 
947     base::flat_set<wl_client*> clients;
948     clients.insert(wl_resource_get_client(remote_shell_resource_));
949 
950     for (const auto& bounds_change : pending_bounds_changes_) {
951       SendBoundsChanged(bounds_change.first, bounds_change.second.display_id,
952                         bounds_change.second.bounds_in_display,
953                         bounds_change.second.reason);
954       clients.insert(wl_resource_get_client(bounds_change.first));
955     }
956     pending_bounds_changes_.clear();
957 
958     for (auto* client : clients)
959       wl_client_flush(client);
960   }
961 
SendActivated(aura::Window * gained_active,aura::Window * lost_active)962   void SendActivated(aura::Window* gained_active, aura::Window* lost_active) {
963     Surface* gained_active_surface =
964         gained_active ? GetShellMainSurface(gained_active) : nullptr;
965     Surface* lost_active_surface =
966         lost_active ? GetShellMainSurface(lost_active) : nullptr;
967     wl_resource* gained_active_surface_resource =
968         gained_active_surface ? GetSurfaceResource(gained_active_surface)
969                               : nullptr;
970     wl_resource* lost_active_surface_resource =
971         lost_active_surface ? GetSurfaceResource(lost_active_surface) : nullptr;
972 
973     wl_client* client = wl_resource_get_client(remote_shell_resource_);
974 
975     // If surface that gained active is not owned by remote shell client then
976     // set it to null.
977     if (gained_active_surface_resource &&
978         wl_resource_get_client(gained_active_surface_resource) != client) {
979       gained_active_surface_resource = nullptr;
980     }
981 
982     // If surface that lost active is not owned by remote shell client then
983     // set it to null.
984     if (lost_active_surface_resource &&
985         wl_resource_get_client(lost_active_surface_resource) != client) {
986       lost_active_surface_resource = nullptr;
987     }
988 
989     zcr_remote_shell_v1_send_activated(remote_shell_resource_,
990                                        gained_active_surface_resource,
991                                        lost_active_surface_resource);
992     wl_client_flush(client);
993   }
994 
HandleRemoteSurfaceBoundsChangedCallback(wl_resource * resource,ash::WindowStateType current_state,ash::WindowStateType requested_state,int64_t display_id,const gfx::Rect & bounds_in_display,bool resize,int bounds_change)995   void HandleRemoteSurfaceBoundsChangedCallback(
996       wl_resource* resource,
997       ash::WindowStateType current_state,
998       ash::WindowStateType requested_state,
999       int64_t display_id,
1000       const gfx::Rect& bounds_in_display,
1001       bool resize,
1002       int bounds_change) {
1003     zcr_remote_surface_v1_bounds_change_reason reason =
1004         ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_RESIZE;
1005     if (!resize) {
1006       reason = current_state == ash::WindowStateType::kPip
1007                    ? ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_MOVE_PIP
1008                    : ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_MOVE;
1009     }
1010     if (bounds_change & ash::WindowResizer::kBoundsChange_Resizes) {
1011       reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_RESIZE;
1012     } else if (bounds_change & ash::WindowResizer::kBoundsChange_Repositions) {
1013       reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_MOVE;
1014     }
1015     // Override the reason only if the window enters snapped mode. If the window
1016     // resizes by dragging in snapped mode, we need to keep the original reason.
1017     if (requested_state != current_state) {
1018       if (requested_state == ash::WindowStateType::kLeftSnapped) {
1019         reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_LEFT;
1020       } else if (requested_state == ash::WindowStateType::kRightSnapped) {
1021         reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_RIGHT;
1022       }
1023     }
1024     if (wl_resource_get_version(resource) >= 22) {
1025       if (needs_send_display_metrics_) {
1026         pending_bounds_changes_.emplace(
1027             std::make_pair<wl_resource*, BoundsChangeData>(
1028                 std::move(resource),
1029                 BoundsChangeData(display_id, bounds_in_display, reason)));
1030         return;
1031       }
1032       SendBoundsChanged(resource, display_id, bounds_in_display, reason);
1033     } else {
1034       gfx::Rect bounds_in_screen = gfx::Rect(bounds_in_display);
1035       display::Display display;
1036       display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id,
1037                                                             &display);
1038       // The display ID should be valid.
1039       DCHECK(display.is_valid());
1040       if (display.is_valid())
1041         bounds_in_screen.Offset(display.bounds().OffsetFromOrigin());
1042       else
1043         LOG(ERROR) << "Invalid Display in send_bounds_changed:" << display_id;
1044 
1045       zcr_remote_surface_v1_send_bounds_changed(
1046           resource, static_cast<uint32_t>(display_id >> 32),
1047           static_cast<uint32_t>(display_id), bounds_in_screen.x(),
1048           bounds_in_screen.y(), bounds_in_screen.width(),
1049           bounds_in_screen.height(), reason);
1050     }
1051     wl_client_flush(wl_resource_get_client(resource));
1052   }
1053 
SendBoundsChanged(wl_resource * resource,int64_t display_id,const gfx::Rect & bounds_in_display,zcr_remote_surface_v1_bounds_change_reason reason)1054   void SendBoundsChanged(wl_resource* resource,
1055                          int64_t display_id,
1056                          const gfx::Rect& bounds_in_display,
1057                          zcr_remote_surface_v1_bounds_change_reason reason) {
1058     zcr_remote_surface_v1_send_bounds_changed(
1059         resource, static_cast<uint32_t>(display_id >> 32),
1060         static_cast<uint32_t>(display_id), bounds_in_display.x(),
1061         bounds_in_display.y(), bounds_in_display.width(),
1062         bounds_in_display.height(), reason);
1063   }
1064 
HandleRemoteSurfaceStateChangedCallback(wl_resource * resource,ash::WindowStateType old_state_type,ash::WindowStateType new_state_type)1065   void HandleRemoteSurfaceStateChangedCallback(
1066       wl_resource* resource,
1067       ash::WindowStateType old_state_type,
1068       ash::WindowStateType new_state_type) {
1069     DCHECK_NE(old_state_type, new_state_type);
1070     LOG_IF(ERROR, pending_bounds_changes_.count(resource) > 0)
1071         << "Sending window state while there is a pending bounds change. This "
1072            "should not happen.";
1073 
1074     uint32_t state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_NORMAL;
1075     switch (new_state_type) {
1076       case ash::WindowStateType::kMinimized:
1077         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_MINIMIZED;
1078         break;
1079       case ash::WindowStateType::kMaximized:
1080         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_MAXIMIZED;
1081         break;
1082       case ash::WindowStateType::kFullscreen:
1083         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_FULLSCREEN;
1084         break;
1085       case ash::WindowStateType::kPinned:
1086         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_PINNED;
1087         break;
1088       case ash::WindowStateType::kTrustedPinned:
1089         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_TRUSTED_PINNED;
1090         break;
1091       case ash::WindowStateType::kLeftSnapped:
1092         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_LEFT_SNAPPED;
1093         break;
1094       case ash::WindowStateType::kRightSnapped:
1095         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_RIGHT_SNAPPED;
1096         break;
1097       case ash::WindowStateType::kPip:
1098         state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_PIP;
1099         break;
1100       default:
1101         break;
1102     }
1103 
1104     zcr_remote_surface_v1_send_state_type_changed(resource, state_type);
1105     wl_client_flush(wl_resource_get_client(resource));
1106   }
1107 
HandleRemoteSurfaceChangeZoomLevelCallback(wl_resource * resource,ZoomChange change)1108   void HandleRemoteSurfaceChangeZoomLevelCallback(wl_resource* resource,
1109                                                   ZoomChange change) {
1110     int32_t value = 0;
1111     switch (change) {
1112       case ZoomChange::IN:
1113         value = ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_IN;
1114         break;
1115       case ZoomChange::OUT:
1116         value = ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_OUT;
1117         break;
1118       case ZoomChange::RESET:
1119         value = ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_RESET;
1120         break;
1121     }
1122     zcr_remote_surface_v1_send_change_zoom_level(resource, value);
1123   }
1124 
HandleRemoteSurfaceGeometryChangedCallback(wl_resource * resource,const gfx::Rect & geometry)1125   void HandleRemoteSurfaceGeometryChangedCallback(wl_resource* resource,
1126                                                   const gfx::Rect& geometry) {
1127     LOG_IF(ERROR, pending_bounds_changes_.count(resource) > 0)
1128         << "Sending the new window geometry while there is a pending bounds "
1129            "change. This should not happen.";
1130     zcr_remote_surface_v1_send_window_geometry_changed(
1131         resource, geometry.x(), geometry.y(), geometry.width(),
1132         geometry.height());
1133     wl_client_flush(wl_resource_get_client(resource));
1134   }
1135 
1136   struct BoundsChangeData {
1137     int64_t display_id;
1138     gfx::Rect bounds_in_display;
1139     zcr_remote_surface_v1_bounds_change_reason reason;
BoundsChangeDataexo::wayland::__anon52ed0c540111::WaylandRemoteShell::BoundsChangeData1140     BoundsChangeData(int64_t display_id,
1141                      const gfx::Rect& bounds,
1142                      zcr_remote_surface_v1_bounds_change_reason reason)
1143         : display_id(display_id), bounds_in_display(bounds), reason(reason) {}
1144   };
1145 
1146   // The exo display instance. Not owned.
1147   Display* const display_;
1148 
1149   // The remote shell resource associated with observer.
1150   wl_resource* const remote_shell_resource_;
1151 
1152   bool needs_send_display_metrics_ = true;
1153 
1154   int layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
1155 
1156   base::flat_map<wl_resource*, BoundsChangeData> pending_bounds_changes_;
1157 
1158   base::WeakPtrFactory<WaylandRemoteShell> weak_ptr_factory_{this};
1159 
1160   DISALLOW_COPY_AND_ASSIGN(WaylandRemoteShell);
1161 };
1162 
remote_shell_destroy(wl_client * client,wl_resource * resource)1163 void remote_shell_destroy(wl_client* client, wl_resource* resource) {
1164   // Nothing to do here.
1165 }
1166 
RemoteSurfaceContainer(uint32_t container)1167 int RemoteSurfaceContainer(uint32_t container) {
1168   switch (container) {
1169     case ZCR_REMOTE_SHELL_V1_CONTAINER_DEFAULT:
1170       return ash::desks_util::GetActiveDeskContainerId();
1171     case ZCR_REMOTE_SHELL_V1_CONTAINER_OVERLAY:
1172       return ash::kShellWindowId_SystemModalContainer;
1173     default:
1174       DLOG(WARNING) << "Unsupported container: " << container;
1175       return ash::desks_util::GetActiveDeskContainerId();
1176   }
1177 }
1178 
HandleRemoteSurfaceCloseCallback(wl_resource * resource)1179 void HandleRemoteSurfaceCloseCallback(wl_resource* resource) {
1180   zcr_remote_surface_v1_send_close(resource);
1181   wl_client_flush(wl_resource_get_client(resource));
1182 }
1183 
HandleRemoteSurfaceDragStartedCallback(wl_resource * resource,int component)1184 void HandleRemoteSurfaceDragStartedCallback(wl_resource* resource,
1185                                             int component) {
1186   zcr_remote_surface_v1_send_drag_started(resource, ResizeDirection(component));
1187   wl_client_flush(wl_resource_get_client(resource));
1188 }
1189 
HandleRemoteSurfaceDragFinishedCallback(wl_resource * resource,int x,int y,bool canceled)1190 void HandleRemoteSurfaceDragFinishedCallback(wl_resource* resource,
1191                                              int x,
1192                                              int y,
1193                                              bool canceled) {
1194   zcr_remote_surface_v1_send_drag_finished(resource, x, y, canceled ? 1 : 0);
1195   wl_client_flush(wl_resource_get_client(resource));
1196 }
1197 
remote_shell_get_remote_surface(wl_client * client,wl_resource * resource,uint32_t id,wl_resource * surface,uint32_t container)1198 void remote_shell_get_remote_surface(wl_client* client,
1199                                      wl_resource* resource,
1200                                      uint32_t id,
1201                                      wl_resource* surface,
1202                                      uint32_t container) {
1203   WaylandRemoteShell* shell = GetUserDataAs<WaylandRemoteShell>(resource);
1204   double default_scale_factor = wl_resource_get_version(resource) >= 8
1205                                     ? GetDefaultDeviceScaleFactor()
1206                                     : 1.0;
1207 
1208   std::unique_ptr<ClientControlledShellSurface> shell_surface =
1209       shell->CreateShellSurface(GetUserDataAs<Surface>(surface),
1210                                 RemoteSurfaceContainer(container),
1211                                 default_scale_factor);
1212   if (!shell_surface) {
1213     wl_resource_post_error(resource, ZCR_REMOTE_SHELL_V1_ERROR_ROLE,
1214                            "surface has already been assigned a role");
1215     return;
1216   }
1217 
1218   wl_resource* remote_surface_resource =
1219       wl_resource_create(client, &zcr_remote_surface_v1_interface,
1220                          wl_resource_get_version(resource), id);
1221 
1222   if (wl_resource_get_version(remote_surface_resource) < 18)
1223     shell_surface->set_server_reparent_window(true);
1224 
1225   shell_surface->set_close_callback(
1226       base::BindRepeating(&HandleRemoteSurfaceCloseCallback,
1227                           base::Unretained(remote_surface_resource)));
1228   shell_surface->set_state_changed_callback(
1229       shell->CreateStateChangedCallback(remote_surface_resource));
1230   shell_surface->set_geometry_changed_callback(
1231       shell->CreateGeometryChangedCallback(remote_surface_resource));
1232   shell_surface->set_surface_destroyed_callback(base::BindOnce(
1233       &wl_resource_destroy, base::Unretained(remote_surface_resource)));
1234 
1235   DCHECK(wl_resource_get_version(remote_surface_resource) >= 10);
1236   shell_surface->set_bounds_changed_callback(
1237       shell->CreateBoundsChangedCallback(remote_surface_resource));
1238   shell_surface->set_drag_started_callback(
1239       base::BindRepeating(&HandleRemoteSurfaceDragStartedCallback,
1240                           base::Unretained(remote_surface_resource)));
1241   shell_surface->set_drag_finished_callback(
1242       base::BindRepeating(&HandleRemoteSurfaceDragFinishedCallback,
1243                           base::Unretained(remote_surface_resource)));
1244 
1245   if (wl_resource_get_version(remote_surface_resource) >= 23) {
1246     shell_surface->set_change_zoom_level_callback(
1247         shell->CreateChangeZoomLevelCallback(remote_surface_resource));
1248   }
1249 
1250   SetImplementation(remote_surface_resource, &remote_surface_implementation,
1251                     std::move(shell_surface));
1252 }
1253 
remote_shell_get_notification_surface(wl_client * client,wl_resource * resource,uint32_t id,wl_resource * surface,const char * notification_key)1254 void remote_shell_get_notification_surface(wl_client* client,
1255                                            wl_resource* resource,
1256                                            uint32_t id,
1257                                            wl_resource* surface,
1258                                            const char* notification_key) {
1259   if (GetUserDataAs<Surface>(surface)->HasSurfaceDelegate()) {
1260     wl_resource_post_error(resource, ZCR_REMOTE_SHELL_V1_ERROR_ROLE,
1261                            "surface has already been assigned a role");
1262     return;
1263   }
1264 
1265   std::unique_ptr<NotificationSurface> notification_surface =
1266       GetUserDataAs<WaylandRemoteShell>(resource)->CreateNotificationSurface(
1267           GetUserDataAs<Surface>(surface), std::string(notification_key));
1268   if (!notification_surface) {
1269     wl_resource_post_error(resource,
1270                            ZCR_REMOTE_SHELL_V1_ERROR_INVALID_NOTIFICATION_KEY,
1271                            "invalid notification key");
1272     return;
1273   }
1274 
1275   wl_resource* notification_surface_resource =
1276       wl_resource_create(client, &zcr_notification_surface_v1_interface,
1277                          wl_resource_get_version(resource), id);
1278   SetImplementation(notification_surface_resource,
1279                     &notification_surface_implementation,
1280                     std::move(notification_surface));
1281 }
1282 
remote_shell_get_input_method_surface(wl_client * client,wl_resource * resource,uint32_t id,wl_resource * surface)1283 void remote_shell_get_input_method_surface(wl_client* client,
1284                                            wl_resource* resource,
1285                                            uint32_t id,
1286                                            wl_resource* surface) {
1287   if (GetUserDataAs<Surface>(surface)->HasSurfaceDelegate()) {
1288     wl_resource_post_error(resource, ZCR_REMOTE_SHELL_V1_ERROR_ROLE,
1289                            "surface has already been assigned a role");
1290     return;
1291   }
1292 
1293   std::unique_ptr<ClientControlledShellSurface> input_method_surface =
1294       GetUserDataAs<WaylandRemoteShell>(resource)->CreateInputMethodSurface(
1295           GetUserDataAs<Surface>(surface), GetDefaultDeviceScaleFactor());
1296   if (!input_method_surface) {
1297     wl_resource_post_error(resource, ZCR_REMOTE_SHELL_V1_ERROR_ROLE,
1298                            "Cannot create an IME surface");
1299     return;
1300   }
1301 
1302   wl_resource* input_method_surface_resource =
1303       wl_resource_create(client, &zcr_input_method_surface_v1_interface,
1304                          wl_resource_get_version(resource), id);
1305   SetImplementation(input_method_surface_resource,
1306                     &input_method_surface_implementation,
1307                     std::move(input_method_surface));
1308 }
1309 
1310 const struct zcr_remote_shell_v1_interface remote_shell_implementation = {
1311     remote_shell_destroy, remote_shell_get_remote_surface,
1312     remote_shell_get_notification_surface,
1313     remote_shell_get_input_method_surface};
1314 
1315 }  // namespace
1316 
bind_remote_shell(wl_client * client,void * data,uint32_t version,uint32_t id)1317 void bind_remote_shell(wl_client* client,
1318                        void* data,
1319                        uint32_t version,
1320                        uint32_t id) {
1321   wl_resource* resource =
1322       wl_resource_create(client, &zcr_remote_shell_v1_interface,
1323                          std::min(version, kZcrRemoteShellVersion), id);
1324 
1325   SetImplementation(resource, &remote_shell_implementation,
1326                     std::make_unique<WaylandRemoteShell>(
1327                         static_cast<Display*>(data), resource));
1328 }
1329 
GetWorkAreaInsetsInClientPixel(const display::Display & display,float default_dsf,const gfx::Size & size_in_client_pixel,const gfx::Rect & work_area_in_dp)1330 gfx::Insets GetWorkAreaInsetsInClientPixel(
1331     const display::Display& display,
1332     float default_dsf,
1333     const gfx::Size& size_in_client_pixel,
1334     const gfx::Rect& work_area_in_dp) {
1335   gfx::Rect local_work_area_in_dp = work_area_in_dp;
1336   local_work_area_in_dp.Offset(-display.bounds().x(), -display.bounds().y());
1337   gfx::Rect work_area_in_client_pixel = ScaleBoundsToPixelSnappedToParent(
1338       size_in_client_pixel, display.bounds().size(), default_dsf,
1339       local_work_area_in_dp);
1340   gfx::Insets insets_in_client_pixel =
1341       gfx::Rect(size_in_client_pixel).InsetsFrom(work_area_in_client_pixel);
1342 
1343   // TODO(oshima): I think this is more conservative than necessary. The correct
1344   // way is to use enclosed rect when converting the work area from dp to
1345   // client pixel, but that led to weird buffer size in overlay detection.
1346   // (crbug.com/920650). Investigate if we can fix it and use enclosed rect.
1347   return gfx::Insets(
1348       gfx::ToRoundedInt(
1349           gfx::ToCeiledInt(insets_in_client_pixel.top() / default_dsf) *
1350           default_dsf),
1351       gfx::ToRoundedInt(
1352           gfx::ToCeiledInt(insets_in_client_pixel.left() / default_dsf) *
1353           default_dsf),
1354       gfx::ToRoundedInt(
1355           gfx::ToCeiledInt(insets_in_client_pixel.bottom() / default_dsf) *
1356           default_dsf),
1357       gfx::ToRoundedInt(
1358           gfx::ToCeiledInt(insets_in_client_pixel.right() / default_dsf) *
1359           default_dsf));
1360 }
1361 
GetStableWorkArea(const display::Display & display)1362 gfx::Rect GetStableWorkArea(const display::Display& display) {
1363   auto* root = ash::Shell::GetRootWindowForDisplayId(display.id());
1364   return ash::WorkAreaInsets::ForWindow(root)->ComputeStableWorkArea();
1365 }
1366 
1367 }  // namespace wayland
1368 }  // namespace exo
1369