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 ¬ification_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