blob: 9388682347dd72e3c1b6c4aaafefc947e4b15238 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/x/atom_cache.h"
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "third_party/abseil-cpp/absl/strings/ascii.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/future.h"
namespace x11 {
namespace {
constexpr auto kAtomsToCache = std::to_array<const char* const>({
"ATOM_PAIR",
"Abs Dbl End Timestamp",
"Abs Dbl Fling X Velocity",
"Abs Dbl Fling Y Velocity",
"Abs Dbl Metrics Data 1",
"Abs Dbl Metrics Data 2",
"Abs Dbl Ordinal X",
"Abs Dbl Ordinal Y",
"Abs Dbl Start Timestamp",
"Abs Finger Count",
"Abs Fling State",
"Abs MT Orientation",
"Abs MT Position X",
"Abs MT Position Y",
"Abs MT Pressure",
"Abs MT Touch Major",
"Abs MT Touch Minor",
"Abs MT Tracking ID",
"Abs Metrics Type",
"Abs Pressure",
"Abs Tilt X",
"Abs Tilt Y",
"Abs X",
"Abs Y",
"CHECK",
"CHROME_SELECTION",
"CHROMIUM_COMPOSITE_WINDOW",
"CHROMIUM_TIMESTAMP",
"CLIPBOARD",
"CLIPBOARD_MANAGER",
"Content Protection",
"Desired",
"Device Node",
"Device Product ID",
"EDID",
"Enabled",
"FAKE_SELECTION",
"Full aspect",
"INCR",
"KEYBOARD",
"LOCK",
"MOUSE",
"MULTIPLE",
"Rel Horiz Wheel",
"Rel Vert Wheel",
"SAVE_TARGETS",
"SELECTION_STRING",
"STRING",
"TARGET1",
"TARGET2",
"TARGETS",
"TEXT",
"TIMESTAMP",
"TOUCHPAD",
"TOUCHSCREEN",
"Tap Paused",
"Touch Timestamp",
"UTF8_STRING",
"Undesired",
"WM_CHANGE_STATE",
"WM_DELETE_WINDOW",
"WM_PROTOCOLS",
"WM_WINDOW_ROLE",
"XdndActionAsk",
"XdndActionCopy",
"XdndActionDirectSave",
"XdndActionLink",
"XdndActionList",
"XdndActionMove",
"XdndActionPrivate",
"XdndAware",
"XdndDirectSave0",
"XdndDrop",
"XdndEnter",
"XdndFinished",
"XdndLeave",
"XdndPosition",
"XdndProxy",
"XdndSelection",
"XdndStatus",
"XdndTypeList",
"_CHROME_DISPLAY_INTERNAL",
"_CHROME_DISPLAY_ROTATION",
"_CHROME_DISPLAY_SCALE_FACTOR",
"_CHROMIUM_DRAG_RECEIVER",
"_GTK_FRAME_EXTENTS",
"_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED",
"_GTK_SHOW_WINDOW_MENU",
"_GTK_THEME_VARIANT",
"_ICC_PROFILE",
"_MOTIF_WM_HINTS",
"_NETSCAPE_URL",
"_NET_ACTIVE_WINDOW",
"_NET_CURRENT_DESKTOP",
"_NET_FRAME_EXTENTS",
"_NET_STARTUP_INFO",
"_NET_STARTUP_INFO_BEGIN",
"_NET_SUPPORTED",
"_NET_SUPPORTING_WM_CHECK",
"_NET_SYSTEM_TRAY_OPCODE",
"_NET_SYSTEM_TRAY_S0",
"_NET_SYSTEM_TRAY_VISUAL",
"_NET_WM_BYPASS_COMPOSITOR",
"_NET_WM_CM_S0",
"_NET_WM_DESKTOP",
"_NET_WM_ICON",
"_NET_WM_MOVERESIZE",
"_NET_WM_NAME",
"_NET_WM_OPAQUE_REGION",
"_NET_WM_PID",
"_NET_WM_PING",
"_NET_WM_STATE",
"_NET_WM_STATE_ABOVE",
"_NET_WM_STATE_FOCUSED",
"_NET_WM_STATE_FULLSCREEN",
"_NET_WM_STATE_HIDDEN",
"_NET_WM_STATE_MAXIMIZED_HORZ",
"_NET_WM_STATE_MAXIMIZED_VERT",
"_NET_WM_STATE_SKIP_TASKBAR",
"_NET_WM_STATE_STICKY",
"_NET_WM_SYNC_REQUEST",
"_NET_WM_SYNC_REQUEST_COUNTER",
"_NET_WM_USER_TIME",
"_NET_WM_WINDOW_OPACITY",
"_NET_WM_WINDOW_TYPE",
"_NET_WM_WINDOW_TYPE_DIALOG",
"_NET_WM_WINDOW_TYPE_DND",
"_NET_WM_WINDOW_TYPE_MENU",
"_NET_WM_WINDOW_TYPE_NORMAL",
"_NET_WM_WINDOW_TYPE_NOTIFICATION",
"_NET_WM_WINDOW_TYPE_TOOLTIP",
"_NET_WORKAREA",
"_SCREENSAVER_STATUS",
"_SCREENSAVER_VERSION",
"_XEMBED_INFO",
"application/octet-stream",
"application/vnd.chromium.test",
"chromium/filename",
"chromium/x-bookmark-entries",
"chromium/x-browser-actions",
"chromium/x-file-system-files",
"chromium/x-internal-source-rfh-token",
"chromium/x-pepper-custom-data",
"chromium/x-renderer-taint",
"chromium/x-source-url",
"chromium/x-web-custom-data",
"chromium/x-webkit-paste",
"image/png",
"image/svg+xml",
"marker_event",
"scaling mode",
"text/html",
"text/plain",
"text/plain;charset=utf-8",
"text/rtf",
"text/uri-list",
"text/x-moz-url",
"xwayland-keyboard",
"xwayland-pointer",
"xwayland-touch",
});
} // namespace
Atom GetAtom(const char* name) {
return Connection::Get()->GetAtom(name);
}
AtomCache::AtomCache(Connection* connection) : connection_(connection) {
std::vector<Future<InternAtomReply>> requests;
requests.reserve(kAtomsToCache.size());
for (const char* name : kAtomsToCache) {
requests.push_back(
connection_->InternAtom(InternAtomRequest{.name = name}));
}
// Flush so all requests are sent before waiting on any replies.
connection_->Flush();
std::vector<std::pair<const char*, Atom>> atoms;
// Reserve a little extra space in case unexpected atoms are cached,
// to prevent reallocating the buffer.
atoms.reserve(kAtomsToCache.size() + 3);
for (size_t i = 0; i < kAtomsToCache.size(); ++i) {
if (auto response = requests[i].Sync()) {
atoms.emplace_back(kAtomsToCache[i], static_cast<Atom>(response->atom));
}
}
cached_atoms_ = base::flat_map<const char*, Atom, Compare>(std::move(atoms));
}
AtomCache::~AtomCache() = default;
Atom AtomCache::GetAtom(const char* name) {
const auto it = cached_atoms_.find(name);
if (it != cached_atoms_.end()) {
return it->second;
}
Atom atom = Atom::None;
if (auto response =
connection_->InternAtom(InternAtomRequest{.name = name}).Sync()) {
atom = response->atom;
CHECK_GT(atom, x11::Atom::kLastPredefinedAtom)
<< " Use x11::Atom::" << name << " instead of x11::GetAtom(\"" << name
<< "\")";
auto owned_name = std::make_unique<std::string>(name);
// Don't log an error if the atom is dynamically named (ends with a digit).
if (owned_name->empty() || !absl::ascii_isdigit(owned_name->back())) {
LOG(ERROR) << "Add " << name << " to kAtomsToCache";
}
cached_atoms_.emplace(
owned_strings_.emplace_back(std::move(owned_name))->c_str(), atom);
}
return atom;
}
} // namespace x11