Commit fce1db03 authored by Tom Anderson's avatar Tom Anderson Committed by Commit Bot

[XProto] Use serializer/deserializers for special-case structs

This CL uses the special reader/writer added by [1] to check
that it's working.

[1] https://chromium-review.googlesource.com/c/chromium/src/+/2209961

BUG=1066670
R=msisov
CC=sky

Change-Id: I09c83827145916366f283e2bac93ed03d5db113a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2212976
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: default avatarMaksim Sisov <msisov@igalia.com>
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772383}
parent b1d9122c
......@@ -102,18 +102,13 @@ float GetRefreshRateFromXRRModeInfo(
return 0;
}
int DefaultScreenDepth(XDisplay* xdisplay) {
return DefaultDepth(xdisplay, DefaultScreen(xdisplay));
}
int DefaultBitsPerComponent(XDisplay* xdisplay) {
Visual* visual = DefaultVisual(xdisplay, DefaultScreen(xdisplay));
int DefaultBitsPerComponent() {
auto* connection = x11::Connection::Get();
const x11::XProto::VisualType* visual = connection->default_root_visual();
// The mask fields are only valid for DirectColor and TrueColor classes.
if (visual->c_class ==
static_cast<int>(x11::XProto::VisualClass::DirectColor) ||
visual->c_class ==
static_cast<int>(x11::XProto::VisualClass::TrueColor)) {
if (visual->c_class == x11::XProto::VisualClass::DirectColor ||
visual->c_class == x11::XProto::VisualClass::TrueColor) {
// RGB components are packed into fixed size integers for each visual. The
// layout of bits in the packing is given by
// |visual->{red,green,blue}_mask|. Count the number of bits to get the
......@@ -130,12 +125,12 @@ int DefaultBitsPerComponent(XDisplay* xdisplay) {
// Next, try getting the number of colormap entries per subfield. If it's a
// power of 2, log2 is a possible guess for the number of bits per component.
if (base::bits::IsPowerOfTwo(visual->map_entries))
return base::bits::Log2Ceiling(visual->map_entries);
if (base::bits::IsPowerOfTwo(visual->colormap_entries))
return base::bits::Log2Ceiling(visual->colormap_entries);
// |bits_per_rgb| can sometimes be unreliable (may be 11 for 30bpp visuals),
// so only use it as a last resort.
return visual->bits_per_rgb;
return visual->bits_per_rgb_value;
}
// Get the EDID data from the |output| and stores to |edid|.
......@@ -168,12 +163,12 @@ int GetXrandrVersion(XDisplay* xdisplay) {
}
std::vector<display::Display> GetFallbackDisplayList(float scale) {
XDisplay* display = gfx::GetXDisplay();
::Screen* screen = DefaultScreenOfDisplay(display);
gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
const auto* screen = x11::Connection::Get()->default_screen();
gfx::Size physical_size(screen->width_in_millimeters,
screen->height_in_millimeters);
int width = WidthOfScreen(screen);
int height = HeightOfScreen(screen);
int width = screen->width_in_pixels;
int height = screen->height_in_pixels;
gfx::Rect bounds_in_pixels(0, 0, width, height);
display::Display gfx_display(0, bounds_in_pixels);
......@@ -187,8 +182,8 @@ std::vector<display::Display> GetFallbackDisplayList(float scale) {
scale = 1;
}
gfx_display.set_color_depth(DefaultScreenDepth(display));
gfx_display.set_depth_per_component(DefaultBitsPerComponent(display));
gfx_display.set_color_depth(screen->root_depth);
gfx_display.set_depth_per_component(DefaultBitsPerComponent());
std::vector<display::Display> displays{gfx_display};
ClipWorkArea(&displays, 0, scale);
......@@ -201,7 +196,8 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
int64_t* primary_display_index_out) {
DCHECK(primary_display_index_out);
DCHECK_GE(version, kMinVersionXrandr);
auto* randr = x11::Connection::Get()->randr();
auto* connection = x11::Connection::Get();
auto* randr = connection->randr();
if (!randr)
return GetFallbackDisplayList(scale);
auto x_root_window = static_cast<x11::Window>(ui::GetX11RootWindow());
......@@ -212,8 +208,8 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
return GetFallbackDisplayList(scale);
}
const int depth = DefaultScreenDepth(gfx::GetXDisplay());
const int bits_per_component = DefaultBitsPerComponent(gfx::GetXDisplay());
const int depth = connection->default_screen()->root_depth;
const int bits_per_component = DefaultBitsPerComponent();
std::map<x11::RandR::Output, int> output_to_monitor =
GetMonitors(version, randr, x_root_window);
......
......@@ -773,23 +773,10 @@ void SetWMSpecState(XID window,
bool enabled,
x11::Atom state1,
x11::Atom state2) {
XEvent xclient;
memset(&xclient, 0, sizeof(xclient));
xclient.type = ClientMessage;
xclient.xclient.window = window;
xclient.xclient.message_type =
static_cast<uint32_t>(gfx::GetAtom("_NET_WM_STATE"));
// The data should be viewed as a list of longs, because x11::Atom is a
// typedef of long.
xclient.xclient.format = 32;
xclient.xclient.data.l[0] = enabled ? kNetWMStateAdd : kNetWMStateRemove;
xclient.xclient.data.l[1] = static_cast<uint32_t>(state1);
xclient.xclient.data.l[2] = static_cast<uint32_t>(state2);
xclient.xclient.data.l[3] = 1;
xclient.xclient.data.l[4] = 0;
XSendEvent(gfx::GetXDisplay(), GetX11RootWindow(), x11::False,
SubstructureRedirectMask | SubstructureNotifyMask, &xclient);
SendClientMessage(
window, GetX11RootWindow(), gfx::GetAtom("_NET_WM_STATE"),
{enabled ? kNetWMStateAdd : kNetWMStateRemove,
static_cast<uint32_t>(state1), static_cast<uint32_t>(state2), 1, 0});
}
void DoWMMoveResize(XDisplay* display,
......@@ -803,20 +790,8 @@ void DoWMMoveResize(XDisplay* display,
// grabs when it receives the event below.
XUngrabPointer(display, x11::CurrentTime);
XEvent event;
memset(&event, 0, sizeof(event));
event.xclient.type = ClientMessage;
event.xclient.display = display;
event.xclient.window = window;
event.xclient.message_type =
static_cast<uint32_t>(gfx::GetAtom("_NET_WM_MOVERESIZE"));
event.xclient.format = 32;
event.xclient.data.l[0] = location_px.x();
event.xclient.data.l[1] = location_px.y();
event.xclient.data.l[2] = direction;
XSendEvent(display, root_window, x11::False,
SubstructureRedirectMask | SubstructureNotifyMask, &event);
SendClientMessage(window, root_window, gfx::GetAtom("_NET_WM_MOVERESIZE"),
{location_px.x(), location_px.y(), direction, 0, 0});
}
bool HasWMSpecProperty(const base::flat_set<x11::Atom>& properties,
......@@ -1177,6 +1152,24 @@ SkColorType ColorTypeForVisual(void* visual) {
return kUnknown_SkColorType;
}
x11::Future<void> SendClientMessage(XID window,
XID target,
x11::Atom type,
const std::array<uint32_t, 5> data,
x11::XProto::EventMask event_mask) {
x11::XProto::ClientMessageEvent event{
.format = 32, .window = static_cast<x11::Window>(window), .type = type};
event.data.data32 = data;
auto event_bytes = x11::Write(event);
DCHECK_EQ(event_bytes.size(), 32ul);
auto* connection = x11::Connection::Get();
x11::XProto::SendEventRequest request{false, static_cast<x11::Window>(target),
event_mask};
std::copy(event_bytes.begin(), event_bytes.end(), request.event.begin());
return connection->SendEvent(request);
}
XRefcountedMemory::XRefcountedMemory(unsigned char* x11_data, size_t length)
: x11_data_(length ? x11_data : nullptr), length_(length) {}
......
......@@ -404,6 +404,16 @@ COMPONENT_EXPORT(UI_BASE_X) bool IsSyncExtensionAvailable();
COMPONENT_EXPORT(UI_BASE_X)
SkColorType ColorTypeForVisual(void* visual);
COMPONENT_EXPORT(UI_BASE_X)
x11::Future<void> SendClientMessage(
XID window,
XID target,
x11::Atom type,
const std::array<uint32_t, 5> data,
x11::XProto::EventMask event_mask =
x11::XProto::EventMask::SubstructureNotify |
x11::XProto::EventMask::SubstructureRedirect);
// Manages a piece of X11 allocated memory as a RefCountedMemory segment. This
// object takes ownership over the passed in memory and will free it with the
// X11 allocator when done.
......
......@@ -1577,23 +1577,13 @@ bool XWindow::InitializeAsStatusIcon() {
static_cast<int>(x11::XProto::BackPixmap::ParentRelative);
}
XChangeWindowAttributes(xdisplay_, xwindow_, flags, &attrs);
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = manager;
ev.xclient.message_type =
static_cast<uint32_t>(gfx::GetAtom("_NET_SYSTEM_TRAY_OPCODE"));
ev.xclient.format = 32;
ev.xclient.data.l[0] = ui::X11EventSource::GetInstance()->GetTimestamp();
ev.xclient.data.l[1] = kSystemTrayRequestDock;
ev.xclient.data.l[2] = xwindow_;
bool error;
{
gfx::X11ErrorTracker error_tracker;
XSendEvent(xdisplay_, manager, false, NoEventMask, &ev);
error = error_tracker.FoundNewError();
}
return !error;
auto future = ui::SendClientMessage(
manager, manager, gfx::GetAtom("_NET_SYSTEM_TRAY_OPCODE"),
{ui::X11EventSource::GetInstance()->GetTimestamp(),
kSystemTrayRequestDock, xwindow_, 0, 0},
x11::XProto::EventMask::NoEvent);
return !future.Sync().error;
}
} // namespace ui
......@@ -4,8 +4,14 @@
#include "ui/gfx/x/connection.h"
#include <X11/Xlib-xcb.h>
#include <xcb/xcb.h>
#include <algorithm>
#include "base/command_line.h"
#include "ui/gfx/x/x11_switches.h"
#include "ui/gfx/x/xproto_types.h"
namespace x11 {
......@@ -28,6 +34,32 @@ Connection* Connection::Get() {
}
Connection::Connection(XDisplay* display)
: XProto(display), ExtensionManager(this) {}
: XProto(display), ExtensionManager(this) {
if (!display)
return;
setup_ = std::make_unique<x11::XProto::Setup>(x11::Read<x11::XProto::Setup>(
reinterpret_cast<const uint8_t*>(xcb_get_setup(XcbConnection()))));
default_screen_ = &setup_->roots[DefaultScreen(display)];
default_root_depth_ =
&*std::find_if(default_screen_->allowed_depths.begin(),
default_screen_->allowed_depths.end(),
[&](const x11::XProto::Depth& depth) {
return depth.depth == default_screen_->root_depth;
});
defualt_root_visual_ = &*std::find_if(
default_root_depth_->visuals.begin(), default_root_depth_->visuals.end(),
[&](const x11::XProto::VisualType visual) {
return visual.visual_id == default_screen_->root_visual;
});
}
Connection::~Connection() = default;
xcb_connection_t* Connection::XcbConnection() {
if (!display())
return nullptr;
return XGetXCBConnection(display());
}
} // namespace x11
......@@ -24,8 +24,25 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
Connection(const Connection&) = delete;
Connection(Connection&&) = delete;
xcb_connection_t* XcbConnection();
const x11::XProto::Setup* setup() const { return setup_.get(); }
const x11::XProto::Screen* default_screen() const { return default_screen_; }
const x11::XProto::Depth* default_root_depth() const {
return default_root_depth_;
}
const x11::XProto::VisualType* default_root_visual() const {
return defualt_root_visual_;
}
private:
explicit Connection(XDisplay* display);
~Connection();
std::unique_ptr<x11::XProto::Setup> setup_;
const x11::XProto::Screen* default_screen_ = nullptr;
const x11::XProto::Depth* default_root_depth_ = nullptr;
const x11::XProto::VisualType* defualt_root_visual_ = nullptr;
};
} // namespace x11
......
......@@ -358,6 +358,9 @@ class GenXproto(FileWriter):
# Map from (XML tag, XML name) to XML element
self.module_names = {}
# Enums that represent bit masks.
self.bitenums = []
# Geenerate an ID suitable for use in temporary variable names.
def new_uid(self, ):
self.prev_id += 1
......@@ -953,6 +956,9 @@ class GenXproto(FileWriter):
return
self.types[renamed].add(t)
if isinstance(t, self.xcbgen.xtypes.Enum):
self.bitenums.append((t, name))
if not t.is_container:
return
......@@ -1103,6 +1109,16 @@ class GenXproto(FileWriter):
self.write()
self.write('} // namespace x11')
self.write()
self.namespace = []
for enum, name in self.bitenums:
name = self.qualtype(enum, name)
self.write('inline %s operator|(' % name)
with Indent(self, ' {0} l, {0} r)'.format(name) + ' {', '}'):
self.write('using T = std::underlying_type_t<%s>;' % name)
self.write('return static_cast<%s>(' % name)
self.write(' static_cast<T>(l) | static_cast<T>(r));')
self.write()
self.write()
self.write('#endif // ' + include_guard)
def gen_source(self):
......
......@@ -49,11 +49,17 @@ struct ReadBuffer {
};
template <typename T>
void Write(const T* t, WriteBuffer* buf) {
static_assert(std::is_trivially_copyable<T>::value, "");
void VerifyAlignment(T* t, size_t offset) {
// On the wire, X11 types are always aligned to their size. This is a sanity
// check to ensure padding etc are working properly.
DCHECK_EQ(buf->size() % sizeof(*t), 0UL);
if (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8)
DCHECK_EQ(offset % sizeof(*t), 0UL);
}
template <typename T>
void Write(const T* t, WriteBuffer* buf) {
static_assert(std::is_trivially_copyable<T>::value, "");
VerifyAlignment(t, buf->size());
const uint8_t* start = reinterpret_cast<const uint8_t*>(t);
std::copy(start, start + sizeof(*t), std::back_inserter(*buf));
}
......@@ -61,9 +67,7 @@ void Write(const T* t, WriteBuffer* buf) {
template <typename T>
void Read(T* t, ReadBuffer* buf) {
static_assert(std::is_trivially_copyable<T>::value, "");
// On the wire, X11 types are always aligned to their size. This is a sanity
// check to ensure padding etc are working properly.
DCHECK_EQ(buf->offset % sizeof(*t), 0UL);
VerifyAlignment(t, buf->offset);
memcpy(t, buf->data + buf->offset, sizeof(*t));
buf->offset += sizeof(*t);
}
......
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