| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/exo/wayland/zaura_shell.h" |
| |
| #include <wayland-server-core.h> |
| #include <wayland-server-protocol-core.h> |
| #include <xdg-shell-server-protocol.h> |
| |
| #include <algorithm> |
| #include <limits> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| #include <vector> |
| |
| #include "ash/display/display_util.h" |
| #include "ash/display/screen_orientation_controller.h" |
| #include "ash/focus/focus_cycler.h" |
| #include "ash/public/cpp/window_properties.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "ash/wm/desks/desk.h" |
| #include "ash/wm/desks/desks_controller.h" |
| #include "ash/wm/overview/overview_controller.h" |
| #include "ash/wm/overview/overview_observer.h" |
| #include "ash/wm/window_state.h" |
| #include "base/bit_cast.h" |
| #include "base/compiler_specific.h" |
| #include "base/logging.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/notimplemented.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chromeos/ui/base/window_properties.h" |
| #include "chromeos/ui/base/window_state_type.h" |
| #include "chromeos/ui/frame/frame_utils.h" |
| #include "chromeos/ui/frame/multitask_menu/float_controller_base.h" |
| #include "components/exo/display.h" |
| #include "components/exo/seat.h" |
| #include "components/exo/seat_observer.h" |
| #include "components/exo/shell_surface.h" |
| #include "components/exo/shell_surface_base.h" |
| #include "components/exo/wayland/output_metrics.h" |
| #include "components/exo/wayland/serial_tracker.h" |
| #include "components/exo/wayland/server_util.h" |
| #include "components/exo/wayland/wayland_display_observer.h" |
| #include "components/exo/wayland/wl_output.h" |
| #include "components/exo/wayland/xdg_shell.h" |
| #include "components/exo/wayland/zaura_output_manager.h" |
| #include "components/version_info/version_info.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/window_occlusion_tracker.h" |
| #include "ui/base/wayland/wayland_display_util.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/display/display_observer.h" |
| #include "ui/display/screen.h" |
| #include "ui/gfx/geometry/rounded_corners_f.h" |
| #include "ui/views/corewm/tooltip_controller.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/wm/core/coordinate_conversion.h" |
| #include "ui/wm/public/activation_client.h" |
| #include "ui/wm/public/tooltip_client.h" |
| |
| namespace exo::wayland { |
| |
| namespace { |
| |
| constexpr int kAuraShellSeatObserverPriority = 1; |
| static_assert(Seat::IsValidObserverPriority(kAuraShellSeatObserverPriority), |
| "kAuraShellSeatObserverPriority is not in the valid range."); |
| static_assert(sizeof(uint32_t) == sizeof(float), |
| "Sizes much match for reinterpret cast to be meaningful"); |
| |
| // A property key containing a boolean set to true if na aura surface object is |
| // associated with surface object. |
| DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasAuraSurfaceKey, false) |
| |
| bool TransformRelativeToScreenIsAxisAligned(aura::Window* window) { |
| gfx::Transform transform_relative_to_screen; |
| DCHECK(window->layer()->GetTargetTransformRelativeTo( |
| window->GetRootWindow()->layer(), &transform_relative_to_screen)); |
| transform_relative_to_screen.PostConcat( |
| window->GetRootWindow()->layer()->GetTargetTransform()); |
| return transform_relative_to_screen.Preserves2dAxisAlignment(); |
| } |
| |
| // This does not handle non-axis aligned rotations, but we don't have any |
| // slightly (e.g. 45 degree) windows so it is okay. |
| gfx::Rect GetTransformedBoundsInScreen(aura::Window* window) { |
| DCHECK(TransformRelativeToScreenIsAxisAligned(window)); |
| // This assumes that opposite points on the window bounds rectangle will |
| // be mapped to opposite points on the output rectangle. |
| gfx::Point a = window->bounds().origin(); |
| gfx::Point b = window->bounds().bottom_right(); |
| ::wm::ConvertPointToScreen(window->parent(), &a); |
| ::wm::ConvertPointToScreen(window->parent(), &b); |
| return gfx::Rect(std::min(a.x(), b.x()), std::min(a.y(), b.y()), |
| std::abs(a.x() - b.x()), std::abs(a.y() - b.y())); |
| } |
| |
| SurfaceFrameType AuraSurfaceFrameType(uint32_t frame_type) { |
| switch (frame_type) { |
| case ZAURA_SURFACE_FRAME_TYPE_NONE: |
| return SurfaceFrameType::NONE; |
| case ZAURA_SURFACE_FRAME_TYPE_NORMAL: |
| return SurfaceFrameType::NORMAL; |
| case ZAURA_SURFACE_FRAME_TYPE_SHADOW: |
| return SurfaceFrameType::SHADOW; |
| default: |
| VLOG(2) << "Unkonwn aura-shell frame type: " << frame_type; |
| return SurfaceFrameType::NONE; |
| } |
| } |
| |
| zaura_surface_occlusion_state WaylandOcclusionState( |
| const aura::Window::OcclusionState occlusion_state) { |
| switch (occlusion_state) { |
| case aura::Window::OcclusionState::UNKNOWN: |
| return ZAURA_SURFACE_OCCLUSION_STATE_UNKNOWN; |
| case aura::Window::OcclusionState::VISIBLE: |
| return ZAURA_SURFACE_OCCLUSION_STATE_VISIBLE; |
| case aura::Window::OcclusionState::OCCLUDED: |
| return ZAURA_SURFACE_OCCLUSION_STATE_OCCLUDED; |
| case aura::Window::OcclusionState::HIDDEN: |
| return ZAURA_SURFACE_OCCLUSION_STATE_HIDDEN; |
| } |
| return ZAURA_SURFACE_OCCLUSION_STATE_UNKNOWN; |
| } |
| |
| void aura_surface_set_frame(wl_client* client, |
| wl_resource* resource, |
| uint32_t type) { |
| GetUserDataAs<AuraSurface>(resource)->SetFrame(AuraSurfaceFrameType(type)); |
| } |
| |
| void aura_surface_set_parent(wl_client* client, |
| wl_resource* resource, |
| wl_resource* parent_resource, |
| int32_t x, |
| int32_t y) { |
| GetUserDataAs<AuraSurface>(resource)->SetParent( |
| parent_resource ? GetUserDataAs<AuraSurface>(parent_resource) : nullptr, |
| gfx::Point(x, y)); |
| } |
| |
| void aura_surface_set_frame_colors(wl_client* client, |
| wl_resource* resource, |
| uint32_t active_color, |
| uint32_t inactive_color) { |
| GetUserDataAs<AuraSurface>(resource)->SetFrameColors(active_color, |
| inactive_color); |
| } |
| |
| void aura_surface_set_startup_id(wl_client* client, |
| wl_resource* resource, |
| const char* startup_id) { |
| GetUserDataAs<AuraSurface>(resource)->SetStartupId(startup_id); |
| } |
| |
| void aura_surface_set_application_id(wl_client* client, |
| wl_resource* resource, |
| const char* application_id) { |
| GetUserDataAs<AuraSurface>(resource)->SetApplicationId(application_id); |
| } |
| |
| void aura_surface_set_client_surface_id_DEPRECATED(wl_client* client, |
| wl_resource* resource, |
| int client_surface_id) { |
| // DEPRECATED. Use aura_surface_set_client_surface_str_id |
| std::string client_surface_str_id = base::NumberToString(client_surface_id); |
| GetUserDataAs<AuraSurface>(resource)->SetClientSurfaceId( |
| client_surface_str_id.c_str()); |
| } |
| |
| void aura_surface_set_occlusion_tracking(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->SetOcclusionTracking(true); |
| } |
| |
| void aura_surface_unset_occlusion_tracking(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->SetOcclusionTracking(false); |
| } |
| |
| void aura_surface_activate(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->Activate(); |
| } |
| |
| void aura_surface_draw_attention(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->DrawAttention(); |
| } |
| |
| void aura_surface_set_fullscreen_mode_deprecated(wl_client* client, |
| wl_resource* resource, |
| uint32_t mode) { |
| GetUserDataAs<AuraSurface>(resource)->SetFullscreenMode(mode); |
| } |
| |
| void aura_surface_set_client_surface_str_id(wl_client* client, |
| wl_resource* resource, |
| const char* client_surface_id) { |
| GetUserDataAs<AuraSurface>(resource)->SetClientSurfaceId(client_surface_id); |
| } |
| |
| void aura_surface_set_server_start_resize(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->SetServerStartResize(); |
| } |
| |
| void aura_surface_intent_to_snap_deprecated(wl_client* client, |
| wl_resource* resource, |
| uint32_t snap_direction) { |
| GetUserDataAs<AuraSurface>(resource)->IntentToSnap(snap_direction); |
| } |
| |
| void aura_surface_set_snap_left_deprecated(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->SetSnapPrimary(); |
| } |
| |
| void aura_surface_set_snap_right_deprecated(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->SetSnapSecondary(); |
| } |
| |
| void aura_surface_unset_snap_deprecated(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->UnsetSnap(); |
| } |
| |
| void aura_surface_set_window_session_id(wl_client* client, |
| wl_resource* resource, |
| int32_t id) { |
| GetUserDataAs<AuraSurface>(resource)->SetWindowSessionId(id); |
| } |
| |
| void aura_surface_set_can_go_back(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->SetCanGoBack(); |
| } |
| |
| void aura_surface_unset_can_go_back(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->UnsetCanGoBack(); |
| } |
| |
| void aura_surface_set_pip(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->SetPip(); |
| } |
| |
| void aura_surface_unset_pip(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->UnsetPip(); |
| } |
| |
| void aura_surface_set_aspect_ratio(wl_client* client, |
| wl_resource* resource, |
| int32_t width, |
| int32_t height) { |
| GetUserDataAs<AuraSurface>(resource)->SetAspectRatio( |
| gfx::SizeF(width, height)); |
| } |
| |
| void aura_surface_move_to_desk(wl_client* client, |
| wl_resource* resource, |
| int index) { |
| GetUserDataAs<AuraSurface>(resource)->MoveToDesk(index); |
| } |
| |
| void aura_surface_set_initial_workspace(wl_client* client, |
| wl_resource* resource, |
| const char* initial_workspace) { |
| GetUserDataAs<AuraSurface>(resource)->SetInitialWorkspace(initial_workspace); |
| } |
| |
| void aura_surface_set_pin(wl_client* client, |
| wl_resource* resource, |
| int32_t trusted) { |
| GetUserDataAs<AuraSurface>(resource)->Pin(trusted); |
| } |
| |
| void aura_surface_unset_pin(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->Unpin(); |
| } |
| |
| void aura_surface_release(wl_client* client, wl_resource* resource) { |
| wl_resource_destroy(resource); |
| } |
| |
| void aura_surface_show_tooltip(wl_client* client, |
| wl_resource* resource, |
| const char* text, |
| int32_t x, |
| int32_t y, |
| uint32_t trigger, |
| uint32_t show_delay, |
| uint32_t hide_delay) { |
| GetUserDataAs<AuraSurface>(resource)->ShowTooltip( |
| base::UTF8ToUTF16(text), gfx::Point(x, y), trigger, |
| base::Milliseconds((uint64_t)show_delay), |
| base::Milliseconds((uint64_t)hide_delay)); |
| } |
| |
| void aura_surface_hide_tooltip(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraSurface>(resource)->HideTooltip(); |
| } |
| |
| void aura_surface_set_accessibility_id(wl_client* client, |
| wl_resource* resource, |
| int32_t id) { |
| GetUserDataAs<AuraSurface>(resource)->SetAccessibilityId(id); |
| } |
| |
| const struct zaura_surface_interface aura_surface_implementation = { |
| aura_surface_set_frame, |
| aura_surface_set_parent, |
| aura_surface_set_frame_colors, |
| aura_surface_set_startup_id, |
| aura_surface_set_application_id, |
| aura_surface_set_client_surface_id_DEPRECATED, |
| aura_surface_set_occlusion_tracking, |
| aura_surface_unset_occlusion_tracking, |
| aura_surface_activate, |
| aura_surface_draw_attention, |
| aura_surface_set_fullscreen_mode_deprecated, |
| aura_surface_set_client_surface_str_id, |
| aura_surface_set_server_start_resize, |
| aura_surface_intent_to_snap_deprecated, |
| aura_surface_set_snap_left_deprecated, |
| aura_surface_set_snap_right_deprecated, |
| aura_surface_unset_snap_deprecated, |
| aura_surface_set_window_session_id, |
| aura_surface_set_can_go_back, |
| aura_surface_unset_can_go_back, |
| aura_surface_set_pip, |
| aura_surface_unset_pip, |
| aura_surface_set_aspect_ratio, |
| aura_surface_move_to_desk, |
| aura_surface_set_initial_workspace, |
| aura_surface_set_pin, |
| aura_surface_unset_pin, |
| aura_surface_release, |
| aura_surface_show_tooltip, |
| aura_surface_hide_tooltip, |
| aura_surface_set_accessibility_id, |
| }; |
| |
| } // namespace |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // aura_surface_interface: |
| |
| AuraSurface::AuraSurface(Surface* surface, wl_resource* resource) |
| : surface_(surface), resource_(resource) { |
| surface_->AddSurfaceObserver(this); |
| surface_->SetProperty(kSurfaceHasAuraSurfaceKey, true); |
| WMHelper::GetInstance()->AddActivationObserver(this); |
| } |
| |
| AuraSurface::~AuraSurface() { |
| WMHelper::GetInstance()->RemoveActivationObserver(this); |
| if (surface_) { |
| surface_->RemoveSurfaceObserver(this); |
| surface_->SetProperty(kSurfaceHasAuraSurfaceKey, false); |
| wm::SetTooltipText(surface_->window(), nullptr); |
| } |
| } |
| |
| void AuraSurface::SetFrame(SurfaceFrameType type) { |
| if (surface_) |
| surface_->SetFrame(type); |
| } |
| |
| void AuraSurface::SetServerStartResize() { |
| if (surface_) |
| surface_->SetServerStartResize(); |
| } |
| |
| void AuraSurface::SetFrameColors(SkColor active_frame_color, |
| SkColor inactive_frame_color) { |
| if (surface_) |
| surface_->SetFrameColors(active_frame_color, inactive_frame_color); |
| } |
| |
| void AuraSurface::SetParent(AuraSurface* parent, const gfx::Point& position) { |
| if (surface_) |
| surface_->SetParent(parent ? parent->surface_.get() : nullptr, position); |
| } |
| |
| void AuraSurface::SetStartupId(const char* startup_id) { |
| if (surface_) |
| surface_->SetStartupId(startup_id); |
| } |
| |
| void AuraSurface::SetApplicationId(const char* application_id) { |
| if (surface_) |
| surface_->SetApplicationId(application_id); |
| } |
| |
| void AuraSurface::SetClientSurfaceId(const char* client_surface_id) { |
| if (surface_) |
| surface_->SetClientSurfaceId(client_surface_id); |
| } |
| |
| void AuraSurface::SetOcclusionTracking(bool tracking) { |
| if (surface_) |
| surface_->SetOcclusionTracking(tracking); |
| } |
| |
| void AuraSurface::Activate() { |
| if (surface_) |
| surface_->RequestActivation(); |
| } |
| |
| void AuraSurface::DrawAttention() { |
| if (!surface_) |
| return; |
| // TODO(hollingum): implement me. |
| LOG(WARNING) << "Surface requested attention, but that is not implemented"; |
| } |
| |
| void AuraSurface::SetFullscreenMode(uint32_t mode) { |
| if (!surface_) |
| return; |
| |
| switch (mode) { |
| case ZAURA_SURFACE_FULLSCREEN_MODE_PLAIN: |
| surface_->SetUseImmersiveForFullscreen(false); |
| break; |
| case ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE: |
| surface_->SetUseImmersiveForFullscreen(true); |
| break; |
| default: |
| VLOG(2) << "aura_surface_set_fullscreen_mode(): unknown fullscreen_mode: " |
| << mode; |
| break; |
| } |
| } |
| |
| void AuraSurface::IntentToSnap(uint32_t snap_direction) { |
| switch (snap_direction) { |
| case ZAURA_SURFACE_SNAP_DIRECTION_NONE: |
| surface_->HideSnapPreview(); |
| break; |
| case ZAURA_SURFACE_SNAP_DIRECTION_LEFT: |
| surface_->ShowSnapPreviewToPrimary(); |
| break; |
| case ZAURA_SURFACE_SNAP_DIRECTION_RIGHT: |
| surface_->ShowSnapPreviewToSecondary(); |
| break; |
| } |
| } |
| |
| void AuraSurface::SetSnapPrimary() { |
| surface_->SetSnapPrimary(chromeos::kDefaultSnapRatio); |
| } |
| |
| void AuraSurface::SetSnapSecondary() { |
| surface_->SetSnapSecondary(chromeos::kDefaultSnapRatio); |
| } |
| |
| void AuraSurface::UnsetSnap() { |
| surface_->UnsetSnap(); |
| } |
| |
| void AuraSurface::SetWindowSessionId(int32_t window_session_id) { |
| surface_->SetWindowSessionId(window_session_id); |
| } |
| |
| void AuraSurface::SetCanGoBack() { |
| surface_->SetCanGoBack(); |
| } |
| |
| void AuraSurface::UnsetCanGoBack() { |
| surface_->UnsetCanGoBack(); |
| } |
| |
| void AuraSurface::SetPip() { |
| surface_->SetPip(); |
| } |
| |
| void AuraSurface::UnsetPip() { |
| surface_->UnsetPip(); |
| } |
| |
| void AuraSurface::SetAspectRatio(const gfx::SizeF& aspect_ratio) { |
| surface_->SetAspectRatio(aspect_ratio); |
| } |
| |
| // Overridden from SurfaceObserver: |
| void AuraSurface::OnSurfaceDestroying(Surface* surface) { |
| surface->RemoveSurfaceObserver(this); |
| surface_ = nullptr; |
| } |
| |
| void AuraSurface::OnWindowOcclusionChanged(Surface* surface) { |
| if (!surface_ || !surface_->IsTrackingOcclusion()) |
| return; |
| auto* window = surface_->window(); |
| ComputeAndSendOcclusion(window->GetOcclusionState(), |
| window->occluded_region_in_root()); |
| } |
| |
| void AuraSurface::OnFrameLockingChanged(Surface* surface, bool lock) { |
| if (wl_resource_get_version(resource_) < |
| ZAURA_SURFACE_LOCK_FRAME_NORMAL_SINCE_VERSION) |
| return; |
| if (lock) |
| zaura_surface_send_lock_frame_normal(resource_); |
| else |
| zaura_surface_send_unlock_frame_normal(resource_); |
| } |
| |
| void AuraSurface::OnWindowActivating(ActivationReason reason, |
| aura::Window* gaining_active, |
| aura::Window* losing_active) { |
| if (!surface_ || !losing_active) |
| return; |
| |
| auto* window = surface_->window(); |
| // Check if this surface is a child of a window that is losing focus. |
| auto* widget = views::Widget::GetTopLevelWidgetForNativeView(window); |
| if (!widget || losing_active != widget->GetNativeWindow() || |
| !surface_->IsTrackingOcclusion()) |
| return; |
| |
| // Result may be changed by animated windows, so compute it explicitly. |
| // We need to send occlusion updates before activation changes because |
| // we can only trigger onUserLeaveHint (which triggers Android PIP) upon |
| // losing activation. Windows that have animations applied to them are |
| // normally ignored by the occlusion tracker, but in this case we want |
| // to send the occlusion state after animations finish before activation |
| // changes. This lets us support showing a new window triggering PIP, |
| // which normally would not work due to the window show animation delaying |
| // any occlusion update. |
| // This happens before any window stacking changes occur, which means that |
| // calling the occlusion tracker here for activation changes which change |
| // the window stacking order may not produce correct results. But, |
| // showing a new window will have it stacked on top already, so this will not |
| // be a problem. |
| // TODO(edcourtney): Currently, this does not work for activating via the |
| // overview, because starting the overview activates some overview specific |
| // window. To support overview, we would need to have it keep the original |
| // window activated and also do this inside OnWindowStackingChanged. |
| // See crbug.com/948492. |
| auto* occlusion_tracker = |
| aura::Env::GetInstance()->GetWindowOcclusionTracker(); |
| if (occlusion_tracker->HasIgnoredAnimatingWindows()) { |
| const auto& occlusion_data = |
| occlusion_tracker->ComputeTargetOcclusionForWindow(window); |
| ComputeAndSendOcclusion(occlusion_data.occlusion_state, |
| occlusion_data.occluded_region); |
| } |
| } |
| |
| void AuraSurface::SendOcclusionFraction(float occlusion_fraction) { |
| if (wl_resource_get_version(resource_) < 8) |
| return; |
| // TODO(edcourtney): For now, we are treating every occlusion change as |
| // from a user action. |
| zaura_surface_send_occlusion_changed( |
| resource_, wl_fixed_from_double(occlusion_fraction), |
| ZAURA_SURFACE_OCCLUSION_CHANGE_REASON_USER_ACTION); |
| wl_client_flush(wl_resource_get_client(resource_)); |
| } |
| |
| void AuraSurface::SendOcclusionState( |
| const aura::Window::OcclusionState occlusion_state) { |
| if (wl_resource_get_version(resource_) < 21) |
| return; |
| zaura_surface_send_occlusion_state_changed( |
| resource_, WaylandOcclusionState(occlusion_state)); |
| wl_client_flush(wl_resource_get_client(resource_)); |
| } |
| |
| void AuraSurface::ComputeAndSendOcclusion( |
| const aura::Window::OcclusionState occlusion_state, |
| const SkRegion& occluded_region) { |
| SendOcclusionState(occlusion_state); |
| |
| // Should re-write in locked case - we don't want to trigger PIP upon |
| // locking the screen. |
| if (ash::Shell::Get()->session_controller()->IsScreenLocked()) { |
| SendOcclusionFraction(0.0f); |
| return; |
| } |
| |
| // Send the occlusion fraction. |
| auto* window = surface_->window(); |
| float fraction_occluded = 0.0f; |
| switch (occlusion_state) { |
| case aura::Window::OcclusionState::VISIBLE: { |
| const gfx::Rect display_bounds_in_screen = |
| display::Screen::Get()->GetDisplayNearestWindow(window).bounds(); |
| const gfx::Rect bounds_in_screen = GetTransformedBoundsInScreen(window); |
| const int tracked_area = |
| bounds_in_screen.width() * bounds_in_screen.height(); |
| |
| // Clip the area outside of the display. |
| gfx::Rect area_inside_display = bounds_in_screen; |
| area_inside_display.Intersect(display_bounds_in_screen); |
| int occluded_area = tracked_area - area_inside_display.width() * |
| area_inside_display.height(); |
| |
| // We already marked the area outside the display as occluded, so |
| // intersect the occluded region with the region of the window which is |
| // inside the display. |
| SkRegion tracked_and_occluded_region = occluded_region; |
| tracked_and_occluded_region.op(gfx::RectToSkIRect(area_inside_display), |
| SkRegion::Op::kIntersect_Op); |
| for (SkRegion::Iterator i(tracked_and_occluded_region); !i.done(); |
| i.next()) { |
| occluded_area += i.rect().width() * i.rect().height(); |
| } |
| if (tracked_area) { |
| fraction_occluded = static_cast<float>(occluded_area) / |
| static_cast<float>(tracked_area); |
| } |
| break; |
| } |
| case aura::Window::OcclusionState::OCCLUDED: |
| case aura::Window::OcclusionState::HIDDEN: |
| // Consider the OCCLUDED and HIDDEN cases as 100% occlusion. |
| fraction_occluded = 1.0f; |
| break; |
| case aura::Window::OcclusionState::UNKNOWN: |
| return; // Window is not tracked. |
| } |
| SendOcclusionFraction(fraction_occluded); |
| } |
| |
| void AuraSurface::OnDeskChanged(Surface* surface, int state) { |
| if (wl_resource_get_version(resource_) < |
| ZAURA_SURFACE_DESK_CHANGED_SINCE_VERSION) { |
| return; |
| } |
| |
| zaura_surface_send_desk_changed(resource_, state); |
| } |
| |
| void AuraSurface::ThrottleFrameRate(bool on) { |
| if (wl_resource_get_version(resource_) < |
| ZAURA_SURFACE_START_THROTTLE_SINCE_VERSION) { |
| return; |
| } |
| if (on) |
| zaura_surface_send_start_throttle(resource_); |
| else |
| zaura_surface_send_end_throttle(resource_); |
| wl_client_flush(wl_resource_get_client(resource_)); |
| } |
| |
| void AuraSurface::OnTooltipShown(Surface* surface, |
| std::u16string_view text, |
| const gfx::Rect& bounds) { |
| if (wl_resource_get_version(resource_) < |
| ZAURA_SURFACE_TOOLTIP_SHOWN_SINCE_VERSION) { |
| return; |
| } |
| zaura_surface_send_tooltip_shown(resource_, base::UTF16ToUTF8(text).c_str(), |
| bounds.x(), bounds.y(), bounds.width(), |
| bounds.height()); |
| } |
| |
| void AuraSurface::OnTooltipHidden(Surface* surface) { |
| if (wl_resource_get_version(resource_) < |
| ZAURA_SURFACE_TOOLTIP_HIDDEN_SINCE_VERSION) { |
| return; |
| } |
| zaura_surface_send_tooltip_hidden(resource_); |
| } |
| |
| void AuraSurface::MoveToDesk(int desk_index) { |
| constexpr int kToggleVisibleOnAllWorkspacesValue = -1; |
| if (desk_index == kToggleVisibleOnAllWorkspacesValue) { |
| surface_->SetVisibleOnAllWorkspaces(); |
| } else { |
| surface_->MoveToDesk(desk_index); |
| } |
| } |
| |
| void AuraSurface::SetInitialWorkspace(const char* initial_workspace) { |
| surface_->SetInitialWorkspace(initial_workspace); |
| } |
| |
| void AuraSurface::Pin(bool trusted) { |
| surface_->Pin(trusted); |
| } |
| |
| void AuraSurface::Unpin() { |
| surface_->Unpin(); |
| } |
| |
| void AuraSurface::ShowTooltip(std::u16string text, |
| const gfx::Point& position, |
| uint32_t trigger, |
| const base::TimeDelta& show_delay, |
| const base::TimeDelta& hide_delay) { |
| tooltip_text_ = std::move(text); |
| auto* window = surface_->window(); |
| wm::SetTooltipText(window, &tooltip_text_); |
| wm::SetTooltipId(window, surface_); |
| |
| auto* tooltip_controller = ash::Shell::Get()->tooltip_controller(); |
| tooltip_controller->SetShowTooltipDelay(window, show_delay); |
| tooltip_controller->SetHideTooltipTimeout(window, hide_delay); |
| |
| switch (trigger) { |
| case ZAURA_SURFACE_TOOLTIP_TRIGGER_CURSOR: |
| tooltip_controller->UpdateTooltip(window); |
| break; |
| case ZAURA_SURFACE_TOOLTIP_TRIGGER_KEYBOARD: |
| tooltip_controller->UpdateTooltipFromKeyboardWithAnchorPoint(position, |
| window); |
| break; |
| default: |
| VLOG(2) << "Unknown aura-shell tooltip trigger type: " << trigger; |
| tooltip_controller->UpdateTooltip(window); |
| } |
| } |
| |
| void AuraSurface::HideTooltip() { |
| tooltip_text_ = std::u16string(); |
| auto* window = surface_->window(); |
| ash::Shell::Get()->tooltip_controller()->UpdateTooltip(window); |
| } |
| |
| void AuraSurface::SetAccessibilityId(int id) { |
| surface_->SetClientAccessibilityId(id); |
| } |
| |
| chromeos::OrientationType OrientationLock(uint32_t orientation_lock) { |
| switch (orientation_lock) { |
| case ZAURA_TOPLEVEL_ORIENTATION_LOCK_NONE: |
| return chromeos::OrientationType::kAny; |
| case ZAURA_TOPLEVEL_ORIENTATION_LOCK_CURRENT: |
| return chromeos::OrientationType::kCurrent; |
| case ZAURA_TOPLEVEL_ORIENTATION_LOCK_PORTRAIT: |
| return chromeos::OrientationType::kPortrait; |
| case ZAURA_TOPLEVEL_ORIENTATION_LOCK_LANDSCAPE: |
| return chromeos::OrientationType::kLandscape; |
| case ZAURA_TOPLEVEL_ORIENTATION_LOCK_PORTRAIT_PRIMARY: |
| return chromeos::OrientationType::kPortraitPrimary; |
| case ZAURA_TOPLEVEL_ORIENTATION_LOCK_LANDSCAPE_PRIMARY: |
| return chromeos::OrientationType::kLandscapePrimary; |
| case ZAURA_TOPLEVEL_ORIENTATION_LOCK_PORTRAIT_SECONDARY: |
| return chromeos::OrientationType::kPortraitSecondary; |
| case ZAURA_TOPLEVEL_ORIENTATION_LOCK_LANDSCAPE_SECONDARY: |
| return chromeos::OrientationType::kLandscapeSecondary; |
| } |
| VLOG(2) << "Unexpected value of orientation_lock: " << orientation_lock; |
| return chromeos::OrientationType::kAny; |
| } |
| |
| using AuraSurfaceConfigureCallback = base::RepeatingCallback<void( |
| const gfx::Rect& bounds, |
| chromeos::WindowStateType state_type, |
| bool resizing, |
| bool activated, |
| float raster_scale, |
| aura::Window::OcclusionState occlusion_state, |
| std::optional<chromeos::WindowStateType> restore_state_type)>; |
| |
| uint32_t HandleAuraSurfaceConfigureCallback( |
| wl_resource* resource, |
| SerialTracker* serial_tracker, |
| const AuraSurfaceConfigureCallback& callback, |
| const gfx::Rect& bounds, |
| chromeos::WindowStateType state_type, |
| bool resizing, |
| bool activated, |
| const gfx::Vector2d& origin_offset, |
| float raster_scale, |
| aura::Window::OcclusionState occlusion_state, |
| std::optional<chromeos::WindowStateType> restore_state_type) { |
| uint32_t serial = |
| serial_tracker->GetNextSerial(SerialTracker::EventType::OTHER_EVENT); |
| callback.Run(bounds, state_type, resizing, activated, raster_scale, |
| occlusion_state, restore_state_type); |
| xdg_surface_send_configure(resource, serial); |
| wl_client_flush(wl_resource_get_client(resource)); |
| return serial; |
| } |
| |
| using AuraSurfaceRotateFocusCallback = base::RepeatingCallback< |
| void(uint32_t serial, ash::FocusCycler::Direction direction, bool restart)>; |
| |
| uint32_t HandleAuraSurfaceRotateFocusCallback( |
| SerialTracker* serial_tracker, |
| AuraSurfaceRotateFocusCallback callback, |
| ash::FocusCycler::Direction direction, |
| bool restart) { |
| auto serial = |
| serial_tracker->GetNextSerial(SerialTracker::EventType::OTHER_EVENT); |
| callback.Run(serial, direction, restart); |
| return serial; |
| } |
| |
| AuraToplevel::AuraToplevel(ShellSurface* shell_surface, |
| SerialTracker* const serial_tracker, |
| SerialTracker* const rotation_serial_tracker, |
| wl_resource* xdg_toplevel_resource, |
| wl_resource* aura_toplevel_resource) |
| : shell_surface_(shell_surface), |
| serial_tracker_(serial_tracker), |
| rotation_serial_tracker_(rotation_serial_tracker), |
| xdg_toplevel_resource_(xdg_toplevel_resource), |
| aura_toplevel_resource_(aura_toplevel_resource) { |
| DCHECK(shell_surface); |
| } |
| |
| AuraToplevel::~AuraToplevel() = default; |
| |
| void AuraToplevel::OnRotatePaneFocus(uint32_t serial, |
| ash::FocusCycler::Direction direction, |
| bool restart) { |
| auto zaura_direction = direction == ash::FocusCycler::Direction::FORWARD |
| ? ZAURA_TOPLEVEL_ROTATE_DIRECTION_FORWARD |
| : ZAURA_TOPLEVEL_ROTATE_DIRECTION_BACKWARD; |
| zaura_toplevel_send_rotate_focus( |
| aura_toplevel_resource_, serial, zaura_direction, |
| restart ? ZAURA_TOPLEVEL_ROTATE_RESTART_STATE_RESTART |
| : ZAURA_TOPLEVEL_ROTATE_RESTART_STATE_NO_RESTART); |
| wl_client_flush(wl_resource_get_client(aura_toplevel_resource_)); |
| } |
| |
| void AuraToplevel::SetOrientationLock(uint32_t lock_type) { |
| shell_surface_->SetOrientationLock(OrientationLock(lock_type)); |
| } |
| |
| void AuraToplevel::SetWindowCornersRadii(const gfx::RoundedCornersF& radii) { |
| shell_surface_->SetWindowCornersRadii(radii); |
| } |
| |
| void AuraToplevel::SetClientSubmitsSurfacesInPixelCoordinates(bool enable) { |
| shell_surface_->set_client_submits_surfaces_in_pixel_coordinates(enable); |
| } |
| |
| void AuraToplevel::SetWindowBounds(int32_t x, |
| int32_t y, |
| int32_t width, |
| int32_t height, |
| int64_t display_id) { |
| if (!shell_surface_->IsDragged()) { |
| if (display_id != display::kInvalidDisplayId) { |
| shell_surface_->SetDisplay(display_id); |
| } |
| shell_surface_->SetWindowBounds(gfx::Rect(x, y, width, height)); |
| } |
| } |
| |
| void AuraToplevel::SetRestoreInfo(int32_t restore_session_id, |
| int32_t restore_window_id) { |
| shell_surface_->SetRestoreInfo(restore_session_id, restore_window_id); |
| } |
| |
| void AuraToplevel::SetRestoreInfoWithWindowIdSource( |
| int32_t restore_session_id, |
| const std::string& restore_window_id_source) { |
| shell_surface_->SetRestoreInfoWithWindowIdSource(restore_session_id, |
| restore_window_id_source); |
| } |
| |
| void AuraToplevel::OnOriginChange(const gfx::Point& origin) { |
| zaura_toplevel_send_origin_change(aura_toplevel_resource_, origin.x(), |
| origin.y()); |
| wl_client_flush(wl_resource_get_client(aura_toplevel_resource_)); |
| } |
| |
| void AuraToplevel::OnOverviewChange(bool in_overview) { |
| zaura_toplevel_send_overview_change( |
| aura_toplevel_resource_, |
| in_overview ? ZAURA_TOPLEVEL_IN_OVERVIEW_IN_OVERVIEW |
| : ZAURA_TOPLEVEL_IN_OVERVIEW_NOT_IN_OVERVIEW); |
| wl_client_flush(wl_resource_get_client(aura_toplevel_resource_)); |
| } |
| |
| void AuraToplevel::SetDecoration(SurfaceFrameType type) { |
| shell_surface_->OnSetFrame(type); |
| } |
| |
| void AuraToplevel::SetZOrder(ui::ZOrderLevel z_order) { |
| shell_surface_->SetZOrder(z_order); |
| } |
| |
| void AuraToplevel::Activate() { |
| shell_surface_->RequestActivation(); |
| } |
| |
| void AuraToplevel::Deactivate() { |
| shell_surface_->RequestDeactivation(); |
| } |
| |
| bool IsImmersive(uint32_t mode) { |
| switch (mode) { |
| case ZAURA_TOPLEVEL_FULLSCREEN_MODE_PLAIN: |
| return false; |
| case ZAURA_TOPLEVEL_FULLSCREEN_MODE_IMMERSIVE: |
| return true; |
| default: |
| VLOG(2) << "Unknown immersive mode: " << mode; |
| return false; |
| } |
| } |
| |
| void AuraToplevel::SetFullscreenMode(uint32_t mode) { |
| shell_surface_->SetUseImmersiveForFullscreen(IsImmersive(mode)); |
| } |
| |
| void AuraToplevel::SetScaleFactor(float scale_factor) { |
| shell_surface_->SetScaleFactor(scale_factor); |
| } |
| |
| void AuraToplevel::SetClientUsesScreenCoordinates() { |
| supports_window_bounds_ = true; |
| shell_surface_->set_client_supports_window_bounds(true); |
| shell_surface_->set_configure_callback( |
| base::BindRepeating(&HandleAuraSurfaceConfigureCallback, |
| xdg_toplevel_resource_, serial_tracker_, |
| base::BindRepeating(&AuraToplevel::OnConfigure, |
| weak_ptr_factory_.GetWeakPtr()))); |
| shell_surface_->set_origin_change_callback(base::BindRepeating( |
| &AuraToplevel::OnOriginChange, weak_ptr_factory_.GetWeakPtr())); |
| if (wl_resource_get_version(aura_toplevel_resource_) >= |
| ZAURA_TOPLEVEL_ROTATE_FOCUS_SINCE_VERSION) { |
| shell_surface_->set_rotate_focus_callback(base::BindRepeating( |
| HandleAuraSurfaceRotateFocusCallback, rotation_serial_tracker_, |
| base::BindRepeating(&AuraToplevel::OnRotatePaneFocus, |
| weak_ptr_factory_.GetWeakPtr()))); |
| } |
| if (wl_resource_get_version(aura_toplevel_resource_) >= |
| ZAURA_TOPLEVEL_OVERVIEW_CHANGE_SINCE_VERSION) { |
| shell_surface_->set_overview_change_callback( |
| base::BindRepeating(base::BindRepeating( |
| &AuraToplevel::OnOverviewChange, weak_ptr_factory_.GetWeakPtr()))); |
| } |
| } |
| |
| void AuraToplevel::SetSystemModal(bool modal) { |
| shell_surface_->SetSystemModal(modal); |
| } |
| |
| void AuraToplevel::SetFloatToLocation(uint32_t location) { |
| switch (location) { |
| case ZAURA_TOPLEVEL_FLOAT_START_LOCATION_BOTTOM_RIGHT: |
| shell_surface_->SetFloatToLocation( |
| chromeos::FloatStartLocation::kBottomRight); |
| break; |
| case ZAURA_TOPLEVEL_FLOAT_START_LOCATION_BOTTOM_LEFT: |
| shell_surface_->SetFloatToLocation( |
| chromeos::FloatStartLocation::kBottomLeft); |
| break; |
| default: |
| VLOG(2) << "aura_toplevel_set_float_to_location(): unknown " |
| "float_start_location: " |
| << location; |
| break; |
| } |
| } |
| |
| void AuraToplevel::UnsetFloat() { |
| shell_surface_->UnsetFloat(); |
| } |
| |
| void AuraToplevel::SetSnapPrimary(float snap_ratio) { |
| shell_surface_->SetSnapPrimary(snap_ratio); |
| } |
| |
| void AuraToplevel::SetSnapSecondary(float snap_ratio) { |
| shell_surface_->SetSnapSecondary(snap_ratio); |
| } |
| |
| void AuraToplevel::SetPersistable(bool persistable) { |
| shell_surface_->SetPersistable(persistable); |
| } |
| |
| void AuraToplevel::SetShape(std::optional<cc::Region> shape) { |
| shell_surface_->SetShape(std::move(shape)); |
| } |
| |
| void AuraToplevel::AckRotateFocus(uint32_t serial, uint32_t h) { |
| auto handled = h == ZAURA_TOPLEVEL_ROTATE_HANDLED_STATE_HANDLED; |
| shell_surface_->AckRotateFocus(serial, handled); |
| } |
| |
| void AuraToplevel::SetCanMaximize(bool can_maximize) { |
| shell_surface_->SetCanMaximize(can_maximize); |
| } |
| |
| void AuraToplevel::SetCanFullscreen(bool can_fullscreen) { |
| shell_surface_->SetCanFullscreen(can_fullscreen); |
| } |
| |
| void AuraToplevel::SetShadowCornersRadii(const gfx::RoundedCornersF& radii) { |
| shell_surface_->SetShadowCornersRadii(radii); |
| } |
| |
| void AuraToplevel::IntentToSnap(uint32_t snap_direction) { |
| switch (snap_direction) { |
| case ZAURA_SURFACE_SNAP_DIRECTION_NONE: |
| shell_surface_->HideSnapPreview(); |
| break; |
| case ZAURA_SURFACE_SNAP_DIRECTION_LEFT: |
| shell_surface_->ShowSnapPreviewToPrimary(); |
| break; |
| case ZAURA_SURFACE_SNAP_DIRECTION_RIGHT: |
| shell_surface_->ShowSnapPreviewToSecondary(); |
| break; |
| } |
| } |
| |
| void AuraToplevel::UnsetSnap() { |
| shell_surface_->UnsetSnap(); |
| } |
| |
| void AuraToplevel::SetTopInset(int top_inset) { |
| shell_surface_->SetTopInset(top_inset); |
| } |
| |
| template <class T> |
| void AddState(wl_array* states, T state) { |
| T* value = static_cast<T*>(wl_array_add(states, sizeof(T))); |
| DCHECK(value); |
| *value = state; |
| } |
| |
| void AuraToplevel::OnConfigure( |
| const gfx::Rect& bounds, |
| chromeos::WindowStateType state_type, |
| bool resizing, |
| bool activated, |
| float raster_scale, |
| aura::Window::OcclusionState occlusion_state, |
| std::optional<chromeos::WindowStateType> restore_state_type) { |
| wl_array states; |
| wl_array_init(&states); |
| if (state_type == chromeos::WindowStateType::kMaximized) |
| AddState(&states, XDG_TOPLEVEL_STATE_MAXIMIZED); |
| // TODO(crbug.com/40197882): Support snapped state. |
| if (IsFullscreenOrPinnedWindowStateType(state_type)) { |
| // If pinned state is not yet supported, always set fullscreen. |
| if (wl_resource_get_version(aura_toplevel_resource_) < |
| ZAURA_TOPLEVEL_STATE_TRUSTED_PINNED_SINCE_VERSION) { |
| AddState(&states, XDG_TOPLEVEL_STATE_FULLSCREEN); |
| } else if (state_type == chromeos::WindowStateType::kFullscreen) { |
| AddState(&states, XDG_TOPLEVEL_STATE_FULLSCREEN); |
| } else if (state_type == chromeos::WindowStateType::kPinned) { |
| AddState(&states, ZAURA_TOPLEVEL_STATE_PINNED); |
| } else if (state_type == chromeos::WindowStateType::kLockedFullscreen) { |
| AddState(&states, ZAURA_TOPLEVEL_STATE_TRUSTED_PINNED); |
| } |
| |
| if (shell_surface_->GetWidget() && |
| shell_surface_->GetWidget()->GetNativeWindow()->GetProperty( |
| chromeos::kImmersiveImpliedByFullscreen)) { |
| // Imemrsive state should NOT be set for pinned state. |
| // TODO(crbug.com/41483774): Lacros randomly enters/exits immersive state |
| // when transitioning to pinned/unpinned state. Add CHECK to guarantee |
| // `state_type` is as same as chrome::WindowStateType::kFullscreen here |
| // after resolving this bug. |
| |
| // TODO(oshima): Immersive should probably be default. |
| // Investigate and fix. |
| AddState(&states, ZAURA_TOPLEVEL_STATE_IMMERSIVE); |
| } |
| // If the window was maxmized before it is fullscreened, we should |
| // keep this state while it is fullscreened. This is what X11 apps, and |
| // thus standard wayland apps expect, and they may rely on this behavior |
| // even though this is not explicitly specified in the protocol spec. |
| if (restore_state_type.has_value() && |
| restore_state_type.value() == chromeos::WindowStateType::kMaximized) { |
| AddState(&states, XDG_TOPLEVEL_STATE_MAXIMIZED); |
| } |
| } |
| if (resizing) |
| AddState(&states, XDG_TOPLEVEL_STATE_RESIZING); |
| if (activated) |
| AddState(&states, XDG_TOPLEVEL_STATE_ACTIVATED); |
| |
| if (state_type == chromeos::WindowStateType::kPrimarySnapped) |
| AddState(&states, ZAURA_TOPLEVEL_STATE_SNAPPED_PRIMARY); |
| if (state_type == chromeos::WindowStateType::kSecondarySnapped) |
| AddState(&states, ZAURA_TOPLEVEL_STATE_SNAPPED_SECONDARY); |
| |
| if (state_type == chromeos::WindowStateType::kFloated) |
| AddState(&states, ZAURA_TOPLEVEL_STATE_FLOATED); |
| |
| if (state_type == chromeos::WindowStateType::kMinimized) |
| AddState(&states, ZAURA_TOPLEVEL_STATE_MINIMIZED); |
| |
| if (state_type == chromeos::WindowStateType::kPip) { |
| AddState(&states, ZAURA_TOPLEVEL_STATE_PIP); |
| } |
| |
| zaura_toplevel_send_configure(aura_toplevel_resource_, bounds.x(), bounds.y(), |
| bounds.width(), bounds.height(), &states); |
| wl_array_release(&states); |
| |
| if (wl_resource_get_version(aura_toplevel_resource_) >= |
| ZAURA_TOPLEVEL_CONFIGURE_RASTER_SCALE_SINCE_VERSION) { |
| uint32_t value = base::bit_cast<uint32_t>(raster_scale); |
| zaura_toplevel_send_configure_raster_scale(aura_toplevel_resource_, value); |
| } |
| |
| if (wl_resource_get_version(aura_toplevel_resource_) >= |
| ZAURA_TOPLEVEL_CONFIGURE_OCCLUSION_STATE_SINCE_VERSION) { |
| zaura_toplevel_send_configure_occlusion_state( |
| aura_toplevel_resource_, WaylandOcclusionState(occlusion_state)); |
| } |
| } |
| |
| AuraPopup::AuraPopup(ShellSurfaceBase* shell_surface) |
| : shell_surface_(shell_surface) { |
| DCHECK(shell_surface); |
| } |
| |
| AuraPopup::~AuraPopup() = default; |
| |
| void AuraPopup::SetClientSubmitsSurfacesInPixelCoordinates(bool enable) { |
| shell_surface_->set_client_submits_surfaces_in_pixel_coordinates(enable); |
| } |
| |
| void AuraPopup::SetDecoration(SurfaceFrameType type) { |
| shell_surface_->OnSetFrame(type); |
| } |
| |
| void AuraPopup::SetMenu() { |
| shell_surface_->SetMenu(); |
| } |
| |
| void AuraPopup::SetScaleFactor(float scale_factor) { |
| shell_surface_->SetScaleFactor(scale_factor); |
| } |
| |
| namespace { |
| |
| void aura_output_release(wl_client* client, wl_resource* resource) { |
| wl_resource_destroy(resource); |
| } |
| |
| const struct zaura_output_interface aura_output_implementation = { |
| aura_output_release, |
| }; |
| |
| } // namespace |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // aura_output_interface: |
| |
| AuraOutput::AuraOutput(wl_resource* resource, |
| WaylandDisplayHandler* display_handler) |
| : resource_(resource), display_handler_(display_handler) { |
| display_handler_->AddObserver(this); |
| } |
| |
| AuraOutput::~AuraOutput() { |
| if (display_handler_) |
| display_handler_->RemoveObserver(this); |
| } |
| |
| bool AuraOutput::SendDisplayMetrics(const display::Display& display, |
| uint32_t changed_metrics) { |
| if (!(changed_metrics & |
| (display::DisplayObserver::DISPLAY_METRIC_BOUNDS | |
| display::DisplayObserver::DISPLAY_METRIC_WORK_AREA | |
| display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR | |
| display::DisplayObserver::DISPLAY_METRIC_ROTATION))) { |
| return false; |
| } |
| |
| const OutputMetrics output_metrics(display); |
| |
| if (wl_resource_get_version(resource_) >= |
| ZAURA_OUTPUT_DISPLAY_ID_SINCE_VERSION) { |
| zaura_output_send_display_id(resource_, output_metrics.display_id.high, |
| output_metrics.display_id.low); |
| } |
| |
| if (wl_resource_get_version(resource_) >= ZAURA_OUTPUT_SCALE_SINCE_VERSION) { |
| for (const auto& output_scale : output_metrics.output_scales) { |
| zaura_output_send_scale(resource_, output_scale.scale_property, |
| output_scale.scale_factor); |
| } |
| } |
| |
| if (wl_resource_get_version(resource_) >= |
| ZAURA_OUTPUT_CONNECTION_SINCE_VERSION) { |
| zaura_output_send_connection(resource_, output_metrics.connection_type); |
| } |
| |
| if (wl_resource_get_version(resource_) >= |
| ZAURA_OUTPUT_DEVICE_SCALE_FACTOR_SINCE_VERSION) { |
| zaura_output_send_device_scale_factor( |
| resource_, output_metrics.device_scale_factor_deprecated); |
| } |
| |
| if (wl_resource_get_version(resource_) >= ZAURA_OUTPUT_INSETS_SINCE_VERSION) { |
| SendInsets(output_metrics.logical_insets); |
| } |
| |
| if (wl_resource_get_version(resource_) >= |
| ZAURA_OUTPUT_LOGICAL_TRANSFORM_SINCE_VERSION) { |
| SendLogicalTransform(output_metrics.logical_transform); |
| } |
| |
| return true; |
| } |
| |
| void AuraOutput::OnOutputDestroyed() { |
| display_handler_->RemoveObserver(this); |
| display_handler_ = nullptr; |
| } |
| |
| bool AuraOutput::HasDisplayHandlerForTesting() const { |
| return !!display_handler_; |
| } |
| |
| void AuraOutput::SendActiveDisplay() { |
| if (wl_resource_get_version(resource_) >= |
| ZAURA_OUTPUT_ACTIVATED_SINCE_VERSION) { |
| zaura_output_send_activated(resource_); |
| } |
| } |
| |
| void AuraOutput::SendInsets(const gfx::Insets& insets) { |
| zaura_output_send_insets(resource_, insets.top(), insets.left(), |
| insets.bottom(), insets.right()); |
| } |
| |
| void AuraOutput::SendLogicalTransform(int32_t transform) { |
| zaura_output_send_logical_transform(resource_, transform); |
| } |
| |
| namespace { |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // aura_shell_interface: |
| |
| // IDs of bugs that have been fixed in the exo implementation. These are |
| // propagated to clients on aura_shell bind and can be used to gate client |
| // logic on the presence of certain fixes. |
| const uint32_t kFixedBugIds[] = { |
| 1151508, // Do not remove, used for sanity checks by |
| // |wayland_simple_client| |
| 1352584, |
| 1358908, |
| 1400226, |
| 1405471, |
| }; |
| |
| // Implements aura shell interface and monitors workspace state needed |
| // for the aura shell interface. |
| class WaylandAuraShell : public ash::DesksController::Observer, |
| public ash::OverviewObserver, |
| public display::DisplayObserver, |
| public SeatObserver { |
| public: |
| WaylandAuraShell(wl_resource* aura_shell_resource, Display* display) |
| : aura_shell_resource_(aura_shell_resource), seat_(display->seat()) { |
| ash::DesksController::Get()->AddObserver(this); |
| ash::Shell::Get()->overview_controller()->AddObserver(this); |
| display::Screen::Get()->AddObserver(this); |
| if (wl_resource_get_version(aura_shell_resource_) >= |
| ZAURA_SHELL_LAYOUT_MODE_SINCE_VERSION) { |
| auto layout_mode = display::Screen::Get()->InTabletMode() |
| ? ZAURA_SHELL_LAYOUT_MODE_TABLET |
| : ZAURA_SHELL_LAYOUT_MODE_WINDOWED; |
| zaura_shell_send_layout_mode(aura_shell_resource_, layout_mode); |
| } |
| if (wl_resource_get_version(aura_shell_resource_) >= |
| ZAURA_SHELL_COMPOSITOR_VERSION_SINCE_VERSION) { |
| const std::string_view ash_version = version_info::GetVersionNumber(); |
| zaura_shell_send_compositor_version(aura_shell_resource_, |
| ash_version.data()); |
| } |
| if (wl_resource_get_version(aura_shell_resource_) >= |
| ZAURA_SHELL_BUG_FIX_SINCE_VERSION) { |
| for (uint32_t bug_id : kFixedBugIds) { |
| zaura_shell_send_bug_fix(aura_shell_resource_, bug_id); |
| } |
| if (wl_resource_get_version(aura_shell_resource_) >= |
| ZAURA_SHELL_ALL_BUG_FIXES_SENT_SINCE_VERSION) { |
| zaura_shell_send_all_bug_fixes_sent(aura_shell_resource_); |
| } |
| wl_client_flush(wl_resource_get_client(aura_shell_resource_)); |
| } |
| |
| if (wl_resource_get_version(aura_shell_resource_) >= |
| ZAURA_SHELL_WINDOW_CORNERS_RADII_SINCE_VERSION) { |
| const auto window_radii = chromeos::GetWindowRoundedCorners(); |
| zaura_shell_send_window_corners_radii( |
| aura_shell_resource_, window_radii.upper_left(), |
| window_radii.upper_right(), window_radii.lower_right(), |
| window_radii.lower_left()); |
| } |
| |
| display->seat()->AddObserver(this, kAuraShellSeatObserverPriority); |
| |
| OnDesksChanged(); |
| OnDeskActivationChanged(); |
| OnOverviewModeChanged(); |
| } |
| WaylandAuraShell(const WaylandAuraShell&) = delete; |
| WaylandAuraShell& operator=(const WaylandAuraShell&) = delete; |
| ~WaylandAuraShell() override { |
| display::Screen::Get()->RemoveObserver(this); |
| ash::Shell::Get()->overview_controller()->RemoveObserver(this); |
| ash::DesksController::Get()->RemoveObserver(this); |
| if (seat_) |
| seat_->RemoveObserver(this); |
| } |
| |
| // display::DisplayObserver: |
| void OnDisplayTabletStateChanged(display::TabletState state) override { |
| if (wl_resource_get_version(aura_shell_resource_) >= |
| ZAURA_SHELL_LAYOUT_MODE_SINCE_VERSION) { |
| if (state == display::TabletState::kInTabletMode) { |
| zaura_shell_send_layout_mode(aura_shell_resource_, |
| ZAURA_SHELL_LAYOUT_MODE_TABLET); |
| wl_client_flush(wl_resource_get_client(aura_shell_resource_)); |
| } else if (state == display::TabletState::kExitingTabletMode) { |
| zaura_shell_send_layout_mode(aura_shell_resource_, |
| ZAURA_SHELL_LAYOUT_MODE_WINDOWED); |
| wl_client_flush(wl_resource_get_client(aura_shell_resource_)); |
| } |
| } |
| } |
| |
| // ash::DesksController::Observer: |
| void OnDeskAdded(const ash::Desk* desk, bool from_undo) override { |
| OnDesksChanged(); |
| } |
| void OnDeskRemoved(const ash::Desk* desk) override { OnDesksChanged(); } |
| void OnDeskReordered(int old_index, int new_index) override { |
| OnDesksChanged(); |
| } |
| void OnDeskActivationChanged(const ash::Desk* activated, |
| const ash::Desk* deactivated) override { |
| OnDeskActivationChanged(); |
| } |
| void OnDeskSwitchAnimationLaunching() override {} |
| void OnDeskSwitchAnimationFinished() override {} |
| void OnDeskNameChanged(const ash::Desk* desk, |
| const std::u16string& new_name) override { |
| OnDesksChanged(); |
| } |
| |
| // ash::OverviewObserver: |
| void OnOverviewModeStartingAnimationComplete(bool canceled) override { |
| if (!canceled) { |
| OnOverviewModeChanged(); |
| } |
| } |
| void OnOverviewModeEndingAnimationComplete(bool canceled) override { |
| if (!canceled) { |
| OnOverviewModeChanged(); |
| } |
| } |
| |
| // SeatObserver: |
| void OnSurfaceFocused(Surface* gained_focus, |
| Surface* lost_focus, |
| bool has_focused_surface) override { |
| FocusedSurfaceChanged(gained_focus, lost_focus, has_focused_surface); |
| } |
| |
| private: |
| void OnDesksChanged() { |
| if (wl_resource_get_version(aura_shell_resource_) < |
| ZAURA_SHELL_DESKS_CHANGED_SINCE_VERSION) { |
| return; |
| } |
| |
| wl_array desk_names; |
| wl_array_init(&desk_names); |
| |
| for (const auto& desk : ash::DesksController::Get()->desks()) { |
| std::string name = base::UTF16ToUTF8(desk->name()); |
| char* desk_name = |
| static_cast<char*>(wl_array_add(&desk_names, name.size() + 1)); |
| UNSAFE_TODO(strcpy(desk_name, name.c_str())); |
| } |
| |
| zaura_shell_send_desks_changed(aura_shell_resource_, &desk_names); |
| wl_array_release(&desk_names); |
| } |
| |
| void OnDeskActivationChanged() { |
| if (wl_resource_get_version(aura_shell_resource_) < |
| ZAURA_SHELL_DESK_ACTIVATION_CHANGED_SINCE_VERSION) { |
| return; |
| } |
| |
| zaura_shell_send_desk_activation_changed( |
| aura_shell_resource_, |
| ash::DesksController::Get()->GetActiveDeskIndex()); |
| } |
| |
| void OnOverviewModeChanged() { |
| if (wl_resource_get_version(aura_shell_resource_) < |
| ZAURA_SHELL_SET_OVERVIEW_MODE_SINCE_VERSION) { |
| return; |
| } |
| |
| const bool in_overview = |
| ash::Shell::Get()->overview_controller()->InOverviewSession(); |
| if (in_overview) { |
| zaura_shell_send_set_overview_mode(aura_shell_resource_); |
| } else { |
| zaura_shell_send_unset_overview_mode(aura_shell_resource_); |
| } |
| } |
| |
| void FocusedSurfaceChanged(Surface* gained_active_surface, |
| Surface* lost_active_surface, |
| bool has_focused_client) { |
| if (wl_resource_get_version(aura_shell_resource_) < |
| ZAURA_SHELL_ACTIVATED_SINCE_VERSION) |
| return; |
| |
| 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(aura_shell_resource_); |
| |
| // If surface that gained active is not owned by the aura shell then |
| // set 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 the aura shell then set |
| // to null. |
| if (lost_active_surface_resource && |
| wl_resource_get_client(lost_active_surface_resource) != client) { |
| lost_active_surface_resource = nullptr; |
| } |
| |
| if (gained_active_surface_resource == lost_active_surface_resource && |
| last_has_focused_client_ == has_focused_client) { |
| return; |
| } |
| last_has_focused_client_ = has_focused_client; |
| |
| zaura_shell_send_activated(aura_shell_resource_, |
| gained_active_surface_resource, |
| lost_active_surface_resource); |
| |
| wl_client_flush(client); |
| } |
| |
| // The aura shell resource associated with observer. |
| const raw_ptr<wl_resource, DanglingUntriaged> aura_shell_resource_; |
| const raw_ptr<Seat> seat_; |
| |
| bool last_has_focused_client_ = false; |
| |
| base::WeakPtrFactory<WaylandAuraShell> weak_ptr_factory_{this}; |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // aura_toplevel_interface: |
| |
| void aura_toplevel_set_orientation_lock(wl_client* client, |
| wl_resource* resource, |
| uint32_t orientation_lock) { |
| GetUserDataAs<AuraToplevel>(resource)->SetOrientationLock(orientation_lock); |
| } |
| |
| void aura_toplevel_set_window_corner_radii(wl_client* client, |
| wl_resource* resource, |
| uint32_t upper_left_radius, |
| uint32_t upper_right_radius, |
| uint32_t lower_right_radius, |
| uint32_t lower_left_radius) { |
| GetUserDataAs<AuraToplevel>(resource)->SetWindowCornersRadii( |
| gfx::RoundedCornersF(upper_left_radius, upper_right_radius, |
| lower_right_radius, lower_left_radius)); |
| } |
| |
| void aura_toplevel_set_shadow_corners_radii(wl_client* client, |
| wl_resource* resource, |
| uint32_t upper_left_radius, |
| uint32_t upper_right_radius, |
| uint32_t lower_right_radius, |
| uint32_t lower_left_radius) { |
| GetUserDataAs<AuraToplevel>(resource)->SetShadowCornersRadii( |
| gfx::RoundedCornersF(upper_left_radius, upper_right_radius, |
| lower_right_radius, lower_left_radius)); |
| } |
| |
| void aura_toplevel_set_client_supports_window_bounds(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetClientUsesScreenCoordinates(); |
| } |
| |
| void aura_toplevel_surface_submission_in_pixel_coordinates( |
| wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource) |
| ->SetClientSubmitsSurfacesInPixelCoordinates(true); |
| } |
| |
| void aura_toplevel_set_window_bounds(wl_client* client, |
| wl_resource* resource, |
| int32_t x, |
| int32_t y, |
| int32_t width, |
| int32_t height, |
| wl_resource* output) { |
| auto display_id = AuraOutputManager::GetDisplayIdForOutput(output); |
| GetUserDataAs<AuraToplevel>(resource)->SetWindowBounds(x, y, width, height, |
| display_id); |
| } |
| |
| void aura_toplevel_set_origin(wl_client* client, |
| wl_resource* resource, |
| int32_t x, |
| int32_t y, |
| wl_resource* output) { |
| // TODO(b/247452928): Implement aura_toplevel.set_origin. |
| NOTIMPLEMENTED(); |
| } |
| |
| void aura_toplevel_set_restore_info(wl_client* client, |
| wl_resource* resource, |
| int32_t restore_session_id, |
| int32_t restore_window_id) { |
| GetUserDataAs<AuraToplevel>(resource)->SetRestoreInfo(restore_session_id, |
| restore_window_id); |
| } |
| |
| void aura_toplevel_set_system_modal(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetSystemModal(true); |
| } |
| |
| void aura_toplevel_unset_system_modal(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetSystemModal(false); |
| } |
| |
| void aura_toplevel_set_float(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetFloatToLocation( |
| ZAURA_TOPLEVEL_FLOAT_START_LOCATION_BOTTOM_RIGHT); |
| } |
| |
| void aura_toplevel_set_float_to_location(wl_client* client, |
| wl_resource* resource, |
| uint32_t location) { |
| GetUserDataAs<AuraToplevel>(resource)->SetFloatToLocation(location); |
| } |
| |
| void aura_toplevel_unset_float(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->UnsetFloat(); |
| } |
| |
| void aura_toplevel_set_snap_primary(wl_client* client, |
| wl_resource* resource, |
| uint32_t snap_ratio_as_uint) { |
| float snap_ratio = base::bit_cast<float>(snap_ratio_as_uint); |
| GetUserDataAs<AuraToplevel>(resource)->SetSnapPrimary(snap_ratio); |
| } |
| |
| void aura_toplevel_set_snap_secondary(wl_client* client, |
| wl_resource* resource, |
| uint32_t snap_ratio_as_uint) { |
| float snap_ratio = base::bit_cast<float>(snap_ratio_as_uint); |
| GetUserDataAs<AuraToplevel>(resource)->SetSnapSecondary(snap_ratio); |
| } |
| |
| void aura_toplevel_intent_to_snap(wl_client* client, |
| wl_resource* resource, |
| uint32_t snap_direction) { |
| GetUserDataAs<AuraToplevel>(resource)->IntentToSnap(snap_direction); |
| } |
| |
| void aura_toplevel_unset_snap(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->UnsetSnap(); |
| } |
| |
| void aura_toplevel_set_restore_info_with_window_id_source( |
| wl_client* client, |
| wl_resource* resource, |
| int32_t restore_session_id, |
| const char* restore_window_id_source) { |
| GetUserDataAs<AuraToplevel>(resource)->SetRestoreInfoWithWindowIdSource( |
| restore_session_id, restore_window_id_source); |
| } |
| |
| SurfaceFrameType AuraTopLevelDecorationType(uint32_t decoration_type) { |
| switch (decoration_type) { |
| case ZAURA_TOPLEVEL_DECORATION_TYPE_NONE: |
| return SurfaceFrameType::NONE; |
| case ZAURA_TOPLEVEL_DECORATION_TYPE_NORMAL: |
| return SurfaceFrameType::NORMAL; |
| case ZAURA_TOPLEVEL_DECORATION_TYPE_SHADOW: |
| return SurfaceFrameType::SHADOW; |
| default: |
| VLOG(2) << "Unknown aura-toplevel decoration type: " << decoration_type; |
| return SurfaceFrameType::NONE; |
| } |
| } |
| |
| void aura_toplevel_set_decoration(wl_client* client, |
| wl_resource* resource, |
| uint32_t type) { |
| GetUserDataAs<AuraToplevel>(resource)->SetDecoration( |
| AuraTopLevelDecorationType(type)); |
| } |
| |
| void aura_toplevel_release(wl_client* client, wl_resource* resource) { |
| wl_resource_destroy(resource); |
| } |
| |
| ui::ZOrderLevel AuraTopLevelZOrderLevel(uint32_t z_order_level) { |
| switch (z_order_level) { |
| case ZAURA_TOPLEVEL_Z_ORDER_LEVEL_NORMAL: |
| return ui::ZOrderLevel::kNormal; |
| case ZAURA_TOPLEVEL_Z_ORDER_LEVEL_FLOATING_WINDOW: |
| return ui::ZOrderLevel::kFloatingWindow; |
| case ZAURA_TOPLEVEL_Z_ORDER_LEVEL_FLOATING_UI_ELEMENT: |
| return ui::ZOrderLevel::kFloatingUIElement; |
| case ZAURA_TOPLEVEL_Z_ORDER_LEVEL_SECURITY_SURFACE: |
| return ui::ZOrderLevel::kSecuritySurface; |
| } |
| |
| NOTREACHED(); |
| } |
| |
| void aura_toplevel_set_z_order(wl_client* client, |
| wl_resource* resource, |
| uint32_t z_order) { |
| GetUserDataAs<AuraToplevel>(resource)->SetZOrder( |
| AuraTopLevelZOrderLevel(z_order)); |
| } |
| |
| void aura_toplevel_activate(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->Activate(); |
| } |
| |
| void aura_toplevel_deactivate(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->Deactivate(); |
| } |
| |
| void aura_toplevel_set_fullscreen_mode(wl_client* client, |
| wl_resource* resource, |
| uint32_t mode) { |
| GetUserDataAs<AuraToplevel>(resource)->SetFullscreenMode(mode); |
| } |
| |
| void aura_toplevel_set_scale_factor(wl_client* client, |
| wl_resource* resource, |
| uint32_t scale_factor_as_uint) { |
| static_assert(sizeof(uint32_t) == sizeof(float), |
| "Sizes much match for reinterpret cast to be meaningful"); |
| float scale_factor = base::bit_cast<float>(scale_factor_as_uint); |
| GetUserDataAs<AuraToplevel>(resource)->SetScaleFactor(scale_factor); |
| } |
| |
| void aura_toplevel_set_persistable(wl_client* client, |
| wl_resource* resource, |
| uint32_t persistable) { |
| GetUserDataAs<AuraToplevel>(resource)->SetPersistable( |
| persistable == ZAURA_TOPLEVEL_PERSISTABLE_PERSISTABLE); |
| } |
| |
| void aura_toplevel_set_shape(wl_client* client, |
| wl_resource* resource, |
| wl_resource* region_resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetShape( |
| region_resource |
| ? std::optional<cc::Region>(*GetUserDataAs<SkRegion>(region_resource)) |
| : std::nullopt); |
| } |
| |
| void aura_toplevel_set_top_inset(wl_client* client, |
| wl_resource* resource, |
| int32_t top_inset) { |
| GetUserDataAs<AuraToplevel>(resource)->SetTopInset(top_inset); |
| } |
| |
| void aura_toplevel_ack_rotate_focus(wl_client* client, |
| wl_resource* resource, |
| uint32_t serial, |
| uint32_t handled) { |
| GetUserDataAs<AuraToplevel>(resource)->AckRotateFocus(serial, handled); |
| } |
| |
| void aura_toplevel_set_can_maximize(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetCanMaximize(true); |
| } |
| |
| void aura_toplevel_unset_can_maximize(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetCanMaximize(false); |
| } |
| |
| void aura_toplevel_set_can_fullscreen(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetCanFullscreen(true); |
| } |
| |
| void aura_toplevel_unset_can_fullscreen(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraToplevel>(resource)->SetCanFullscreen(false); |
| } |
| |
| const struct zaura_toplevel_interface aura_toplevel_implementation = { |
| aura_toplevel_set_orientation_lock, |
| aura_toplevel_surface_submission_in_pixel_coordinates, |
| aura_toplevel_set_client_supports_window_bounds, |
| aura_toplevel_set_window_bounds, |
| aura_toplevel_set_restore_info, |
| aura_toplevel_set_system_modal, |
| aura_toplevel_unset_system_modal, |
| aura_toplevel_set_restore_info_with_window_id_source, |
| aura_toplevel_set_decoration, |
| aura_toplevel_release, |
| aura_toplevel_set_float, |
| aura_toplevel_unset_float, |
| aura_toplevel_set_z_order, |
| aura_toplevel_set_origin, |
| aura_toplevel_activate, |
| aura_toplevel_deactivate, |
| aura_toplevel_set_fullscreen_mode, |
| aura_toplevel_set_scale_factor, |
| aura_toplevel_set_snap_primary, |
| aura_toplevel_set_snap_secondary, |
| aura_toplevel_intent_to_snap, |
| aura_toplevel_unset_snap, |
| aura_toplevel_set_persistable, |
| aura_toplevel_set_shape, |
| aura_toplevel_set_top_inset, |
| aura_toplevel_ack_rotate_focus, |
| aura_toplevel_set_can_maximize, |
| aura_toplevel_unset_can_maximize, |
| aura_toplevel_set_can_fullscreen, |
| aura_toplevel_unset_can_fullscreen, |
| aura_toplevel_set_float_to_location, |
| aura_toplevel_set_window_corner_radii, |
| aura_toplevel_set_shadow_corners_radii}; |
| |
| void aura_popup_surface_submission_in_pixel_coordinates(wl_client* client, |
| wl_resource* resource) { |
| GetUserDataAs<AuraPopup>(resource) |
| ->SetClientSubmitsSurfacesInPixelCoordinates(true); |
| } |
| |
| SurfaceFrameType AuraPopupDecorationType(uint32_t decoration_type) { |
| switch (decoration_type) { |
| case ZAURA_POPUP_DECORATION_TYPE_NONE: |
| return SurfaceFrameType::NONE; |
| case ZAURA_POPUP_DECORATION_TYPE_NORMAL: |
| return SurfaceFrameType::NORMAL; |
| case ZAURA_POPUP_DECORATION_TYPE_SHADOW: |
| return SurfaceFrameType::SHADOW; |
| default: |
| VLOG(2) << "Unknown aura-popup decoration type: " << decoration_type; |
| return SurfaceFrameType::NONE; |
| } |
| } |
| |
| void aura_popup_set_decoration(wl_client* client, |
| wl_resource* resource, |
| uint32_t type) { |
| GetUserDataAs<AuraPopup>(resource)->SetDecoration( |
| AuraPopupDecorationType(type)); |
| } |
| |
| void aura_popup_set_menu(wl_client* client, wl_resource* resource) { |
| GetUserDataAs<AuraPopup>(resource)->SetMenu(); |
| } |
| |
| void aura_popup_release(wl_client* client, wl_resource* resource) { |
| wl_resource_destroy(resource); |
| } |
| |
| void aura_popup_set_scale_factor(wl_client* client, |
| wl_resource* resource, |
| uint32_t scale_factor_as_uint) { |
| float scale_factor = base::bit_cast<float>(scale_factor_as_uint); |
| GetUserDataAs<AuraPopup>(resource)->SetScaleFactor(scale_factor); |
| } |
| |
| const struct zaura_popup_interface aura_popup_implementation = { |
| aura_popup_surface_submission_in_pixel_coordinates, |
| aura_popup_set_decoration, |
| aura_popup_set_menu, |
| aura_popup_release, |
| aura_popup_set_scale_factor, |
| }; |
| |
| void aura_shell_get_aura_toplevel(wl_client* client, |
| wl_resource* resource, |
| uint32_t id, |
| wl_resource* xdg_toplevel_resource) { |
| ShellSurfaceData shell_surface_data = |
| GetShellSurfaceFromToplevelResource(xdg_toplevel_resource); |
| wl_resource* aura_toplevel_resource = wl_resource_create( |
| client, &zaura_toplevel_interface, wl_resource_get_version(resource), id); |
| |
| SetImplementation( |
| aura_toplevel_resource, &aura_toplevel_implementation, |
| std::make_unique<AuraToplevel>( |
| shell_surface_data.shell_surface, shell_surface_data.serial_tracker, |
| shell_surface_data.rotation_serial_tracker, |
| shell_surface_data.surface_resource, aura_toplevel_resource)); |
| } |
| |
| void aura_shell_get_aura_popup(wl_client* client, |
| wl_resource* resource, |
| uint32_t id, |
| wl_resource* surface_resource) { |
| wl_resource* aura_popup_resource = wl_resource_create( |
| client, &zaura_popup_interface, wl_resource_get_version(resource), id); |
| |
| ShellSurfaceBase* shell_surface = |
| GetShellSurfaceFromPopupResource(surface_resource); |
| |
| SetImplementation(aura_popup_resource, &aura_popup_implementation, |
| std::make_unique<AuraPopup>(shell_surface)); |
| } |
| |
| void aura_shell_get_aura_surface(wl_client* client, |
| wl_resource* resource, |
| uint32_t id, |
| wl_resource* surface_resource) { |
| Surface* surface = GetUserDataAs<Surface>(surface_resource); |
| if (surface->GetProperty(kSurfaceHasAuraSurfaceKey)) { |
| wl_resource_post_error( |
| resource, ZAURA_SHELL_ERROR_AURA_SURFACE_EXISTS, |
| "an aura surface object for that surface already exists"); |
| return; |
| } |
| |
| wl_resource* aura_surface_resource = wl_resource_create( |
| client, &zaura_surface_interface, wl_resource_get_version(resource), id); |
| |
| SetImplementation( |
| aura_surface_resource, &aura_surface_implementation, |
| std::make_unique<AuraSurface>(surface, aura_surface_resource)); |
| } |
| |
| void aura_shell_get_aura_output(wl_client* client, |
| wl_resource* resource, |
| uint32_t id, |
| wl_resource* output_resource) { |
| WaylandDisplayHandler* display_handler = |
| GetUserDataAs<WaylandDisplayHandler>(output_resource); |
| |
| wl_resource* aura_output_resource = wl_resource_create( |
| client, &zaura_output_interface, wl_resource_get_version(resource), id); |
| |
| auto aura_output = |
| std::make_unique<AuraOutput>(aura_output_resource, display_handler); |
| |
| SetImplementation(aura_output_resource, &aura_output_implementation, |
| std::move(aura_output)); |
| } |
| |
| void aura_shell_surface_submission_in_pixel_coordinates(wl_client* client, |
| wl_resource* resource) { |
| LOG(WARNING) << "Deprecated. The server doesn't support this request."; |
| } |
| |
| void aura_shell_release(wl_client* client, wl_resource* resource) { |
| // Nothing to do here. |
| } |
| |
| const struct zaura_shell_interface aura_shell_implementation = { |
| aura_shell_get_aura_surface, |
| aura_shell_get_aura_output, |
| aura_shell_surface_submission_in_pixel_coordinates, |
| aura_shell_get_aura_toplevel, |
| aura_shell_get_aura_popup, |
| aura_shell_release, |
| }; |
| } // namespace |
| |
| void bind_aura_shell(wl_client* client, |
| void* data, |
| uint32_t version, |
| uint32_t id) { |
| wl_resource* resource = |
| wl_resource_create(client, &zaura_shell_interface, |
| std::min(version, kZAuraShellVersion), id); |
| |
| Display* display = static_cast<Display*>(data); |
| SetImplementation(resource, &aura_shell_implementation, |
| std::make_unique<WaylandAuraShell>(resource, display)); |
| } |
| |
| } // namespace exo::wayland |