blob: ae1f21f8fdadee70f365240b962020462750e074 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/exo/wayland/zcr_remote_shell_impl.h"
#include "ash/public/cpp/arc_resize_lock_type.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shell.h"
#include "ash/wm/window_resizer.h"
#include "base/command_line.h"
#include "chromeos/ui/base/window_pin_type.h"
#include "components/exo/display.h"
#include "components/exo/wayland/server_util.h"
#include "components/exo/wm_helper_chromeos.h"
#include "ui/display/screen.h"
#include "ui/views/window/caption_button_types.h"
#include "ui/wm/core/window_animations.h"
namespace exo {
namespace wayland {
// Ensure that V1 and V2 constants remain identical.
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE) ==
static_cast<int>(
ZCR_REMOTE_SURFACE_V2_SYSTEMUI_VISIBILITY_STATE_VISIBLE),
"ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE and "
"ZCR_REMOTE_SURFACE_V2_SYSTEMUI_VISIBILITY_STATE_VISIBLE should be equal");
static_assert(
static_cast<int>(
ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY) ==
static_cast<int>(
ZCR_REMOTE_SURFACE_V2_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY),
"ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY and "
"ZCR_REMOTE_SURFACE_V2_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY "
"should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_OUTPUT_V1_SYSTEMUI_BEHAVIOR_VISIBLE) ==
static_cast<int>(ZCR_REMOTE_OUTPUT_V2_SYSTEMUI_BEHAVIOR_VISIBLE),
"ZCR_REMOTE_OUTPUT_V1_SYSTEMUI_BEHAVIOR_VISIBLE and "
"ZCR_REMOTE_OUTPUT_V2_SYSTEMUI_BEHAVIOR_VISIBLE should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_OUTPUT_V1_SYSTEMUI_BEHAVIOR_HIDDEN) ==
static_cast<int>(ZCR_REMOTE_OUTPUT_V2_SYSTEMUI_BEHAVIOR_HIDDEN),
"ZCR_REMOTE_OUTPUT_V1_SYSTEMUI_BEHAVIOR_HIDDEN and "
"ZCR_REMOTE_OUTPUT_V2_SYSTEMUI_BEHAVIOR_HIDDEN should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_NONE),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_NONE should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOP) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_TOP),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOP and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_TOP should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPRIGHT) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_TOPRIGHT),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPRIGHT and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_TOPRIGHT should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_RIGHT) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_RIGHT),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_RIGHT and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_RIGHT should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMRIGHT) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_BOTTOMRIGHT),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMRIGHT and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_BOTTOMRIGHT should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOM) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_BOTTOM),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOM and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_BOTTOM should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMLEFT) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_BOTTOMLEFT),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMLEFT and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_BOTTOMLEFT should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_LEFT) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_LEFT),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_LEFT and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_LEFT should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPLEFT) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_TOPLEFT),
"ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPLEFT and "
"ZCR_REMOTE_SURFACE_V2_RESIZE_DIRECTION_TOPLEFT should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET) ==
static_cast<int>(ZCR_REMOTE_SHELL_V2_LAYOUT_MODE_TABLET),
"ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET and "
"ZCR_REMOTE_SHELL_V2_LAYOUT_MODE_TABLET should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED) ==
static_cast<int>(ZCR_REMOTE_SHELL_V2_LAYOUT_MODE_WINDOWED),
"ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED and "
"ZCR_REMOTE_SHELL_V2_LAYOUT_MODE_WINDOWED should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_CLIENT_FOCUSED) ==
static_cast<int>(
ZCR_REMOTE_SHELL_V2_DESKTOP_FOCUS_STATE_CLIENT_FOCUSED),
"ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_CLIENT_FOCUSED and "
"ZCR_REMOTE_SHELL_V2_DESKTOP_FOCUS_STATE_CLIENT_FOCUSED should be equal");
static_assert(
static_cast<int>(
ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_OTHER_CLIENT_FOCUSED) ==
static_cast<int>(
ZCR_REMOTE_SHELL_V2_DESKTOP_FOCUS_STATE_OTHER_CLIENT_FOCUSED),
"ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_OTHER_CLIENT_FOCUSED and "
"ZCR_REMOTE_SHELL_V2_DESKTOP_FOCUS_STATE_OTHER_CLIENT_FOCUSED should be "
"equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_NO_FOCUS) ==
static_cast<int>(ZCR_REMOTE_SHELL_V2_DESKTOP_FOCUS_STATE_NO_FOCUS),
"ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_NO_FOCUS and "
"ZCR_REMOTE_SHELL_V2_DESKTOP_FOCUS_STATE_NO_FOCUS should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_RESIZE) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_RESIZE),
"ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_RESIZE and "
"ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_RESIZE should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_MOVE) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_MOVE),
"ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_MOVE and "
"ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_MOVE should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_PIP) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_PIP),
"ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_PIP and "
"ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_PIP should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_RESIZE) ==
static_cast<int>(
ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_DRAG_RESIZE),
"ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_RESIZE and "
"ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_DRAG_RESIZE should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_MOVE) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_DRAG_MOVE),
"ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_MOVE and "
"ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_DRAG_MOVE should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_LEFT) ==
static_cast<int>(
ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_SNAP_TO_LEFT),
"ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_LEFT and "
"ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_SNAP_TO_LEFT should be equal");
static_assert(
static_cast<int>(
ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_RIGHT) ==
static_cast<int>(
ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_SNAP_TO_RIGHT),
"ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_RIGHT and "
"ZCR_REMOTE_SURFACE_V2_BOUNDS_CHANGE_REASON_SNAP_TO_RIGHT should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_NORMAL) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_NORMAL),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_NORMAL and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_NORMAL should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_MINIMIZED) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_MINIMIZED),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_MINIMIZED and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_MINIMIZED should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_MAXIMIZED) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_MAXIMIZED),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_MAXIMIZED and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_MAXIMIZED should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_FULLSCREEN) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_FULLSCREEN),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_FULLSCREEN and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_FULLSCREEN should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_PINNED) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_PINNED),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_PINNED and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_PINNED should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_TRUSTED_PINNED) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_TRUSTED_PINNED),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_TRUSTED_PINNED and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_TRUSTED_PINNED should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_LEFT_SNAPPED) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_LEFT_SNAPPED),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_LEFT_SNAPPED and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_LEFT_SNAPPED should be equal");
static_assert(
static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_RIGHT_SNAPPED) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_RIGHT_SNAPPED),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_RIGHT_SNAPPED and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_RIGHT_SNAPPED should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SHELL_V1_STATE_TYPE_PIP) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_STATE_TYPE_PIP),
"ZCR_REMOTE_SHELL_V1_STATE_TYPE_PIP and "
"ZCR_REMOTE_SURFACE_V2_STATE_TYPE_PIP should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_IN) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_ZOOM_CHANGE_IN),
"ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_IN and "
"ZCR_REMOTE_SURFACE_V2_ZOOM_CHANGE_IN should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_OUT) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_ZOOM_CHANGE_OUT),
"ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_OUT and "
"ZCR_REMOTE_SURFACE_V2_ZOOM_CHANGE_OUT should be equal");
static_assert(static_cast<int>(ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_RESET) ==
static_cast<int>(ZCR_REMOTE_SURFACE_V2_ZOOM_CHANGE_RESET),
"ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_RESET and "
"ZCR_REMOTE_SURFACE_V2_ZOOM_CHANGE_RESET should be equal");
using chromeos::WindowStateType;
// We don't send configure immediately after tablet mode switch
// because layout can change due to orientation lock state or accelerometer.
constexpr int kConfigureDelayAfterLayoutSwitchMs = 300;
constexpr int kRemoteShellSeatObserverPriority = 0;
static_assert(Seat::IsValidObserverPriority(kRemoteShellSeatObserverPriority),
"kRemoteShellSeatObserverPriority is not in the valid range.");
// Convert to 8.24 fixed format.
int32_t To8_24Fixed(double value) {
constexpr int kDecimalBits = 24;
return static_cast<int32_t>(value * (1 << kDecimalBits));
}
ash::ShelfLayoutManager* GetShelfLayoutManagerForDisplay(
const display::Display& display) {
auto* root = ash::Shell::GetRootWindowForDisplayId(display.id());
return ash::Shelf::ForWindow(root)->shelf_layout_manager();
}
int SystemUiVisibility(const display::Display& display) {
auto* shelf_layout_manager = GetShelfLayoutManagerForDisplay(display);
switch (shelf_layout_manager->visibility_state()) {
case ash::SHELF_VISIBLE:
return ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE;
case ash::SHELF_AUTO_HIDE:
case ash::SHELF_HIDDEN:
return ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY;
}
NOTREACHED() << "Got unexpected shelf visibility state "
<< shelf_layout_manager->visibility_state();
return 0;
}
int SystemUiBehavior(const display::Display& display) {
auto* shelf_layout_manager = GetShelfLayoutManagerForDisplay(display);
switch (shelf_layout_manager->auto_hide_behavior()) {
case ash::ShelfAutoHideBehavior::kNever:
return ZCR_REMOTE_OUTPUT_V1_SYSTEMUI_BEHAVIOR_VISIBLE;
case ash::ShelfAutoHideBehavior::kAlways:
case ash::ShelfAutoHideBehavior::kAlwaysHidden:
return ZCR_REMOTE_OUTPUT_V1_SYSTEMUI_BEHAVIOR_HIDDEN;
}
NOTREACHED() << "Got unexpected shelf visibility behavior.";
return 0;
}
uint32_t ResizeDirection(int component) {
switch (component) {
case HTCAPTION:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE;
case HTTOP:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOP;
case HTTOPRIGHT:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPRIGHT;
case HTRIGHT:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_RIGHT;
case HTBOTTOMRIGHT:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMRIGHT;
case HTBOTTOM:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOM;
case HTBOTTOMLEFT:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMLEFT;
case HTLEFT:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_LEFT;
case HTTOPLEFT:
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPLEFT;
default:
LOG(ERROR) << "Unknown component:" << component;
break;
}
NOTREACHED();
return ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE;
}
// This is a workaround for b/148977363
void MaybeApplyCTSHack(int layout_mode,
const gfx::Size& size_in_pixel,
gfx::Insets* insets_in_client_pixel,
gfx::Insets* stable_insets_in_client_pixel) {
constexpr int kBadBottomInsets = 90;
if (layout_mode == ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET &&
size_in_pixel.width() == 3000 && size_in_pixel.height() == 2000 &&
stable_insets_in_client_pixel->bottom() == kBadBottomInsets) {
stable_insets_in_client_pixel->set_bottom(kBadBottomInsets + 1);
if (insets_in_client_pixel->bottom() == kBadBottomInsets)
insets_in_client_pixel->set_bottom(kBadBottomInsets + 1);
}
}
bool WaylandRemoteOutput::SendDisplayMetrics(const display::Display& display,
uint32_t changed_metrics) {
if (wl_resource_get_version(resource_) <
event_mapping_.stable_insets_since_version) {
return false;
}
if (initial_config_sent_ &&
!(changed_metrics & display::DisplayObserver::DISPLAY_METRIC_WORK_AREA)) {
return false;
}
if (!initial_config_sent_) {
initial_config_sent_ = true;
uint32_t display_id_hi = static_cast<uint32_t>(display.id() >> 32);
uint32_t display_id_lo = static_cast<uint32_t>(display.id());
if (event_mapping_.send_display_id)
event_mapping_.send_display_id(resource_, display_id_hi, display_id_lo);
constexpr int64_t DISPLAY_ID_PORT_MASK = 0xff;
uint32_t port = static_cast<uint32_t>(display.id() & DISPLAY_ID_PORT_MASK);
if (event_mapping_.send_port)
event_mapping_.send_port(resource_, port);
wl_array data;
wl_array_init(&data);
const auto& bytes =
WMHelper::GetInstance()->GetDisplayIdentificationData(display.id());
for (uint8_t byte : bytes) {
uint8_t* ptr =
static_cast<uint8_t*>(wl_array_add(&data, sizeof(uint8_t)));
DCHECK(ptr);
*ptr = byte;
}
event_mapping_.send_identification_data(resource_, &data);
wl_array_release(&data);
}
float device_scale_factor = display.device_scale_factor();
gfx::Size size_in_pixel = display.GetSizeInPixel();
gfx::Insets insets_in_pixel = GetWorkAreaInsetsInPixel(
display, device_scale_factor, size_in_pixel, display.work_area());
event_mapping_.send_insets(resource_, insets_in_pixel.left(),
insets_in_pixel.top(), insets_in_pixel.right(),
insets_in_pixel.bottom());
gfx::Insets stable_insets_in_pixel = GetWorkAreaInsetsInPixel(
display, device_scale_factor, size_in_pixel, GetStableWorkArea(display));
event_mapping_.send_stable_insets(
resource_, stable_insets_in_pixel.left(), stable_insets_in_pixel.top(),
stable_insets_in_pixel.right(), stable_insets_in_pixel.bottom());
// Currently no client uses zcr_remote_output_v1 systemui_visibility.
// Only systemui_behavior is sent here.
if (wl_resource_get_version(resource_) >=
event_mapping_.system_ui_behavior_since_version) {
int systemui_behavior = SystemUiBehavior(display);
event_mapping_.send_systemui_behavior(resource_, systemui_behavior);
}
return true;
}
WaylandRemoteSurfaceDelegate::WaylandRemoteSurfaceDelegate(
base::WeakPtr<WaylandRemoteShell> shell,
wl_resource* resource,
WaylandRemoteShellEventMapping event_mapping)
: shell_(std::move(shell)),
resource_(resource),
event_mapping_(event_mapping) {}
WaylandRemoteSurfaceDelegate::~WaylandRemoteSurfaceDelegate() {
if (shell_)
shell_->OnRemoteSurfaceDestroyed(resource_);
}
// ClientControlledShellSurfaceDelegate:
void WaylandRemoteSurfaceDelegate::OnGeometryChanged(
const gfx::Rect& geometry) {
if (shell_)
shell_->OnRemoteSurfaceGeometryChanged(resource_, geometry);
}
void WaylandRemoteSurfaceDelegate::OnStateChanged(
chromeos::WindowStateType old_state_type,
chromeos::WindowStateType new_state_type) {
shell_->OnRemoteSurfaceStateChanged(resource_, old_state_type,
new_state_type);
}
void WaylandRemoteSurfaceDelegate::OnBoundsChanged(
chromeos::WindowStateType current_state,
chromeos::WindowStateType requested_state,
int64_t display_id,
const gfx::Rect& bounds_in_display,
bool is_resize,
int bounds_change) {
if (shell_) {
shell_->OnRemoteSurfaceBoundsChanged(
resource_, current_state, requested_state, display_id,
bounds_in_display, is_resize, bounds_change);
}
}
void WaylandRemoteSurfaceDelegate::OnDragStarted(int component) {
event_mapping_.send_drag_started(resource_, ResizeDirection(component));
wl_client_flush(wl_resource_get_client(resource_));
}
void WaylandRemoteSurfaceDelegate::OnDragFinished(int x, int y, bool canceled) {
event_mapping_.send_drag_finished(resource_, x, y, canceled ? 1 : 0);
wl_client_flush(wl_resource_get_client(resource_));
}
void WaylandRemoteSurfaceDelegate::OnZoomLevelChanged(ZoomChange zoom_change) {
if (wl_resource_get_version(resource_) >=
event_mapping_.change_zoom_level_since_version &&
shell_) {
shell_->OnRemoteSurfaceChangeZoomLevel(resource_, zoom_change);
}
}
using OutputResourceProvider = base::RepeatingCallback<wl_resource*(int64_t)>;
WaylandRemoteShell::WaylandRemoteShell(
Display* display,
wl_resource* remote_shell_resource,
OutputResourceProvider output_provider,
WaylandRemoteShellEventMapping event_mapping,
bool use_default_scale_cancellation_default)
: event_mapping_(event_mapping),
display_(display),
remote_shell_resource_(remote_shell_resource),
output_provider_(output_provider),
use_default_scale_cancellation_(use_default_scale_cancellation_default),
seat_(display->seat()) {
WMHelperChromeOS* helper = WMHelperChromeOS::GetInstance();
helper->AddTabletModeObserver(this);
helper->AddFrameThrottlingObserver();
helper->SetDefaultScaleCancellation(use_default_scale_cancellation_);
layout_mode_ = helper->InTabletMode()
? ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET
: ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
if (wl_resource_get_version(remote_shell_resource_) >=
event_mapping_.layout_mode_since_version) {
event_mapping_.send_layout_mode(remote_shell_resource_, layout_mode_);
}
if (wl_resource_get_version(remote_shell_resource_) >=
event_mapping_.default_device_scale_factor_since_version) {
double scale_factor = GetDefaultDeviceScaleFactor();
int32_t fixed_scale = To8_24Fixed(scale_factor);
event_mapping_.send_default_device_scale_factor(remote_shell_resource_,
fixed_scale);
}
SendDisplayMetrics();
// The activation event has been moved to aura_shell, but the
// desktop_focus_state event is still in remote_shell, which needs to be
// called before the activation event.
display->seat()->AddObserver(this, kRemoteShellSeatObserverPriority);
}
WaylandRemoteShell::~WaylandRemoteShell() {
WMHelperChromeOS* helper = WMHelperChromeOS::GetInstance();
helper->RemoveTabletModeObserver(this);
helper->RemoveFrameThrottlingObserver();
if (seat_)
seat_->RemoveObserver(this);
}
std::unique_ptr<ClientControlledShellSurface>
WaylandRemoteShell::CreateShellSurface(Surface* surface,
int container,
double default_device_scale_factor) {
return display_->CreateOrGetClientControlledShellSurface(
surface, container, default_device_scale_factor,
use_default_scale_cancellation_);
}
std::unique_ptr<ClientControlledShellSurface::Delegate>
WaylandRemoteShell::CreateShellSurfaceDelegate(wl_resource* resource) {
return std::make_unique<WaylandRemoteSurfaceDelegate>(
weak_ptr_factory_.GetWeakPtr(), resource, event_mapping_);
}
std::unique_ptr<NotificationSurface>
WaylandRemoteShell::CreateNotificationSurface(
Surface* surface,
const std::string& notification_key) {
return display_->CreateNotificationSurface(surface, notification_key);
}
std::unique_ptr<InputMethodSurface>
WaylandRemoteShell::CreateInputMethodSurface(
Surface* surface,
double default_device_scale_factor) {
return display_->CreateInputMethodSurface(
surface, default_device_scale_factor, use_default_scale_cancellation_);
}
std::unique_ptr<ToastSurface> WaylandRemoteShell::CreateToastSurface(
Surface* surface,
double default_device_scale_factor) {
return display_->CreateToastSurface(surface, default_device_scale_factor,
use_default_scale_cancellation_);
}
void WaylandRemoteShell::SetUseDefaultScaleCancellation(
bool use_default_scale) {
use_default_scale_cancellation_ = use_default_scale;
WMHelper::GetInstance()->SetDefaultScaleCancellation(use_default_scale);
}
void WaylandRemoteShell::OnRemoteSurfaceDestroyed(wl_resource* resource) {
// Sometimes resource might be destroyed after bounds change is scheduled to
// |pending_bounds_change_| but before that bounds change is emitted. Erase
// it from |pending_bounds_changes_| to prevent crashes. See also
// https://crbug.com/1163271.
pending_bounds_changes_.erase(resource);
}
// Overridden from display::DisplayObserver:
void WaylandRemoteShell::OnDisplayAdded(const display::Display& new_display) {
ScheduleSendDisplayMetrics(0);
}
void WaylandRemoteShell::OnDisplayRemoved(const display::Display& old_display) {
ScheduleSendDisplayMetrics(0);
}
void WaylandRemoteShell::OnDisplayTabletStateChanged(
display::TabletState state) {
const bool layout_change_started =
state == display::TabletState::kEnteringTabletMode ||
state == display::TabletState::kExitingTabletMode;
if (layout_change_started)
ScheduleSendDisplayMetrics(kConfigureDelayAfterLayoutSwitchMs);
}
void WaylandRemoteShell::OnDisplayMetricsChanged(
const display::Display& display,
uint32_t changed_metrics) {
// No need to update when a primary display has changed without bounds
// change. See WaylandDisplayObserver::OnDisplayMetricsChanged
// for more details.
if (changed_metrics &
(DISPLAY_METRIC_BOUNDS | DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
DISPLAY_METRIC_ROTATION | DISPLAY_METRIC_WORK_AREA)) {
ScheduleSendDisplayMetrics(0);
}
}
// Overridden from ash::TabletModeObserver:
void WaylandRemoteShell::OnTabletModeStarted() {
layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET;
if (wl_resource_get_version(remote_shell_resource_) >=
event_mapping_.layout_mode_since_version)
event_mapping_.send_layout_mode(remote_shell_resource_, layout_mode_);
}
void WaylandRemoteShell::OnTabletModeEnding() {
layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
if (wl_resource_get_version(remote_shell_resource_) >=
event_mapping_.layout_mode_since_version)
event_mapping_.send_layout_mode(remote_shell_resource_, layout_mode_);
}
void WaylandRemoteShell::OnTabletModeEnded() {}
void WaylandRemoteShell::ScheduleSendDisplayMetrics(int delay_ms) {
needs_send_display_metrics_ = true;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&WaylandRemoteShell::SendDisplayMetrics,
weak_ptr_factory_.GetWeakPtr()),
base::Milliseconds(delay_ms));
}
// Returns the transform that a display's output is currently adjusted for.
wl_output_transform WaylandRemoteShell::DisplayTransform(
display::Display::Rotation rotation) {
switch (rotation) {
case display::Display::ROTATE_0:
return WL_OUTPUT_TRANSFORM_NORMAL;
case display::Display::ROTATE_90:
return WL_OUTPUT_TRANSFORM_90;
case display::Display::ROTATE_180:
return WL_OUTPUT_TRANSFORM_180;
case display::Display::ROTATE_270:
return WL_OUTPUT_TRANSFORM_270;
}
NOTREACHED();
return WL_OUTPUT_TRANSFORM_NORMAL;
}
void WaylandRemoteShell::SendDisplayMetrics() {
if (!needs_send_display_metrics_)
return;
needs_send_display_metrics_ = false;
const display::Screen* screen = display::Screen::GetScreen();
double default_dsf = GetDefaultDeviceScaleFactor();
for (const auto& display : screen->GetAllDisplays()) {
double device_scale_factor = display.device_scale_factor();
uint32_t display_id_hi = static_cast<uint32_t>(display.id() >> 32);
uint32_t display_id_lo = static_cast<uint32_t>(display.id());
gfx::Size size_in_pixel = display.GetSizeInPixel();
wl_array data;
wl_array_init(&data);
const auto& bytes =
WMHelper::GetInstance()->GetDisplayIdentificationData(display.id());
for (uint8_t byte : bytes) {
uint8_t* ptr =
static_cast<uint8_t*>(wl_array_add(&data, sizeof(uint8_t)));
DCHECK(ptr);
*ptr = byte;
}
if (wl_resource_get_version(remote_shell_resource_) >=
event_mapping_.send_workspace_info_since_version) {
// Apply the scale factor used on the remote shell client (ARC).
const gfx::Rect& bounds = display.bounds();
// Note: The origin is used just to identify the workspace on the client
// side, and does not account the actual pixel size of other workspace
// on the client side.
int x_px = base::ClampRound(bounds.x() * default_dsf);
int y_px = base::ClampRound(bounds.y() * default_dsf);
float server_to_client_pixel_scale = default_dsf / device_scale_factor;
gfx::Size size_in_client_pixel =
gfx::ScaleToRoundedSize(size_in_pixel, server_to_client_pixel_scale);
gfx::Insets insets_in_client_pixel = GetWorkAreaInsetsInPixel(
display, default_dsf, size_in_client_pixel, display.work_area());
gfx::Insets stable_insets_in_client_pixel =
GetWorkAreaInsetsInPixel(display, default_dsf, size_in_client_pixel,
GetStableWorkArea(display));
// TODO(b/148977363): Fix the issue and remove the hack.
MaybeApplyCTSHack(layout_mode_, size_in_pixel, &insets_in_client_pixel,
&stable_insets_in_client_pixel);
int systemui_visibility = SystemUiVisibility(display);
if (event_mapping_.send_workspace_info)
event_mapping_.send_workspace_info(
remote_shell_resource_, display_id_hi, display_id_lo, x_px, y_px,
size_in_client_pixel.width(), size_in_client_pixel.height(),
insets_in_client_pixel.left(), insets_in_client_pixel.top(),
insets_in_client_pixel.right(), insets_in_client_pixel.bottom(),
stable_insets_in_client_pixel.left(),
stable_insets_in_client_pixel.top(),
stable_insets_in_client_pixel.right(),
stable_insets_in_client_pixel.bottom(), systemui_visibility,
DisplayTransform(display.rotation()), display.IsInternal(), &data);
} else {
NOTREACHED() << "The remote shell resource version being used ("
<< wl_resource_get_version(remote_shell_resource_)
<< ") is not supported.";
}
wl_array_release(&data);
}
if (event_mapping_.send_configure)
event_mapping_.send_configure(remote_shell_resource_, layout_mode_);
base::flat_set<wl_client*> clients;
clients.insert(wl_resource_get_client(remote_shell_resource_));
for (const auto& bounds_change : pending_bounds_changes_) {
SendBoundsChanged(bounds_change.first, bounds_change.second.display_id,
bounds_change.second.bounds_in_display,
bounds_change.second.reason);
clients.insert(wl_resource_get_client(bounds_change.first));
}
pending_bounds_changes_.clear();
for (auto* client : clients)
wl_client_flush(client);
}
void WaylandRemoteShell::OnSurfaceFocused(Surface* gained_focus,
Surface* lost_focus,
bool has_focused_client) {
FocusedSurfaceChanged(gained_focus, lost_focus, has_focused_client);
}
void WaylandRemoteShell::FocusedSurfaceChanged(Surface* gained_active_surface,
Surface* lost_active_surface,
bool has_focused_client) {
if (gained_active_surface == lost_active_surface &&
last_has_focused_client_ == has_focused_client) {
return;
}
last_has_focused_client_ = has_focused_client;
wl_resource* gained_active_surface_resource =
gained_active_surface ? GetSurfaceResource(gained_active_surface)
: nullptr;
wl_resource* lost_active_surface_resource =
lost_active_surface ? GetSurfaceResource(lost_active_surface) : nullptr;
wl_client* client = wl_resource_get_client(remote_shell_resource_);
// If surface that gained active is not owned by remote shell client then
// set it to null.
if (gained_active_surface_resource &&
wl_resource_get_client(gained_active_surface_resource) != client) {
gained_active_surface_resource = nullptr;
}
// If surface that lost active is not owned by remote shell client then
// set it to null.
if (lost_active_surface_resource &&
wl_resource_get_client(lost_active_surface_resource) != client) {
lost_active_surface_resource = nullptr;
}
if (wl_resource_get_version(remote_shell_resource_) >=
event_mapping_.desktop_focus_state_changed_since_version) {
uint32_t focus_state;
if (gained_active_surface_resource) {
focus_state = ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_CLIENT_FOCUSED;
} else if (has_focused_client) {
focus_state =
ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_OTHER_CLIENT_FOCUSED;
} else {
focus_state = ZCR_REMOTE_SHELL_V1_DESKTOP_FOCUS_STATE_NO_FOCUS;
}
event_mapping_.send_desktop_focus_state_changed(remote_shell_resource_,
focus_state);
}
if (event_mapping_.send_activated) {
event_mapping_.send_activated(remote_shell_resource_,
gained_active_surface_resource,
lost_active_surface_resource);
}
wl_client_flush(client);
}
void WaylandRemoteShell::OnRemoteSurfaceBoundsChanged(
wl_resource* resource,
WindowStateType current_state,
WindowStateType requested_state,
int64_t display_id,
const gfx::Rect& bounds_in_display,
bool resize,
int bounds_change) {
zcr_remote_surface_v1_bounds_change_reason reason =
ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_RESIZE;
if (!resize)
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_MOVE;
if (current_state == WindowStateType::kPip)
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_PIP;
if (bounds_change & ash::WindowResizer::kBoundsChange_Resizes) {
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_RESIZE;
} else if (bounds_change & ash::WindowResizer::kBoundsChange_Repositions) {
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_MOVE;
}
// Override the reason only if the window enters snapped mode. If the window
// resizes by dragging in snapped mode, we need to keep the original reason.
if (requested_state != current_state) {
if (requested_state == WindowStateType::kPrimarySnapped) {
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_LEFT;
} else if (requested_state == WindowStateType::kSecondarySnapped) {
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_RIGHT;
}
}
if (needs_send_display_metrics_) {
// We store only the latest bounds for each |resource|.
pending_bounds_changes_.insert_or_assign(
std::move(resource),
BoundsChangeData(display_id, bounds_in_display, reason));
return;
}
SendBoundsChanged(resource, display_id, bounds_in_display, reason);
wl_client_flush(wl_resource_get_client(resource));
}
void WaylandRemoteShell::SendBoundsChanged(
wl_resource* resource,
int64_t display_id,
const gfx::Rect& bounds_in_display,
zcr_remote_surface_v1_bounds_change_reason reason) {
if (event_mapping_.send_bounds_changed)
event_mapping_.send_bounds_changed(
resource, static_cast<uint32_t>(display_id >> 32),
static_cast<uint32_t>(display_id), bounds_in_display.x(),
bounds_in_display.y(), bounds_in_display.width(),
bounds_in_display.height(), reason);
if (wl_resource_get_version(resource) >=
event_mapping_.bounds_changed_in_output_since_version) {
wl_resource* output = output_provider_.Run(display_id);
if (output == nullptr) {
LOG(WARNING) << "Failed to get wayland_output resource for display_id: "
<< display_id;
return;
}
event_mapping_.send_bounds_changed_in_output(
resource, output, bounds_in_display.x(), bounds_in_display.y(),
bounds_in_display.width(), bounds_in_display.height(), reason);
}
}
void WaylandRemoteShell::OnRemoteSurfaceStateChanged(
wl_resource* resource,
WindowStateType old_state_type,
WindowStateType new_state_type) {
DCHECK_NE(old_state_type, new_state_type);
LOG_IF(ERROR, pending_bounds_changes_.count(resource) > 0)
<< "Sending window state while there is a pending bounds change. This "
"should not happen.";
uint32_t state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_NORMAL;
switch (new_state_type) {
case WindowStateType::kMinimized:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_MINIMIZED;
break;
case WindowStateType::kMaximized:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_MAXIMIZED;
break;
case WindowStateType::kFullscreen:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_FULLSCREEN;
break;
case WindowStateType::kPinned:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_PINNED;
break;
case WindowStateType::kTrustedPinned:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_TRUSTED_PINNED;
break;
case WindowStateType::kPrimarySnapped:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_LEFT_SNAPPED;
break;
case WindowStateType::kSecondarySnapped:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_RIGHT_SNAPPED;
break;
case WindowStateType::kPip:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_PIP;
break;
default:
break;
}
event_mapping_.send_state_type_changed(resource, state_type);
wl_client_flush(wl_resource_get_client(resource));
}
void WaylandRemoteShell::OnRemoteSurfaceChangeZoomLevel(wl_resource* resource,
ZoomChange change) {
int32_t value = 0;
switch (change) {
case ZoomChange::IN:
value = ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_IN;
break;
case ZoomChange::OUT:
value = ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_OUT;
break;
case ZoomChange::RESET:
value = ZCR_REMOTE_SURFACE_V1_ZOOM_CHANGE_RESET;
break;
}
event_mapping_.send_change_zoom_level(resource, value);
wl_client_flush(wl_resource_get_client(resource));
}
void WaylandRemoteShell::OnRemoteSurfaceGeometryChanged(
wl_resource* resource,
const gfx::Rect& geometry) {
LOG_IF(ERROR, pending_bounds_changes_.count(resource) > 0)
<< "Sending the new window geometry while there is a pending bounds "
"change. This should not happen.";
event_mapping_.send_window_geometry_changed(resource, geometry.x(),
geometry.y(), geometry.width(),
geometry.height());
wl_client_flush(wl_resource_get_client(resource));
}
namespace switches {
// This flag can be used to emulate device scale factor for remote shell.
constexpr char kForceRemoteShellScale[] = "force-remote-shell-scale";
} // namespace switches
using chromeos::WindowStateType;
namespace zcr_remote_shell {
// Returns the scale factor to be used by remote shell clients.
double GetDefaultDeviceScaleFactor() {
// A flag used by VM to emulate a device scale for a particular board.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kForceRemoteShellScale)) {
std::string value =
command_line->GetSwitchValueASCII(switches::kForceRemoteShellScale);
double scale = 1.0;
if (base::StringToDouble(value, &scale))
return std::max(1.0, scale);
}
return WMHelper::GetInstance()->GetDefaultDeviceScaleFactor();
}
// Scale the |child_bounds| in such a way that if it should fill the
// |parent_size|'s width/height, it returns the |parent_size_in_pixel|'s
// width/height.
gfx::Rect ScaleBoundsToPixelSnappedToParent(
const gfx::Size& parent_size_in_pixel,
const gfx::Size& parent_size,
float device_scale_factor,
const gfx::Rect& child_bounds) {
int right = child_bounds.right();
int bottom = child_bounds.bottom();
int new_x = base::ClampRound(child_bounds.x() * device_scale_factor);
int new_y = base::ClampRound(child_bounds.y() * device_scale_factor);
int new_right = right == parent_size.width()
? parent_size_in_pixel.width()
: base::ClampRound(right * device_scale_factor);
int new_bottom = bottom == parent_size.height()
? parent_size_in_pixel.height()
: base::ClampRound(bottom * device_scale_factor);
return gfx::Rect(new_x, new_y, new_right - new_x, new_bottom - new_y);
}
void ScaleSkRegion(const SkRegion& src, float scale, SkRegion* dst) {
SkRegion::Iterator iter(src);
for (; !iter.done(); iter.next()) {
SkIRect r;
r.fLeft = base::ClampFloor(iter.rect().fLeft * scale);
r.fTop = base::ClampFloor(iter.rect().fTop * scale);
r.fRight = base::ClampCeil(iter.rect().fRight * scale);
r.fBottom = base::ClampCeil(iter.rect().fBottom * scale);
dst->op(r, SkRegion::kUnion_Op);
}
}
int Component(uint32_t direction) {
switch (direction) {
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE:
return HTNOWHERE;
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOP:
return HTTOP;
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPRIGHT:
return HTTOPRIGHT;
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_RIGHT:
return HTRIGHT;
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMRIGHT:
return HTBOTTOMRIGHT;
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOM:
return HTBOTTOM;
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_BOTTOMLEFT:
return HTBOTTOMLEFT;
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_LEFT:
return HTLEFT;
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_TOPLEFT:
return HTTOPLEFT;
default:
VLOG(2) << "Unknown direction:" << direction;
break;
}
return HTNOWHERE;
}
uint32_t CaptionButtonMask(uint32_t mask) {
uint32_t caption_button_icon_mask = 0;
if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_BACK)
caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_BACK;
if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_MENU)
caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_MENU;
if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_MINIMIZE)
caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_MINIMIZE;
if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_MAXIMIZE_RESTORE)
caption_button_icon_mask |= 1
<< views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE;
if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_CLOSE)
caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_CLOSE;
if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_ZOOM)
caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_ZOOM;
if (mask & ZCR_REMOTE_SURFACE_V1_FRAME_BUTTON_TYPE_CENTER)
caption_button_icon_mask |= 1 << views::CAPTION_BUTTON_ICON_CENTER;
return caption_button_icon_mask;
}
////////////////////////////////////////////////////////////////////////////////
// remote_surface_interface:
SurfaceFrameType RemoteShellSurfaceFrameType(uint32_t frame_type) {
switch (frame_type) {
case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_NONE:
return SurfaceFrameType::NONE;
case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_NORMAL:
return SurfaceFrameType::NORMAL;
case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_SHADOW:
return SurfaceFrameType::SHADOW;
case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_AUTOHIDE:
return SurfaceFrameType::AUTOHIDE;
case ZCR_REMOTE_SURFACE_V1_FRAME_TYPE_OVERLAY:
return SurfaceFrameType::OVERLAY;
default:
VLOG(2) << "Unknown remote-shell frame type: " << frame_type;
return SurfaceFrameType::NONE;
}
}
void remote_surface_set_app_id(wl_client* client,
wl_resource* resource,
const char* app_id) {
GetUserDataAs<ShellSurfaceBase>(resource)->SetApplicationId(app_id);
}
void remote_surface_set_window_geometry(wl_client* client,
wl_resource* resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
// DEPRECATED - Use set_bounds to send bounds info with a display_id.
GetUserDataAs<ShellSurfaceBase>(resource)->SetGeometry(
gfx::Rect(x, y, width, height));
}
void remote_surface_set_orientation(wl_client* client,
wl_resource* resource,
int32_t orientation) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetOrientation(
orientation == ZCR_REMOTE_SURFACE_V1_ORIENTATION_PORTRAIT
? Orientation::PORTRAIT
: Orientation::LANDSCAPE);
}
void remote_surface_set_scale(wl_client* client,
wl_resource* resource,
wl_fixed_t scale) {
// DEPRECATED (b/141715728) - The server updates the client's scale.
GetUserDataAs<ClientControlledShellSurface>(resource)->SetScale(
wl_fixed_to_double(scale));
}
void remote_surface_set_rectangular_shadow_DEPRECATED(wl_client* client,
wl_resource* resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
NOTREACHED();
}
void remote_surface_set_rectangular_shadow_background_opacity_DEPRECATED(
wl_client* client,
wl_resource* resource,
wl_fixed_t opacity) {
NOTREACHED();
}
void remote_surface_set_title(wl_client* client,
wl_resource* resource,
const char* title) {
GetUserDataAs<ShellSurfaceBase>(resource)->SetTitle(
std::u16string(base::UTF8ToUTF16(title)));
}
void remote_surface_set_top_inset(wl_client* client,
wl_resource* resource,
int32_t height) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetTopInset(height);
}
void remote_surface_activate(wl_client* client,
wl_resource* resource,
uint32_t serial) {
ShellSurfaceBase* shell_surface = GetUserDataAs<ShellSurfaceBase>(resource);
shell_surface->Activate();
}
void remote_surface_maximize(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetMaximized();
}
void remote_surface_minimize(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetMinimized();
}
void remote_surface_restore(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetRestored();
}
void remote_surface_fullscreen(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetFullscreen(true);
}
void remote_surface_unfullscreen(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetFullscreen(false);
}
void remote_surface_pin(wl_client* client,
wl_resource* resource,
int32_t trusted) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetPinned(
trusted ? chromeos::WindowPinType::kTrustedPinned
: chromeos::WindowPinType::kPinned);
}
void remote_surface_unpin(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetPinned(
chromeos::WindowPinType::kNone);
}
void remote_surface_set_system_modal(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetSystemModal(true);
}
void remote_surface_unset_system_modal(wl_client* client,
wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetSystemModal(false);
}
void remote_surface_set_rectangular_surface_shadow(wl_client* client,
wl_resource* resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
// Shadow Bounds are set in pixels, and should not be scaled.
ClientControlledShellSurface* shell_surface =
GetUserDataAs<ClientControlledShellSurface>(resource);
shell_surface->SetShadowBounds(gfx::Rect(x, y, width, height));
}
void remote_surface_set_systemui_visibility(wl_client* client,
wl_resource* resource,
uint32_t visibility) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetSystemUiVisibility(
visibility != ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE);
}
void remote_surface_set_always_on_top(wl_client* client,
wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetAlwaysOnTop(true);
}
void remote_surface_unset_always_on_top(wl_client* client,
wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetAlwaysOnTop(false);
}
void remote_surface_ack_configure_DEPRECATED(wl_client* client,
wl_resource* resource,
uint32_t serial) {
NOTREACHED();
}
void remote_surface_move_DEPRECATED(wl_client* client, wl_resource* resource) {
NOTREACHED();
}
void remote_surface_set_window_type(wl_client* client,
wl_resource* resource,
uint32_t type) {
auto* widget = GetUserDataAs<ShellSurfaceBase>(resource)->GetWidget();
if (!widget)
return;
switch (type) {
case ZCR_REMOTE_SURFACE_V1_WINDOW_TYPE_NORMAL:
widget->GetNativeWindow()->SetProperty(ash::kHideInOverviewKey, false);
break;
case ZCR_REMOTE_SURFACE_V1_WINDOW_TYPE_SYSTEM_UI:
// TODO(takise): Consider removing this as this window type was added for
// the old assistant and is not longer used.
widget->GetNativeWindow()->SetProperty(ash::kHideInOverviewKey, true);
wm::SetWindowVisibilityAnimationType(
widget->GetNativeWindow(), wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
break;
case ZCR_REMOTE_SURFACE_V1_WINDOW_TYPE_HIDDEN_IN_OVERVIEW:
widget->GetNativeWindow()->SetProperty(ash::kHideInOverviewKey, true);
break;
}
}
void remote_surface_resize_DEPRECATED(wl_client* client,
wl_resource* resource) {
// DEPRECATED
NOTREACHED();
}
void remote_surface_set_resize_outset_DEPRECATED(wl_client* client,
wl_resource* resource,
int32_t outset) {
// DEPRECATED
NOTREACHED();
}
void remote_surface_start_move(wl_client* client,
wl_resource* resource,
int32_t x,
int32_t y) {
ClientControlledShellSurface* shell_surface =
GetUserDataAs<ClientControlledShellSurface>(resource);
float scale = shell_surface->GetClientToDpScale();
gfx::PointF p(x, y);
shell_surface->StartDrag(HTCAPTION, gfx::ScalePoint(p, scale));
}
void remote_surface_set_can_maximize(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetCanMaximize(true);
}
void remote_surface_unset_can_maximize(wl_client* client,
wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetCanMaximize(false);
}
void remote_surface_set_min_size(wl_client* client,
wl_resource* resource,
int32_t width,
int32_t height) {
ClientControlledShellSurface* shell_surface =
GetUserDataAs<ClientControlledShellSurface>(resource);
float scale = shell_surface->GetClientToDpScale();
gfx::Size s(width, height);
shell_surface->SetMinimumSize(gfx::ScaleToRoundedSize(s, scale));
}
void remote_surface_set_max_size(wl_client* client,
wl_resource* resource,
int32_t width,
int32_t height) {
ClientControlledShellSurface* shell_surface =
GetUserDataAs<ClientControlledShellSurface>(resource);
float scale = shell_surface->GetClientToDpScale();
gfx::Size s(width, height);
shell_surface->SetMaximumSize(gfx::ScaleToRoundedSize(s, scale));
}
void remote_surface_set_aspect_ratio(wl_client* client,
wl_resource* resource,
int32_t aspect_ratio_width,
int32_t aspect_ratio_height) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetAspectRatio(
gfx::SizeF(aspect_ratio_width, aspect_ratio_height));
}
void remote_surface_set_snapped_to_left(wl_client* client,
wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetSnappedToPrimary();
}
void remote_surface_set_snapped_to_right(wl_client* client,
wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)
->SetSnappedToSecondary();
}
void remote_surface_start_resize(wl_client* client,
wl_resource* resource,
uint32_t direction,
int32_t x,
int32_t y) {
ClientControlledShellSurface* shell_surface =
GetUserDataAs<ClientControlledShellSurface>(resource);
float scale = shell_surface->GetClientToDpScale();
gfx::PointF p(x, y);
shell_surface->StartDrag(Component(direction), gfx::ScalePoint(p, scale));
}
void remote_surface_set_frame(wl_client* client,
wl_resource* resource,
uint32_t type) {
ClientControlledShellSurface* shell_surface =
GetUserDataAs<ClientControlledShellSurface>(resource);
shell_surface->root_surface()->SetFrame(RemoteShellSurfaceFrameType(type));
}
void remote_surface_set_frame_buttons(wl_client* client,
wl_resource* resource,
uint32_t visible_button_mask,
uint32_t enabled_button_mask) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetFrameButtons(
CaptionButtonMask(visible_button_mask),
CaptionButtonMask(enabled_button_mask));
}
void remote_surface_set_extra_title(wl_client* client,
wl_resource* resource,
const char* extra_title) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetExtraTitle(
std::u16string(base::UTF8ToUTF16(extra_title)));
}
chromeos::OrientationType OrientationLock(uint32_t orientation_lock) {
switch (orientation_lock) {
case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_NONE:
return chromeos::OrientationType::kAny;
case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_CURRENT:
return chromeos::OrientationType::kCurrent;
case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT:
return chromeos::OrientationType::kPortrait;
case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE:
return chromeos::OrientationType::kLandscape;
case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT_PRIMARY:
return chromeos::OrientationType::kPortraitPrimary;
case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT_SECONDARY:
return chromeos::OrientationType::kPortraitSecondary;
case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE_PRIMARY:
return chromeos::OrientationType::kLandscapePrimary;
case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE_SECONDARY:
return chromeos::OrientationType::kLandscapeSecondary;
}
VLOG(2) << "Unexpected value of orientation_lock: " << orientation_lock;
return chromeos::OrientationType::kAny;
}
void remote_surface_set_orientation_lock(wl_client* client,
wl_resource* resource,
uint32_t orientation_lock) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetOrientationLock(
OrientationLock(orientation_lock));
}
void remote_surface_pip(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetPip();
}
void remote_surface_set_bounds(wl_client* client,
wl_resource* resource,
uint32_t display_id_hi,
uint32_t display_id_lo,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
// Bounds are set in pixels, and should not be scaled.
GetUserDataAs<ClientControlledShellSurface>(resource)->SetBounds(
static_cast<int64_t>(display_id_hi) << 32 | display_id_lo,
gfx::Rect(x, y, width, height));
}
void remote_surface_block_ime(wl_client* client, wl_resource* resource) {
NOTIMPLEMENTED();
}
void remote_surface_unblock_ime(wl_client* client, wl_resource* resource) {
NOTIMPLEMENTED();
}
void remote_surface_set_accessibility_id(wl_client* client,
wl_resource* resource,
int32_t accessibility_id) {
GetUserDataAs<ClientControlledShellSurface>(resource)
->SetClientAccessibilityId(accessibility_id);
}
void remote_surface_set_pip_original_window(wl_client* client,
wl_resource* resource) {
auto* widget = GetUserDataAs<ShellSurfaceBase>(resource)->GetWidget();
if (!widget) {
LOG(ERROR) << "no widget found for setting pip original window";
return;
}
widget->GetNativeWindow()->SetProperty(ash::kPipOriginalWindowKey, true);
}
void remote_surface_unset_pip_original_window(wl_client* client,
wl_resource* resource) {
auto* widget = GetUserDataAs<ShellSurfaceBase>(resource)->GetWidget();
if (!widget) {
LOG(ERROR) << "no widget found for unsetting pip original window";
return;
}
widget->GetNativeWindow()->SetProperty(ash::kPipOriginalWindowKey, false);
}
void remote_surface_set_system_gesture_exclusion(wl_client* client,
wl_resource* resource,
wl_resource* region_resource) {
auto* shell_surface = GetUserDataAs<ClientControlledShellSurface>(resource);
auto* widget = shell_surface->GetWidget();
if (!widget) {
LOG(ERROR) << "no widget found for setting system gesture exclusion";
return;
}
if (region_resource) {
SkRegion* dst = new SkRegion;
ScaleSkRegion(*GetUserDataAs<SkRegion>(region_resource),
shell_surface->GetClientToDpScale(), dst);
widget->GetNativeWindow()->SetProperty(ash::kSystemGestureExclusionKey,
dst);
} else {
widget->GetNativeWindow()->ClearProperty(ash::kSystemGestureExclusionKey);
}
}
void remote_surface_set_resize_lock(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetResizeLockType(
ash::ArcResizeLockType::RESIZE_DISABLED_TOGGLABLE);
}
void remote_surface_unset_resize_lock(wl_client* client,
wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetResizeLockType(
ash::ArcResizeLockType::NONE);
}
void remote_surface_set_bounds_in_output(wl_client* client,
wl_resource* resource,
wl_resource* output_resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
WaylandDisplayHandler* display_handler =
GetUserDataAs<WaylandDisplayHandler>(output_resource);
// Bounds are set in pixels, and should not be scaled.
GetUserDataAs<ClientControlledShellSurface>(resource)->SetBounds(
display_handler->id(), gfx::Rect(x, y, width, height));
}
void remote_surface_set_resize_lock_type(wl_client* client,
wl_resource* resource,
uint32_t type) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetResizeLockType(
static_cast<ash::ArcResizeLockType>(type));
}
////////////////////////////////////////////////////////////////////////////////
// notification_surface_interface:
void notification_surface_set_app_id(wl_client* client,
wl_resource* resource,
const char* app_id) {
GetUserDataAs<NotificationSurface>(resource)->SetApplicationId(app_id);
}
////////////////////////////////////////////////////////////////////////////////
// input_method_surface_interface:
void input_method_surface_set_bounds(wl_client* client,
wl_resource* resource,
uint32_t display_id_hi,
uint32_t display_id_lo,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
GetUserDataAs<InputMethodSurface>(resource)->SetBounds(
static_cast<int64_t>(display_id_hi) << 32 | display_id_lo,
gfx::Rect(x, y, width, height));
}
void input_method_surface_set_bounds_in_output(wl_client* client,
wl_resource* resource,
wl_resource* output_resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
WaylandDisplayHandler* display_handler =
GetUserDataAs<WaylandDisplayHandler>(output_resource);
GetUserDataAs<InputMethodSurface>(resource)->SetBounds(
display_handler->id(), gfx::Rect(x, y, width, height));
}
////////////////////////////////////////////////////////////////////////////////
// toast_surface_interface:
void toast_surface_set_position(wl_client* client,
wl_resource* resource,
uint32_t display_id_hi,
uint32_t display_id_lo,
int32_t x,
int32_t y) {
GetUserDataAs<ToastSurface>(resource)->SetDisplay(
static_cast<int64_t>(display_id_hi) << 32 | display_id_lo);
GetUserDataAs<ToastSurface>(resource)->SetBoundsOrigin(gfx::Point(x, y));
}
void toast_surface_set_size(wl_client* client,
wl_resource* resource,
int32_t width,
int32_t height) {
GetUserDataAs<ToastSurface>(resource)->SetBoundsSize(
gfx::Size(width, height));
}
void toast_surface_set_bounds_in_output(wl_client* client,
wl_resource* resource,
wl_resource* output_resource,
int32_t x,
int32_t y,
int32_t width,
int32_t height) {
WaylandDisplayHandler* display_handler =
GetUserDataAs<WaylandDisplayHandler>(output_resource);
GetUserDataAs<ToastSurface>(resource)->SetBounds(
display_handler->id(), gfx::Rect(x, y, width, height));
}
////////////////////////////////////////////////////////////////////////////////
// remote_shell_interface:
void remote_shell_set_use_default_scale_cancellation(
wl_client*,
wl_resource* resource,
int32_t use_default_scale_cancellation) {
auto* shell = GetUserDataAs<WaylandRemoteShell>(resource);
if (wl_resource_get_version(resource) <
shell->event_mapping_.set_use_default_scale_cancellation_since_version) {
return;
}
shell->SetUseDefaultScaleCancellation(use_default_scale_cancellation != 0);
}
} // namespace zcr_remote_shell
} // namespace wayland
} // namespace exo