Commit 2e943845 authored by Yuanyao Zhong's avatar Yuanyao Zhong Committed by Chromium LUCI CQ

[Chromecast] Add create surface logic to wayland_webview_client

Extend the wayland_webview_client to be able to create a surface with
buffer. This can be use to test the window and surface composition.

Test: build and test on desktop.
Bug: None
Change-Id: Id8aca9f2fe9819e9535986f978d7190eb30cbafc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2569971Reviewed-by: default avatarDaniel Nicoara <dnicoara@chromium.org>
Commit-Queue: Yuanyao Zhong <yyzhong@google.com>
Cr-Commit-Position: refs/heads/master@{#834759}
parent 9702e4fd
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "chromecast/browser/webview/proto/webview.pb.h" #include "chromecast/browser/webview/proto/webview.pb.h"
#include "third_party/grpc/src/include/grpcpp/grpcpp.h" #include "third_party/grpc/src/include/grpcpp/grpcpp.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrDirectContext.h" #include "third_party/skia/include/gpu/GrDirectContext.h"
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
...@@ -28,6 +30,7 @@ constexpr int kGrpcMaxReconnectBackoffMs = 1000; ...@@ -28,6 +30,7 @@ constexpr int kGrpcMaxReconnectBackoffMs = 1000;
constexpr char kBackCommand[] = "back"; constexpr char kBackCommand[] = "back";
constexpr char kCreateCommand[] = "create"; constexpr char kCreateCommand[] = "create";
constexpr char kCreateSurfaceCommand[] = "create_surface";
constexpr char kDestroyCommand[] = "destroy"; constexpr char kDestroyCommand[] = "destroy";
constexpr char kForwardCommand[] = "forward"; constexpr char kForwardCommand[] = "forward";
constexpr char kListCommand[] = "list"; constexpr char kListCommand[] = "list";
...@@ -35,6 +38,7 @@ constexpr char kNavigateCommand[] = "navigate"; ...@@ -35,6 +38,7 @@ constexpr char kNavigateCommand[] = "navigate";
constexpr char kResizeCommand[] = "resize"; constexpr char kResizeCommand[] = "resize";
constexpr char kPositionCommand[] = "position"; constexpr char kPositionCommand[] = "position";
constexpr char kKeyCommand[] = "key"; constexpr char kKeyCommand[] = "key";
constexpr char kFillCommand[] = "fill";
void FrameCallback(void* data, wl_callback* callback, uint32_t time) { void FrameCallback(void* data, wl_callback* callback, uint32_t time) {
WebviewClient* webview_client = static_cast<WebviewClient*>(data); WebviewClient* webview_client = static_cast<WebviewClient*>(data);
...@@ -57,10 +61,24 @@ using chromecast::webview::TouchInput; ...@@ -57,10 +61,24 @@ using chromecast::webview::TouchInput;
using chromecast::webview::WebviewRequest; using chromecast::webview::WebviewRequest;
using chromecast::webview::WebviewResponse; using chromecast::webview::WebviewResponse;
WebviewClient::Webview::Webview() {} WebviewClient::Webview::Webview() {
isWebview = true;
}
WebviewClient::Webview::~Webview() {} WebviewClient::Webview::~Webview() {}
WebviewClient::Surface::Surface() {}
WebviewClient::Surface::~Surface() {}
WebviewClient::Webview* WebviewClient::Webview::FromSurface(
WebviewClient::Surface* surface) {
if (!surface->isWebview) {
return nullptr;
}
return static_cast<Webview*>(surface);
}
WebviewClient::WebviewClient() WebviewClient::WebviewClient()
: task_runner_(base::ThreadTaskRunnerHandle::Get()), : task_runner_(base::ThreadTaskRunnerHandle::Get()),
file_descriptor_watcher_(task_runner_) {} file_descriptor_watcher_(task_runner_) {}
...@@ -125,28 +143,41 @@ void WebviewClient::AllocateBuffers(const InitParams& params) { ...@@ -125,28 +143,41 @@ void WebviewClient::AllocateBuffers(const InitParams& params) {
} }
} }
void WebviewClient::CreateWebview(const std::vector<std::string>& tokens) { bool WebviewClient::SetupSurface(const std::vector<std::string>& tokens,
Surface* surface,
int* id) {
if (tokens.size() != 2) { if (tokens.size() != 2) {
LOG(ERROR) << "Usage: create [ID]"; LOG(ERROR) << "Usage: create [ID]";
return; return false;
} }
int id; if (!base::StringToInt(tokens[1], id)) {
if (!base::StringToInt(tokens[1], &id)) {
LOG(ERROR) << "ID is not an int"; LOG(ERROR) << "ID is not an int";
return; return false;
} else if (webviews_.find(id) != webviews_.end()) { } else if (surfaces_.find(*id) != surfaces_.end()) {
LOG(ERROR) << "Webview with ID " << tokens[1] << " already exists"; LOG(ERROR) << "Surface with ID " << tokens[1] << " already exists";
return; return false;
} }
std::unique_ptr<Webview> webview = std::make_unique<Webview>(); surface->buffer = CreateBuffer(gfx::Size(1, 1), drm_format_, bo_usage_);
webview->buffer = CreateBuffer(gfx::Size(1, 1), drm_format_, bo_usage_);
webview->surface.reset(static_cast<wl_surface*>( surface->surface.reset(static_cast<wl_surface*>(
wl_compositor_create_surface(globals_.compositor.get()))); wl_compositor_create_surface(globals_.compositor.get())));
surface->subsurface.reset(wl_subcompositor_get_subsurface(
globals_.subcompositor.get(), surface->surface.get(), surface_.get()));
wl_subsurface_set_sync(surface->subsurface.get());
return true;
}
void WebviewClient::CreateWebview(const std::vector<std::string>& tokens) {
std::unique_ptr<Webview> webview = std::make_unique<Webview>();
int id;
if (!SetupSurface(tokens, webview.get(), &id)) {
return;
}
webview->context = std::make_unique<::grpc::ClientContext>(); webview->context = std::make_unique<::grpc::ClientContext>();
webview->client = stub_->CreateWebview(webview->context.get()); webview->client = stub_->CreateWebview(webview->context.get());
...@@ -164,10 +195,6 @@ void WebviewClient::CreateWebview(const std::vector<std::string>& tokens) { ...@@ -164,10 +195,6 @@ void WebviewClient::CreateWebview(const std::vector<std::string>& tokens) {
return; return;
} }
webview->subsurface.reset(wl_subcompositor_get_subsurface(
globals_.subcompositor.get(), webview->surface.get(), surface_.get()));
wl_subsurface_set_sync(webview->subsurface.get());
std::unique_ptr<zaura_surface> aura_surface; std::unique_ptr<zaura_surface> aura_surface;
aura_surface.reset(zaura_shell_get_aura_surface(globals_.aura_shell.get(), aura_surface.reset(zaura_shell_get_aura_surface(globals_.aura_shell.get(),
webview->surface.get())); webview->surface.get()));
...@@ -177,16 +204,25 @@ void WebviewClient::CreateWebview(const std::vector<std::string>& tokens) { ...@@ -177,16 +204,25 @@ void WebviewClient::CreateWebview(const std::vector<std::string>& tokens) {
} }
zaura_surface_set_client_surface_id(aura_surface.get(), id); zaura_surface_set_client_surface_id(aura_surface.get(), id);
webviews_[id] = std::move(webview); surfaces_[id] = std::move(webview);
}
void WebviewClient::CreateSurface(const std::vector<std::string>& tokens) {
std::unique_ptr<Surface> surface = std::make_unique<Surface>();
int id;
if (!SetupSurface(tokens, surface.get(), &id)) {
return;
}
surfaces_[id] = std::move(surface);
} }
void WebviewClient::DestroyWebview(const std::vector<std::string>& tokens) { void WebviewClient::DestroySurface(const std::vector<std::string>& tokens) {
int id; int id;
if (tokens.size() != 2 || !base::StringToInt(tokens[1], &id)) { if (tokens.size() != 2 || !base::StringToInt(tokens[1], &id)) {
LOG(ERROR) << "Usage: destroy [ID]"; LOG(ERROR) << "Usage: destroy [ID]";
return; return;
} }
webviews_.erase(id); surfaces_.erase(id);
} }
void WebviewClient::HandleDown(void* data, void WebviewClient::HandleDown(void* data,
...@@ -200,17 +236,17 @@ void WebviewClient::HandleDown(void* data, ...@@ -200,17 +236,17 @@ void WebviewClient::HandleDown(void* data,
gfx::Point touch_point(wl_fixed_to_int(x), wl_fixed_to_int(y)); gfx::Point touch_point(wl_fixed_to_int(x), wl_fixed_to_int(y));
auto iter = std::find_if( auto iter = std::find_if(
webviews_.begin(), webviews_.end(), surfaces_.begin(), surfaces_.end(),
[surface](const std::pair<const int, std::unique_ptr<Webview>>& pair) { [surface](const std::pair<const int, std::unique_ptr<Surface>>& pair) {
const auto& webview = pair.second; const auto& webview = pair.second;
return webview->surface.get() == surface; return webview->surface.get() == surface;
}); });
if (iter == webviews_.end()) { if (iter == surfaces_.end() || !Webview::FromSurface(iter->second.get())) {
focused_webview_ = nullptr; focused_webview_ = nullptr;
return; return;
} }
const Webview* webview = iter->second.get(); const Webview* webview = Webview::FromSurface(iter->second.get());
focused_webview_ = webview; focused_webview_ = webview;
SendTouchInput(focused_webview_, touch_point.x(), touch_point.y(), SendTouchInput(focused_webview_, touch_point.x(), touch_point.y(),
ui::ET_TOUCH_PRESSED, time, id); ui::ET_TOUCH_PRESSED, time, id);
...@@ -300,14 +336,16 @@ void WebviewClient::InputCallback() { ...@@ -300,14 +336,16 @@ void WebviewClient::InputCallback() {
if (tokens[0] == kCreateCommand) if (tokens[0] == kCreateCommand)
CreateWebview(tokens); CreateWebview(tokens);
else if (tokens[0] == kCreateSurfaceCommand)
CreateSurface(tokens);
else if (tokens[0] == kDestroyCommand) else if (tokens[0] == kDestroyCommand)
DestroyWebview(tokens); DestroySurface(tokens);
else if (tokens[0] == kListCommand) else if (tokens[0] == kListCommand)
ListActiveWebviews(); ListActiveSurfaces();
else if (tokens[1] == kNavigateCommand) else if (tokens[1] == kNavigateCommand)
SendNavigationRequest(tokens); SendNavigationRequest(tokens);
else if (tokens[1] == kResizeCommand) else if (tokens[1] == kResizeCommand)
SendResizeRequest(tokens); HandleResizeRequest(tokens);
else if (tokens[1] == kPositionCommand) else if (tokens[1] == kPositionCommand)
SetPosition(tokens); SetPosition(tokens);
else if (tokens[1] == kBackCommand) else if (tokens[1] == kBackCommand)
...@@ -316,14 +354,16 @@ void WebviewClient::InputCallback() { ...@@ -316,14 +354,16 @@ void WebviewClient::InputCallback() {
SendForwardRequest(tokens); SendForwardRequest(tokens);
else if (tokens[1] == kKeyCommand) else if (tokens[1] == kKeyCommand)
SendKeyRequest(tokens); SendKeyRequest(tokens);
else if (tokens[1] == kFillCommand)
HandleFillSurfaceColor(tokens);
std::cout << "Enter command: "; std::cout << "Enter command: ";
std::cout.flush(); std::cout.flush();
} }
void WebviewClient::ListActiveWebviews() { void WebviewClient::ListActiveSurfaces() {
for (const auto& pair : webviews_) for (const auto& pair : surfaces_)
std::cout << pair.first << std::endl; std::cout << "Surface: " << pair.first << std::endl;
} }
void WebviewClient::Paint() { void WebviewClient::Paint() {
...@@ -348,14 +388,14 @@ void WebviewClient::Paint() { ...@@ -348,14 +388,14 @@ void WebviewClient::Paint() {
static wl_callback_listener frame_listener = {FrameCallback}; static wl_callback_listener frame_listener = {FrameCallback};
wl_callback_add_listener(frame_callback_.get(), &frame_listener, this); wl_callback_add_listener(frame_callback_.get(), &frame_listener, this);
for (const auto& pair : webviews_) { for (const auto& pair : surfaces_) {
Webview* webview = pair.second.get(); Surface* surface = pair.second.get();
wl_surface_set_buffer_scale(webview->surface.get(), scale_); wl_surface_set_buffer_scale(surface->surface.get(), scale_);
wl_surface_damage(webview->surface.get(), 0, 0, surface_size_.width(), wl_surface_damage(surface->surface.get(), 0, 0, surface_size_.width(),
surface_size_.height()); surface_size_.height());
wl_surface_attach(webview->surface.get(), webview->buffer->buffer.get(), 0, wl_surface_attach(surface->surface.get(), surface->buffer->buffer.get(), 0,
0); 0);
wl_surface_commit(webview->surface.get()); wl_surface_commit(surface->surface.get());
} }
wl_surface_commit(surface_.get()); wl_surface_commit(surface_.get());
...@@ -370,12 +410,15 @@ void WebviewClient::SchedulePaint() { ...@@ -370,12 +410,15 @@ void WebviewClient::SchedulePaint() {
void WebviewClient::SendBackRequest(const std::vector<std::string>& tokens) { void WebviewClient::SendBackRequest(const std::vector<std::string>& tokens) {
int id; int id;
if (tokens.size() != 2 || !base::StringToInt(tokens[0], &id) || if (tokens.size() != 2 || !base::StringToInt(tokens[0], &id) ||
webviews_.find(id) == webviews_.end()) { surfaces_.find(id) == surfaces_.end()) {
LOG(ERROR) << "Usage: [ID] back"; LOG(ERROR) << "Usage: [ID] back";
return; return;
} }
const auto& webview = webviews_[id]; const Webview* webview = Webview::FromSurface(surfaces_[id].get());
if (!webview)
return;
WebviewRequest back_request; WebviewRequest back_request;
back_request.mutable_go_back(); back_request.mutable_go_back();
if (!webview->client->Write(back_request)) { if (!webview->client->Write(back_request)) {
...@@ -386,12 +429,15 @@ void WebviewClient::SendBackRequest(const std::vector<std::string>& tokens) { ...@@ -386,12 +429,15 @@ void WebviewClient::SendBackRequest(const std::vector<std::string>& tokens) {
void WebviewClient::SendForwardRequest(const std::vector<std::string>& tokens) { void WebviewClient::SendForwardRequest(const std::vector<std::string>& tokens) {
int id; int id;
if (tokens.size() != 2 || !base::StringToInt(tokens[0], &id) || if (tokens.size() != 2 || !base::StringToInt(tokens[0], &id) ||
webviews_.find(id) == webviews_.end()) { surfaces_.find(id) == surfaces_.end()) {
LOG(ERROR) << "Usage: [ID] forward"; LOG(ERROR) << "Usage: [ID] forward";
return; return;
} }
const auto& webview = webviews_[id]; const Webview* webview = Webview::FromSurface(surfaces_[id].get());
if (!webview)
return;
WebviewRequest forward_request; WebviewRequest forward_request;
forward_request.mutable_go_forward(); forward_request.mutable_go_forward();
if (!webview->client->Write(forward_request)) { if (!webview->client->Write(forward_request)) {
...@@ -403,12 +449,15 @@ void WebviewClient::SendNavigationRequest( ...@@ -403,12 +449,15 @@ void WebviewClient::SendNavigationRequest(
const std::vector<std::string>& tokens) { const std::vector<std::string>& tokens) {
int id; int id;
if (tokens.size() != 3 || !base::StringToInt(tokens[0], &id) || if (tokens.size() != 3 || !base::StringToInt(tokens[0], &id) ||
webviews_.find(id) == webviews_.end()) { surfaces_.find(id) == surfaces_.end()) {
LOG(ERROR) << "Usage: [ID] navigate [URL]"; LOG(ERROR) << "Usage: [ID] navigate [URL]";
return; return;
} }
const auto& webview = webviews_[id]; const Webview* webview = Webview::FromSurface(surfaces_[id].get());
if (!webview)
return;
WebviewRequest load_url_request; WebviewRequest load_url_request;
load_url_request.mutable_navigate()->set_url(tokens[2]); load_url_request.mutable_navigate()->set_url(tokens[2]);
if (!webview->client->Write(load_url_request)) { if (!webview->client->Write(load_url_request)) {
...@@ -416,17 +465,41 @@ void WebviewClient::SendNavigationRequest( ...@@ -416,17 +465,41 @@ void WebviewClient::SendNavigationRequest(
} }
} }
void WebviewClient::SendResizeRequest(const std::vector<std::string>& tokens) { void WebviewClient::HandleResizeRequest(
const std::vector<std::string>& tokens) {
int id, width, height; int id, width, height;
if (tokens.size() != 4 || !base::StringToInt(tokens[0], &id) || if (tokens.size() != 4 || !base::StringToInt(tokens[0], &id) ||
webviews_.find(id) == webviews_.end() ||
!base::StringToInt(tokens[2], &width) || !base::StringToInt(tokens[2], &width) ||
!base::StringToInt(tokens[3], &height)) { !base::StringToInt(tokens[3], &height)) {
LOG(ERROR) << "Usage: [ID] resize [WIDTH] [HEIGHT]"; LOG(ERROR) << "Usage: [ID] resize [WIDTH] [HEIGHT]";
return; return;
} }
const auto& webview = webviews_[id]; if (surfaces_.find(id) != surfaces_.end()) {
Webview* webview = Webview::FromSurface(surfaces_[id].get());
if (webview) {
SendResizeRequest(webview, width, height);
} else {
surfaces_[id]->buffer =
CreateBuffer(gfx::Size(width, height), drm_format_, bo_usage_);
}
}
}
void WebviewClient::HandleFillSurfaceColor(
const std::vector<std::string>& tokens) {
int id;
uint32_t color;
if (tokens.size() != 3 || !base::StringToInt(tokens[0], &id) ||
!base::HexStringToUInt(tokens[2], &color) ||
surfaces_.find(id) == surfaces_.end()) {
LOG(ERROR) << "Usage: [ID] " << kFillCommand << " [ARGB] (e.g. FF000000)";
return;
}
surfaces_[id]->buffer->sk_surface->getCanvas()->clear(color);
}
void WebviewClient::SendResizeRequest(Webview* webview, int width, int height) {
WebviewRequest resize_request; WebviewRequest resize_request;
resize_request.mutable_resize()->set_width(width); resize_request.mutable_resize()->set_width(width);
resize_request.mutable_resize()->set_height(height); resize_request.mutable_resize()->set_height(height);
...@@ -446,12 +519,14 @@ void WebviewClient::SendKeyRequest(const std::vector<std::string>& tokens) { ...@@ -446,12 +519,14 @@ void WebviewClient::SendKeyRequest(const std::vector<std::string>& tokens) {
return; return;
} }
const auto& webview = webviews_[id]; const Webview* webview = Webview::FromSurface(surfaces_[id].get());
if (!webview)
return;
SendKeyEvent(webview.get(), base::Time::Now().ToDeltaSinceWindowsEpoch(), SendKeyEvent(webview, base::Time::Now().ToDeltaSinceWindowsEpoch(), tokens[2],
tokens[2], true); true);
SendKeyEvent(webview.get(), base::Time::Now().ToDeltaSinceWindowsEpoch(), SendKeyEvent(webview, base::Time::Now().ToDeltaSinceWindowsEpoch(), tokens[2],
tokens[2], false); false);
} }
void WebviewClient::SendKeyEvent(const Webview* webview, void WebviewClient::SendKeyEvent(const Webview* webview,
...@@ -501,14 +576,18 @@ void WebviewClient::SendTouchInput(const Webview* webview, ...@@ -501,14 +576,18 @@ void WebviewClient::SendTouchInput(const Webview* webview,
void WebviewClient::SetPosition(const std::vector<std::string>& tokens) { void WebviewClient::SetPosition(const std::vector<std::string>& tokens) {
int id, x, y; int id, x, y;
if (tokens.size() != 4 || !base::StringToInt(tokens[0], &id) || if (tokens.size() != 4 || !base::StringToInt(tokens[0], &id) ||
webviews_.find(id) == webviews_.end() ||
!base::StringToInt(tokens[2], &x) || !base::StringToInt(tokens[3], &y)) { !base::StringToInt(tokens[2], &x) || !base::StringToInt(tokens[3], &y)) {
LOG(ERROR) << "Usage: [ID] position [X] [Y]"; LOG(ERROR) << "Usage: [ID] position [X] [Y]";
return; return;
} }
const auto& webview = webviews_[id]; Surface* surface = nullptr;
wl_subsurface_set_position(webview->subsurface.get(), x, y); if (surfaces_.find(id) != surfaces_.end()) {
surface = surfaces_[id].get();
} else {
LOG(ERROR) << "Cannont find surface with ID: " << id;
}
wl_subsurface_set_position(surface->subsurface.get(), x, y);
} }
void WebviewClient::TakeExclusiveAccess() { void WebviewClient::TakeExclusiveAccess() {
......
...@@ -40,19 +40,30 @@ class WebviewClient : public exo::wayland::clients::ClientBase { ...@@ -40,19 +40,30 @@ class WebviewClient : public exo::wayland::clients::ClientBase {
using WebviewRequestResponseClient = using WebviewRequestResponseClient =
::grpc::ClientReaderWriterInterface<chromecast::webview::WebviewRequest, ::grpc::ClientReaderWriterInterface<chromecast::webview::WebviewRequest,
chromecast::webview::WebviewResponse>; chromecast::webview::WebviewResponse>;
struct Webview { struct Surface {
Webview(); Surface();
~Webview(); virtual ~Surface();
bool isWebview = false;
std::unique_ptr<ClientBase::Buffer> buffer; std::unique_ptr<ClientBase::Buffer> buffer;
std::unique_ptr<wl_surface> surface; std::unique_ptr<wl_surface> surface;
std::unique_ptr<wl_subsurface> subsurface; std::unique_ptr<wl_subsurface> subsurface;
};
struct Webview : public Surface {
Webview();
~Webview() override;
static Webview* FromSurface(Surface* surface);
std::unique_ptr<WebviewRequestResponseClient> client; std::unique_ptr<WebviewRequestResponseClient> client;
std::unique_ptr<::grpc::ClientContext> context; std::unique_ptr<::grpc::ClientContext> context;
}; };
void AllocateBuffers(const InitParams& params); void AllocateBuffers(const InitParams& params);
void CreateWebview(const std::vector<std::string>& tokens); void CreateWebview(const std::vector<std::string>& tokens);
void DestroyWebview(const std::vector<std::string>& tokens); void CreateSurface(const std::vector<std::string>& tokens);
bool SetupSurface(const std::vector<std::string>& tokens,
Surface* surface,
int* id);
void DestroySurface(const std::vector<std::string>& tokens);
void HandleDown(void* data, void HandleDown(void* data,
struct wl_touch* wl_touch, struct wl_touch* wl_touch,
uint32_t serial, uint32_t serial,
...@@ -79,12 +90,14 @@ class WebviewClient : public exo::wayland::clients::ClientBase { ...@@ -79,12 +90,14 @@ class WebviewClient : public exo::wayland::clients::ClientBase {
uint32_t time, uint32_t time,
int32_t id) override; int32_t id) override;
void InputCallback(); void InputCallback();
void ListActiveWebviews(); void ListActiveSurfaces();
void Paint(); void Paint();
void SendBackRequest(const std::vector<std::string>& tokens); void SendBackRequest(const std::vector<std::string>& tokens);
void SendForwardRequest(const std::vector<std::string>& tokens); void SendForwardRequest(const std::vector<std::string>& tokens);
void SendNavigationRequest(const std::vector<std::string>& tokens); void SendNavigationRequest(const std::vector<std::string>& tokens);
void SendResizeRequest(const std::vector<std::string>& tokens); void SendResizeRequest(Webview* webview, int width, int height);
void HandleResizeRequest(const std::vector<std::string>& tokens);
void HandleFillSurfaceColor(const std::vector<std::string>& tokens);
void SendKeyRequest(const std::vector<std::string>& tokens); void SendKeyRequest(const std::vector<std::string>& tokens);
void SendTouchInput(const Webview* webview, void SendTouchInput(const Webview* webview,
...@@ -106,7 +119,7 @@ class WebviewClient : public exo::wayland::clients::ClientBase { ...@@ -106,7 +119,7 @@ class WebviewClient : public exo::wayland::clients::ClientBase {
int32_t bo_usage_ = 0; int32_t bo_usage_ = 0;
const Webview* focused_webview_; const Webview* focused_webview_;
std::map<int, std::unique_ptr<Webview>> webviews_; std::map<int, std::unique_ptr<Surface>> surfaces_;
std::map<int32_t, gfx::Point> points_; std::map<int32_t, gfx::Point> points_;
std::unique_ptr<wl_callback> frame_callback_; std::unique_ptr<wl_callback> frame_callback_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment