// 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/wl_shell.h"
#include <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
#include "ash/public/cpp/shell_window_ids.h"
#include "base/functional/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "components/exo/display.h"
#include "components/exo/shell_surface.h"
#include "components/exo/wayland/server_util.h"
#include "components/exo/wayland/wayland_display_observer.h"
namespace exo {
namespace wayland {
namespace {
////////////////////////////////////////////////////////////////////////////////
// wl_shell_surface_interface:
void shell_surface_pong(wl_client* client,
wl_resource* resource,
uint32_t serial) {
NOTIMPLEMENTED();
}
void shell_surface_move(wl_client* client,
wl_resource* resource,
wl_resource* seat_resource,
uint32_t serial) {
GetUserDataAs<ShellSurface>(resource)->StartMove();
}
void shell_surface_resize(wl_client* client,
wl_resource* resource,
wl_resource* seat_resource,
uint32_t serial,
uint32_t edges) {
NOTIMPLEMENTED();
}
void shell_surface_set_toplevel(wl_client* client, wl_resource* resource) {
GetUserDataAs<ShellSurface>(resource)->SetEnabled(true);
}
void shell_surface_set_transient(wl_client* client,
wl_resource* resource,
wl_resource* parent_resource,
int x,
int y,
uint32_t flags) {
ShellSurface* shell_surface = GetUserDataAs<ShellSurface>(resource);
if (shell_surface->GetEnabled())
return;
if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
shell_surface->SetContainer(ash::kShellWindowId_SystemModalContainer);
shell_surface->SetActivatable(false);
}
shell_surface->SetEnabled(true);
}
void shell_surface_set_fullscreen(wl_client* client,
wl_resource* resource,
uint32_t method,
uint32_t framerate,
wl_resource* output_resource) {
ShellSurface* shell_surface = GetUserDataAs<ShellSurface>(resource);
if (shell_surface->GetEnabled())
return;
int64_t display_id =
output_resource
? GetUserDataAs<WaylandDisplayHandler>(output_resource)->id()
: display::kInvalidDisplayId;
shell_surface->SetEnabled(true);
shell_surface->SetFullscreen(true, display_id);
}
void shell_surface_set_popup(wl_client* client,
wl_resource* resource,
wl_resource* seat_resource,
uint32_t serial,
wl_resource* parent_resource,
int32_t x,
int32_t y,
uint32_t flags) {
NOTIMPLEMENTED();
}
void shell_surface_set_maximized(wl_client* client,
wl_resource* resource,
wl_resource* output_resource) {
ShellSurface* shell_surface = GetUserDataAs<ShellSurface>(resource);
if (shell_surface->GetEnabled())
return;
shell_surface->SetEnabled(true);
shell_surface->Maximize();
}
void shell_surface_set_title(wl_client* client,
wl_resource* resource,
const char* title) {
GetUserDataAs<ShellSurface>(resource)->SetTitle(
std::u16string(base::UTF8ToUTF16(title)));
}
void shell_surface_set_class(wl_client* client,
wl_resource* resource,
const char* clazz) {
GetUserDataAs<ShellSurface>(resource)->SetApplicationId(clazz);
}
const struct wl_shell_surface_interface shell_surface_implementation = {
shell_surface_pong, shell_surface_move,
shell_surface_resize, shell_surface_set_toplevel,
shell_surface_set_transient, shell_surface_set_fullscreen,
shell_surface_set_popup, shell_surface_set_maximized,
shell_surface_set_title, shell_surface_set_class};
////////////////////////////////////////////////////////////////////////////////
// wl_shell_interface:
uint32_t HandleShellSurfaceConfigureCallback(
wl_resource* resource,
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) {
wl_shell_surface_send_configure(resource, WL_SHELL_SURFACE_RESIZE_NONE,
bounds.width(), bounds.height());
wl_client_flush(wl_resource_get_client(resource));
return 0;
}
void shell_get_shell_surface(wl_client* client,
wl_resource* resource,
uint32_t id,
wl_resource* surface) {
std::unique_ptr<ShellSurface> shell_surface =
GetUserDataAs<Display>(resource)->CreateShellSurface(
GetUserDataAs<Surface>(surface));
if (!shell_surface) {
wl_resource_post_error(resource, WL_SHELL_ERROR_ROLE,
"surface has already been assigned a role");
return;
}
wl_resource* shell_surface_resource =
wl_resource_create(client, &wl_shell_surface_interface, 1, id);
// Shell surfaces are initially disabled and needs to be explicitly mapped
// before they are enabled and can become visible.
shell_surface->SetEnabled(false);
shell_surface->SetSecurityDelegate(GetSecurityDelegate(client));
shell_surface->set_configure_callback(
base::BindRepeating(&HandleShellSurfaceConfigureCallback,
base::Unretained(shell_surface_resource)));
shell_surface->set_surface_destroyed_callback(base::BindOnce(
&wl_resource_destroy, base::Unretained(shell_surface_resource)));
SetImplementation(shell_surface_resource, &shell_surface_implementation,
std::move(shell_surface));
}
const struct wl_shell_interface shell_implementation = {
shell_get_shell_surface};
} // namespace
void bind_shell(wl_client* client, void* data, uint32_t version, uint32_t id) {
wl_resource* resource =
wl_resource_create(client, &wl_shell_interface, 1, id);
wl_resource_set_implementation(resource, &shell_implementation, data,
nullptr);
}
} // namespace wayland
} // namespace exo