Commit 34f6a34f authored by Tom Anderson's avatar Tom Anderson Committed by Chromium LUCI CQ

[XProto] Add initial property cache

This is a first step toward reducing round trips on state
changes and during DnD and tab dragging.

Followup changes will:
* Add the ability to set properties
* Add a event-related unit tests
  * Before this can be done, event dispatching needs to be
    refactored to remove reliance on X11EventSource.
    * This will also allow us to move PropertyCache from
      //ui/base/x to //ui/gfx/x.

BUG=739898
R=sky

Change-Id: I3bdd3a7200b7c7d6785b0b5cdced0c1673d76ec5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2578117
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835499}
parent b6c0a534
......@@ -1131,6 +1131,7 @@ test("ui_base_unittests") {
if (use_x11) {
sources += [
"dragdrop/os_exchange_data_provider_x11_unittest.cc",
"x/property_cache_unittest.cc",
"x/selection_requestor_unittest.cc",
]
deps += [ "//ui/gfx/x:unit_test" ]
......
......@@ -12,6 +12,8 @@ component("x") {
output_name = "ui_base_x"
sources = [
"property_cache.cc",
"property_cache.h",
"selection_utils.cc",
"selection_utils.h",
"x11_cursor.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/x/property_cache.h"
#include <limits>
#include "base/check_op.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/xproto.h"
namespace ui {
PropertyCache::PropertyCache(x11::Connection* connection,
x11::Window window,
const std::vector<x11::Atom>& properties)
: connection_(connection),
window_(window),
event_selector_(window_, x11::EventMask::PropertyChange) {
if (X11EventSource::GetInstance())
X11EventSource::GetInstance()->AddXEventObserver(this);
std::vector<std::pair<x11::Atom, PropertyValue>> mem(properties.size());
for (size_t i = 0; i < properties.size(); i++) {
mem[i].first = properties[i];
FetchProperty(properties[i], &mem[i].second);
}
properties_ = base::flat_map<x11::Atom, PropertyValue>(std::move(mem));
}
PropertyCache::~PropertyCache() {
if (X11EventSource::GetInstance())
X11EventSource::GetInstance()->RemoveXEventObserver(this);
}
const x11::GetPropertyResponse& PropertyCache::GetProperty(x11::Atom atom) {
auto it = properties_.find(atom);
DCHECK(it != properties_.end());
if (!it->second.response.has_value())
it->second.future.Wait();
DCHECK(it->second.response.has_value());
return it->second.response.value();
}
void PropertyCache::WillProcessXEvent(x11::Event* xev) {
auto* prop = xev->As<x11::PropertyNotifyEvent>();
if (!prop)
return;
if (prop->window != window_)
return;
auto it = properties_.find(prop->atom);
if (it == properties_.end())
return;
FetchProperty(it->first, &it->second);
}
void PropertyCache::FetchProperty(x11::Atom property, PropertyValue* value) {
value->future = connection_->GetProperty({
.window = window_,
.property = property,
.long_length = std::numeric_limits<uint32_t>::max(),
});
value->future.OnResponse(base::BindOnce(&PropertyCache::OnGetPropertyResponse,
weak_factory_.GetWeakPtr(), value));
}
void PropertyCache::OnGetPropertyResponse(PropertyValue* value,
x11::GetPropertyResponse response) {
value->response = std::move(response);
}
PropertyCache::PropertyValue::PropertyValue() = default;
PropertyCache::PropertyValue::PropertyValue(PropertyValue&&) = default;
PropertyCache::PropertyValue& PropertyCache::PropertyValue::operator=(
PropertyValue&&) = default;
PropertyCache::PropertyValue::~PropertyValue() = default;
} // namespace ui
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_X_PROPERTY_CACHE_H_
#define UI_BASE_X_PROPERTY_CACHE_H_
#include <vector>
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto.h"
namespace ui {
// Watches properties on an X11 window. Property values are obtained once upon
// creation and are refreshed after each property change.
class COMPONENT_EXPORT(UI_BASE_X) PropertyCache : public XEventObserver {
public:
PropertyCache(x11::Connection* connection,
x11::Window window,
const std::vector<x11::Atom>& properties);
PropertyCache(const PropertyCache&) = delete;
PropertyCache& operator=(const PropertyCache&) = delete;
~PropertyCache() override;
const x11::GetPropertyResponse& GetProperty(x11::Atom atom);
private:
struct PropertyValue {
PropertyValue();
PropertyValue(PropertyValue&&);
PropertyValue& operator=(PropertyValue&&);
~PropertyValue();
x11::Future<x11::GetPropertyReply> future;
// |response| is nullopt if the request hasn't yet finished.
base::Optional<x11::GetPropertyResponse> response = base::nullopt;
};
// ui::XEventObserver:
void WillProcessXEvent(x11::Event* xev) override;
void FetchProperty(x11::Atom property, PropertyValue* value);
void OnGetPropertyResponse(PropertyValue* value,
x11::GetPropertyResponse response);
x11::Connection* connection_;
x11::Window window_;
XScopedEventSelector event_selector_;
base::flat_map<x11::Atom, PropertyValue> properties_;
base::WeakPtrFactory<PropertyCache> weak_factory_{this};
};
} // namespace ui
#endif // UI_BASE_X_PROPERTY_CACHE_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/x/property_cache.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
namespace ui {
TEST(X11PropertyCacheTest, Basic) {
x11::Connection connection;
auto window = CreateDummyWindow();
auto atom = gfx::GetAtom("DUMMY ATOM");
SetProperty(window, atom, x11::Atom::ATOM, atom).Sync();
PropertyCache cache(&connection, window, {atom});
auto& response = cache.GetProperty(atom);
ASSERT_TRUE(response);
EXPECT_EQ(response->bytes_after, 0u);
EXPECT_EQ(response->format, 32);
EXPECT_EQ(response->type, x11::Atom::ATOM);
EXPECT_EQ(*response->value->front_as<x11::Atom>(), atom);
EXPECT_EQ(response->value_len, 1u);
}
} // namespace ui
......@@ -34,6 +34,7 @@
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_types.h"
typedef unsigned long Cursor;
......@@ -172,14 +173,14 @@ bool GetProperty(x11::Window window, const x11::Atom name, T* value) {
}
template <typename T>
void SetArrayProperty(x11::Window window,
x11::Atom name,
x11::Atom type,
const std::vector<T>& values) {
x11::Future<void> SetArrayProperty(x11::Window window,
x11::Atom name,
x11::Atom type,
const std::vector<T>& values) {
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
std::vector<uint8_t> data(sizeof(T) * values.size());
memcpy(data.data(), values.data(), sizeof(T) * values.size());
x11::Connection::Get()->ChangeProperty(x11::ChangePropertyRequest{
return x11::Connection::Get()->ChangeProperty(x11::ChangePropertyRequest{
.window = static_cast<x11::Window>(window),
.property = name,
.type = type,
......@@ -189,11 +190,11 @@ void SetArrayProperty(x11::Window window,
}
template <typename T>
void SetProperty(x11::Window window,
x11::Atom name,
x11::Atom type,
const T& value) {
SetArrayProperty(window, name, type, std::vector<T>{value});
x11::Future<void> SetProperty(x11::Window window,
x11::Atom name,
x11::Atom type,
const T& value) {
return SetArrayProperty(window, name, type, std::vector<T>{value});
}
COMPONENT_EXPORT(UI_BASE_X)
......
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