Commit 6eb1c0f0 authored by Tom Anderson's avatar Tom Anderson Committed by Commit Bot

[XProto] Remove Xlib usage in clipboard code

R=adunaev
CC=sky,msisov,nickdiego

Change-Id: I5fc6f0fd97e646044b7d3d0894f6bf5e2b4e2e37
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2253223
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#781980}
parent 7955598d
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/clipboard_monitor.h" #include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/custom_data_helper.h" #include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/nine_image_painter_factory.h"
#include "ui/base/x/selection_owner.h" #include "ui/base/x/selection_owner.h"
#include "ui/base/x/selection_requestor.h" #include "ui/base/x/selection_requestor.h"
#include "ui/base/x/selection_utils.h" #include "ui/base/x/selection_utils.h"
...@@ -36,6 +37,8 @@ ...@@ -36,6 +37,8 @@
#include "ui/gfx/x/event.h" #include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xproto.h"
namespace ui { namespace ui {
...@@ -66,63 +69,54 @@ class SelectionChangeObserver : public XEventObserver { ...@@ -66,63 +69,54 @@ class SelectionChangeObserver : public XEventObserver {
void WillProcessXEvent(x11::Event* xev) override; void WillProcessXEvent(x11::Event* xev) override;
void DidProcessXEvent(x11::Event* xev) override {} void DidProcessXEvent(x11::Event* xev) override {}
int event_base_; x11::Atom clipboard_atom_{};
x11::Atom clipboard_atom_; uint64_t clipboard_sequence_number_{};
uint64_t clipboard_sequence_number_; uint64_t primary_sequence_number_{};
uint64_t primary_sequence_number_;
DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver); DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver);
}; };
SelectionChangeObserver::SelectionChangeObserver() SelectionChangeObserver::SelectionChangeObserver() {
: event_base_(-1), auto& xfixes = x11::Connection::Get()->xfixes();
clipboard_atom_(x11::Atom::None), // Let the server know the client version. No need to sync since we don't
clipboard_sequence_number_(0), // care what version is running on the server.
primary_sequence_number_(0) { xfixes.QueryVersion({x11::XFixes::major_version, x11::XFixes::minor_version});
int ignored; if (!xfixes.present())
if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_, &ignored)) { return;
clipboard_atom_ = gfx::GetAtom(kClipboard);
XFixesSelectSelectionInput(gfx::GetXDisplay(),
static_cast<uint32_t>(GetX11RootWindow()),
static_cast<uint32_t>(clipboard_atom_),
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
// This seems to be semi-optional. For some reason, registering for any
// selection notify events seems to subscribe us to events for both the
// primary and the clipboard buffers. Register anyway just to be safe.
XFixesSelectSelectionInput(gfx::GetXDisplay(),
static_cast<uint32_t>(GetX11RootWindow()),
XA_PRIMARY,
XFixesSetSelectionOwnerNotifyMask |
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask);
X11EventSource::GetInstance()->AddXEventObserver(this);
}
}
SelectionChangeObserver::~SelectionChangeObserver() { clipboard_atom_ = gfx::GetAtom(kClipboard);
// We are a singleton; we will outlive the event source. auto mask = x11::XFixes::SelectionEventMask::SetSelectionOwner |
x11::XFixes::SelectionEventMask::SelectionWindowDestroy |
x11::XFixes::SelectionEventMask::SelectionClientClose;
xfixes.SelectSelectionInput({GetX11RootWindow(), clipboard_atom_, mask});
// This seems to be semi-optional. For some reason, registering for any
// selection notify events seems to subscribe us to events for both the
// primary and the clipboard buffers. Register anyway just to be safe.
xfixes.SelectSelectionInput({GetX11RootWindow(), x11::Atom::PRIMARY, mask});
X11EventSource::GetInstance()->AddXEventObserver(this);
} }
// We are a singleton; we will outlive the event source.
SelectionChangeObserver::~SelectionChangeObserver() = default;
SelectionChangeObserver* SelectionChangeObserver::GetInstance() { SelectionChangeObserver* SelectionChangeObserver::GetInstance() {
return base::Singleton<SelectionChangeObserver>::get(); return base::Singleton<SelectionChangeObserver>::get();
} }
void SelectionChangeObserver::WillProcessXEvent(x11::Event* x11_event) { void SelectionChangeObserver::WillProcessXEvent(x11::Event* xev) {
XEvent* xev = &x11_event->xlib_event(); auto* ev = xev->As<x11::XFixes::SelectionNotifyEvent>();
if (xev->type == event_base_ + XFixesSelectionNotify) { if (!ev)
XFixesSelectionNotifyEvent* ev = return;
reinterpret_cast<XFixesSelectionNotifyEvent*>(xev);
if (static_cast<x11::Atom>(ev->selection) == clipboard_atom_) { if (static_cast<x11::Atom>(ev->selection) == clipboard_atom_) {
clipboard_sequence_number_++; clipboard_sequence_number_++;
ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged(); ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
} else if (ev->selection == XA_PRIMARY) { } else if (ev->selection == x11::Atom::PRIMARY) {
primary_sequence_number_++; primary_sequence_number_++;
} else { } else {
DLOG(ERROR) << "Unexpected selection atom: " << ev->selection; DLOG(ERROR) << "Unexpected selection atom: "
} << static_cast<uint32_t>(ev->selection);
} }
} }
...@@ -243,10 +237,8 @@ class ClipboardX11::X11Details : public XEventDispatcher { ...@@ -243,10 +237,8 @@ class ClipboardX11::X11Details : public XEventDispatcher {
// XEventDispatcher: // XEventDispatcher:
bool DispatchXEvent(x11::Event* xev) override; bool DispatchXEvent(x11::Event* xev) override;
bool CanDispatchXEvent(x11::Event* xev);
// Our X11 state. // Our X11 state.
Display* x_display_; x11::Connection* connection_;
x11::Window x_root_window_; x11::Window x_root_window_;
// Input-only window used as a selection owner. // Input-only window used as a selection owner.
...@@ -269,26 +261,14 @@ class ClipboardX11::X11Details : public XEventDispatcher { ...@@ -269,26 +261,14 @@ class ClipboardX11::X11Details : public XEventDispatcher {
}; };
ClipboardX11::X11Details::X11Details() ClipboardX11::X11Details::X11Details()
: x_display_(gfx::GetXDisplay()), : connection_(x11::Connection::Get()),
x_root_window_(ui::GetX11RootWindow()), x_root_window_(ui::GetX11RootWindow()),
x_window_(static_cast<x11::Window>(XCreateWindow( x_window_(CreateDummyWindow("Chromium Clipboard Window")),
x_display_, selection_requestor_(x_window_, this),
static_cast<uint32_t>(x_root_window_), clipboard_owner_(connection_, x_window_, gfx::GetAtom(kClipboard)),
-100, primary_owner_(connection_, x_window_, x11::Atom::PRIMARY) {
-100, SetStringProperty(x_window_, x11::Atom::WM_NAME, x11::Atom::STRING,
10, "Chromium clipboard");
10, // x, y, width, height
0, // border width
static_cast<int>(x11::WindowClass::CopyFromParent), // depth
static_cast<int>(x11::WindowClass::InputOnly),
nullptr, // visual
0,
nullptr))),
selection_requestor_(x_display_, x_window_, this),
clipboard_owner_(x_display_, x_window_, gfx::GetAtom(kClipboard)),
primary_owner_(x_display_, x_window_, x11::Atom::PRIMARY) {
XStoreName(x_display_, static_cast<uint32_t>(x_window_),
"Chromium clipboard");
x_window_events_ = x_window_events_ =
std::make_unique<XScopedEventSelector>(x_window_, PropertyChangeMask); std::make_unique<XScopedEventSelector>(x_window_, PropertyChangeMask);
...@@ -300,7 +280,7 @@ ClipboardX11::X11Details::~X11Details() { ...@@ -300,7 +280,7 @@ ClipboardX11::X11Details::~X11Details() {
if (X11EventSource::GetInstance()) if (X11EventSource::GetInstance())
X11EventSource::GetInstance()->RemoveXEventDispatcher(this); X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
XDestroyWindow(x_display_, static_cast<uint32_t>(x_window_)); connection_->DestroyWindow({x_window_});
} }
x11::Atom ClipboardX11::X11Details::LookupSelectionForClipboardBuffer( x11::Atom ClipboardX11::X11Details::LookupSelectionForClipboardBuffer(
...@@ -452,64 +432,42 @@ void ClipboardX11::X11Details::StoreCopyPasteDataAndWait() { ...@@ -452,64 +432,42 @@ void ClipboardX11::X11Details::StoreCopyPasteDataAndWait() {
base::TimeTicks::Now() - start); base::TimeTicks::Now() - start);
} }
bool ClipboardX11::X11Details::CanDispatchXEvent(x11::Event* x11_event) { bool ClipboardX11::X11Details::DispatchXEvent(x11::Event* xev) {
XEvent* xev = &x11_event->xlib_event(); if (auto* request = xev->As<x11::SelectionRequestEvent>()) {
if (xev->xany.window == static_cast<uint32_t>(x_window_)) if (request->owner != x_window_)
return true; return false;
if (request->selection == x11::Atom::PRIMARY) {
if (xev->type == PropertyNotify) { primary_owner_.OnSelectionRequest(*xev);
return primary_owner_.CanDispatchPropertyEvent(*x11_event) || } else {
clipboard_owner_.CanDispatchPropertyEvent(*x11_event) || // We should not get requests for the CLIPBOARD_MANAGER selection
selection_requestor_.CanDispatchPropertyEvent(*x11_event); // because we never take ownership of it.
} DCHECK_EQ(GetCopyPasteSelection(), request->selection);
return false; clipboard_owner_.OnSelectionRequest(*xev);
}
bool ClipboardX11::X11Details::DispatchXEvent(x11::Event* x11_event) {
XEvent* xev = &x11_event->xlib_event();
if (!CanDispatchXEvent(x11_event))
return false;
switch (xev->type) {
case x11::SelectionRequestEvent::opcode: {
if (xev->xselectionrequest.selection == XA_PRIMARY) {
primary_owner_.OnSelectionRequest(*x11_event);
} else {
// We should not get requests for the CLIPBOARD_MANAGER selection
// because we never take ownership of it.
DCHECK_EQ(GetCopyPasteSelection(),
static_cast<x11::Atom>(xev->xselectionrequest.selection));
clipboard_owner_.OnSelectionRequest(*x11_event);
}
break;
}
case x11::SelectionNotifyEvent::opcode: {
selection_requestor_.OnSelectionNotify(*x11_event);
break;
}
case x11::SelectionClearEvent::opcode: {
if (xev->xselectionclear.selection == XA_PRIMARY) {
primary_owner_.OnSelectionClear(*x11_event);
} else {
// We should not get requests for the CLIPBOARD_MANAGER selection
// because we never take ownership of it.
DCHECK_EQ(GetCopyPasteSelection(),
static_cast<x11::Atom>(xev->xselection.selection));
clipboard_owner_.OnSelectionClear(*x11_event);
}
break;
} }
case x11::PropertyNotifyEvent::opcode: { } else if (auto* notify = xev->As<x11::SelectionNotifyEvent>()) {
if (primary_owner_.CanDispatchPropertyEvent(*x11_event)) if (notify->requestor != x_window_)
primary_owner_.OnPropertyEvent(*x11_event); return false;
if (clipboard_owner_.CanDispatchPropertyEvent(*x11_event)) selection_requestor_.OnSelectionNotify(*notify);
clipboard_owner_.OnPropertyEvent(*x11_event); } else if (auto* clear = xev->As<x11::SelectionClearEvent>()) {
if (selection_requestor_.CanDispatchPropertyEvent(*x11_event)) if (clear->owner != x_window_)
selection_requestor_.OnPropertyEvent(*x11_event); return false;
break; if (clear->selection == x11::Atom::PRIMARY) {
primary_owner_.OnSelectionClear(*xev);
} else {
// We should not get requests for the CLIPBOARD_MANAGER selection
// because we never take ownership of it.
DCHECK_EQ(GetCopyPasteSelection(), clear->selection);
clipboard_owner_.OnSelectionClear(*xev);
} }
default: } else if (auto* prop = xev->As<x11::PropertyNotifyEvent>()) {
break; if (prop->window != x_window_)
return false;
if (primary_owner_.CanDispatchPropertyEvent(*xev))
primary_owner_.OnPropertyEvent(*xev);
if (clipboard_owner_.CanDispatchPropertyEvent(*xev))
clipboard_owner_.OnPropertyEvent(*xev);
if (selection_requestor_.CanDispatchPropertyEvent(*xev))
selection_requestor_.OnPropertyEvent(*xev);
} }
return false; return false;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "ui/events/x/x11_window_event_manager.h" #include "ui/events/x/x11_window_event_manager.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
namespace ui { namespace ui {
...@@ -40,10 +41,12 @@ static_assert(KSelectionOwnerTimerPeriodMs <= kIncrementalTransferTimeoutMs, ...@@ -40,10 +41,12 @@ static_assert(KSelectionOwnerTimerPeriodMs <= kIncrementalTransferTimeoutMs,
// Returns a conservative max size of the data we can pass into // Returns a conservative max size of the data we can pass into
// XChangeProperty(). Copied from GTK. // XChangeProperty(). Copied from GTK.
size_t GetMaxRequestSize(XDisplay* display) { size_t GetMaxRequestSize(x11::Connection* connection) {
long extended_max_size = XExtendedMaxRequestSize(display); long extended_max_size = connection->extended_max_request_length();
long max_size = long max_size =
(extended_max_size ? extended_max_size : XMaxRequestSize(display)) - 100; (extended_max_size ? extended_max_size
: connection->setup().maximum_request_length) -
100;
return std::min(static_cast<long>(0x40000), return std::min(static_cast<long>(0x40000),
std::max(static_cast<long>(0), max_size)); std::max(static_cast<long>(0), max_size));
} }
...@@ -79,13 +82,12 @@ void SetSelectionOwner(x11::Window window, ...@@ -79,13 +82,12 @@ void SetSelectionOwner(x11::Window window,
} // namespace } // namespace
SelectionOwner::SelectionOwner(XDisplay* x_display, SelectionOwner::SelectionOwner(x11::Connection* connection,
x11::Window x_window, x11::Window x_window,
x11::Atom selection_name) x11::Atom selection_name)
: x_display_(x_display), : x_window_(x_window),
x_window_(x_window),
selection_name_(selection_name), selection_name_(selection_name),
max_request_size_(GetMaxRequestSize(x_display)) {} max_request_size_(GetMaxRequestSize(connection)) {}
SelectionOwner::~SelectionOwner() { SelectionOwner::~SelectionOwner() {
// If we are the selection owner, we need to release the selection so we // If we are the selection owner, we need to release the selection so we
...@@ -117,22 +119,20 @@ void SelectionOwner::ClearSelectionOwner() { ...@@ -117,22 +119,20 @@ void SelectionOwner::ClearSelectionOwner() {
} }
void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) { void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) {
const XEvent& event = x11_event.xlib_event(); auto& request = *x11_event.As<x11::SelectionRequestEvent>();
auto requestor = static_cast<x11::Window>(event.xselectionrequest.requestor); auto requestor = request.requestor;
x11::Atom requested_target = x11::Atom requested_target = request.target;
static_cast<x11::Atom>(event.xselectionrequest.target); x11::Atom requested_property = request.property;
x11::Atom requested_property =
static_cast<x11::Atom>(event.xselectionrequest.property);
// Incrementally build our selection. By default this is a refusal, and we'll // Incrementally build our selection. By default this is a refusal, and we'll
// override the parts indicating success in the different cases. // override the parts indicating success in the different cases.
XEvent reply; x11::SelectionNotifyEvent reply{
reply.xselection.type = SelectionNotify; .time = request.time,
reply.xselection.requestor = static_cast<uint32_t>(requestor); .requestor = requestor,
reply.xselection.selection = event.xselectionrequest.selection; .selection = request.selection,
reply.xselection.target = static_cast<uint32_t>(requested_target); .target = requested_target,
reply.xselection.property = x11::None; // Indicates failure .property = x11::Atom::None, // Indicates failure
reply.xselection.time = event.xselectionrequest.time; };
if (requested_target == gfx::GetAtom(kMultiple)) { if (requested_target == gfx::GetAtom(kMultiple)) {
// The contents of |requested_property| should be a list of // The contents of |requested_property| should be a list of
...@@ -153,16 +153,15 @@ void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) { ...@@ -153,16 +153,15 @@ void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) {
ui::SetArrayProperty(requestor, requested_property, ui::SetArrayProperty(requestor, requested_property,
gfx::GetAtom(kAtomPair), conversion_results); gfx::GetAtom(kAtomPair), conversion_results);
reply.xselection.property = static_cast<uint32_t>(requested_property); reply.property = requested_property;
} }
} else { } else {
if (ProcessTarget(requested_target, requestor, requested_property)) if (ProcessTarget(requested_target, requestor, requested_property))
reply.xselection.property = static_cast<uint32_t>(requested_property); reply.property = requested_property;
} }
// Send off the reply. // Send off the reply.
XSendEvent(x_display_, static_cast<uint32_t>(requestor), x11::False, 0, ui::SendEvent(reply, requestor, x11::EventMask::NoEvent);
&reply);
} }
void SelectionOwner::OnSelectionClear(const x11::Event& event) { void SelectionOwner::OnSelectionClear(const x11::Event& event) {
...@@ -173,7 +172,7 @@ void SelectionOwner::OnSelectionClear(const x11::Event& event) { ...@@ -173,7 +172,7 @@ void SelectionOwner::OnSelectionClear(const x11::Event& event) {
} }
bool SelectionOwner::CanDispatchPropertyEvent(const x11::Event& event) { bool SelectionOwner::CanDispatchPropertyEvent(const x11::Event& event) {
return event.xlib_event().xproperty.state == PropertyDelete && return event.As<x11::PropertyNotifyEvent>()->state == x11::Property::Delete &&
FindIncrementalTransferForEvent(event) != incremental_transfers_.end(); FindIncrementalTransferForEvent(event) != incremental_transfers_.end();
} }
...@@ -296,14 +295,12 @@ void SelectionOwner::CompleteIncrementalTransfer( ...@@ -296,14 +295,12 @@ void SelectionOwner::CompleteIncrementalTransfer(
} }
std::vector<SelectionOwner::IncrementalTransfer>::iterator std::vector<SelectionOwner::IncrementalTransfer>::iterator
SelectionOwner::FindIncrementalTransferForEvent(const x11::Event& x11_event) { SelectionOwner::FindIncrementalTransferForEvent(const x11::Event& event) {
const XEvent& event = x11_event.xlib_event();
for (auto it = incremental_transfers_.begin(); for (auto it = incremental_transfers_.begin();
it != incremental_transfers_.end(); ++it) { it != incremental_transfers_.end(); ++it) {
if (it->window == static_cast<x11::Window>(event.xproperty.window) && const auto* prop = event.As<x11::PropertyNotifyEvent>();
it->property == static_cast<x11::Atom>(event.xproperty.atom)) { if (it->window == prop->window && it->property == prop->atom)
return it; return it;
}
} }
return incremental_transfers_.end(); return incremental_transfers_.end();
} }
......
...@@ -34,7 +34,7 @@ COMPONENT_EXPORT(UI_BASE_X) extern const char kTargets[]; ...@@ -34,7 +34,7 @@ COMPONENT_EXPORT(UI_BASE_X) extern const char kTargets[];
// processes. // processes.
class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner { class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner {
public: public:
SelectionOwner(XDisplay* xdisplay, SelectionOwner(x11::Connection* connection,
x11::Window xwindow, x11::Window xwindow,
x11::Atom selection_name); x11::Atom selection_name);
~SelectionOwner(); ~SelectionOwner();
...@@ -126,7 +126,6 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner { ...@@ -126,7 +126,6 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner {
const x11::Event& event); const x11::Event& event);
// Our X11 state. // Our X11 state.
XDisplay* x_display_;
x11::Window x_window_; x11::Window x_window_;
// The X11 selection that this instance communicates on. // The X11 selection that this instance communicates on.
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "ui/events/platform/x11/x11_event_source.h" #include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xproto.h"
namespace ui { namespace ui {
...@@ -50,11 +51,9 @@ std::vector<uint8_t> CombineData( ...@@ -50,11 +51,9 @@ std::vector<uint8_t> CombineData(
} // namespace } // namespace
SelectionRequestor::SelectionRequestor(XDisplay* x_display, SelectionRequestor::SelectionRequestor(x11::Window x_window,
x11::Window x_window,
XEventDispatcher* dispatcher) XEventDispatcher* dispatcher)
: x_display_(x_display), : x_window_(x_window),
x_window_(x_window),
x_property_(x11::Atom::None), x_property_(x11::Atom::None),
dispatcher_(dispatcher), dispatcher_(dispatcher),
current_request_index_(0u) { current_request_index_(0u) {
...@@ -120,14 +119,13 @@ SelectionData SelectionRequestor::RequestAndWaitForTypes( ...@@ -120,14 +119,13 @@ SelectionData SelectionRequestor::RequestAndWaitForTypes(
return SelectionData(); return SelectionData();
} }
void SelectionRequestor::OnSelectionNotify(const x11::Event& x11_event) { void SelectionRequestor::OnSelectionNotify(
const XEvent& event = x11_event.xlib_event(); const x11::SelectionNotifyEvent& selection) {
Request* request = GetCurrentRequest(); Request* request = GetCurrentRequest();
x11::Atom event_property = static_cast<x11::Atom>(event.xselection.property); x11::Atom event_property = selection.property;
if (!request || request->completed || if (!request || request->completed ||
request->selection != request->selection != selection.selection ||
static_cast<x11::Atom>(event.xselection.selection) || request->target != selection.target) {
request->target != static_cast<x11::Atom>(event.xselection.target)) {
// ICCCM requires us to delete the property passed into SelectionNotify. // ICCCM requires us to delete the property passed into SelectionNotify.
if (event_property != x11::Atom::None) if (event_property != x11::Atom::None)
ui::DeleteProperty(x_window_, event_property); ui::DeleteProperty(x_window_, event_property);
...@@ -158,11 +156,10 @@ void SelectionRequestor::OnSelectionNotify(const x11::Event& x11_event) { ...@@ -158,11 +156,10 @@ void SelectionRequestor::OnSelectionNotify(const x11::Event& x11_event) {
} }
} }
bool SelectionRequestor::CanDispatchPropertyEvent(const x11::Event& x11_event) { bool SelectionRequestor::CanDispatchPropertyEvent(const x11::Event& event) {
const XEvent& event = x11_event.xlib_event(); const auto* prop = event.As<x11::PropertyNotifyEvent>();
return event.xproperty.window == static_cast<uint32_t>(x_window_) && return prop->window == x_window_ && prop->atom == x_property_ &&
static_cast<x11::Atom>(event.xproperty.atom) == x_property_ && prop->state == x11::Property::NewValue;
event.xproperty.state == PropertyNewValue;
} }
void SelectionRequestor::OnPropertyEvent(const x11::Event& event) { void SelectionRequestor::OnPropertyEvent(const x11::Event& event) {
......
...@@ -33,9 +33,7 @@ class SelectionData; ...@@ -33,9 +33,7 @@ class SelectionData;
// implement per-component fast-paths. // implement per-component fast-paths.
class COMPONENT_EXPORT(UI_BASE) SelectionRequestor { class COMPONENT_EXPORT(UI_BASE) SelectionRequestor {
public: public:
SelectionRequestor(XDisplay* xdisplay, SelectionRequestor(x11::Window xwindow, XEventDispatcher* dispatcher);
x11::Window xwindow,
XEventDispatcher* dispatcher);
~SelectionRequestor(); ~SelectionRequestor();
// Does the work of requesting |target| from |selection|, spinning up the // Does the work of requesting |target| from |selection|, spinning up the
...@@ -61,7 +59,7 @@ class COMPONENT_EXPORT(UI_BASE) SelectionRequestor { ...@@ -61,7 +59,7 @@ class COMPONENT_EXPORT(UI_BASE) SelectionRequestor {
// It is our owner's responsibility to plumb X11 SelectionNotify events on // It is our owner's responsibility to plumb X11 SelectionNotify events on
// |xwindow_| to us. // |xwindow_| to us.
void OnSelectionNotify(const x11::Event& event); void OnSelectionNotify(const x11::SelectionNotifyEvent& event);
// Returns true if SelectionOwner can process the XChangeProperty event, // Returns true if SelectionOwner can process the XChangeProperty event,
// |event|. // |event|.
...@@ -121,7 +119,6 @@ class COMPONENT_EXPORT(UI_BASE) SelectionRequestor { ...@@ -121,7 +119,6 @@ class COMPONENT_EXPORT(UI_BASE) SelectionRequestor {
Request* GetCurrentRequest(); Request* GetCurrentRequest();
// Our X11 state. // Our X11 state.
XDisplay* x_display_;
x11::Window x_window_; x11::Window x_window_;
// The property on |x_window_| set by the selection owner with the value of // The property on |x_window_| set by the selection owner with the value of
......
...@@ -55,7 +55,8 @@ class SelectionRequestorTest : public testing::Test { ...@@ -55,7 +55,8 @@ class SelectionRequestorTest : public testing::Test {
event->property = static_cast<uint32_t>(requestor_->x_property_); event->property = static_cast<uint32_t>(requestor_->x_property_);
event->time = x11::CurrentTime; event->time = x11::CurrentTime;
requestor_->OnSelectionNotify(x11::Event(&ge, x11::Connection::Get())); x11::Event xev(&ge, x11::Connection::Get());
requestor_->OnSelectionNotify(*xev.As<x11::SelectionNotifyEvent>());
} }
protected: protected:
...@@ -75,8 +76,7 @@ class SelectionRequestorTest : public testing::Test { ...@@ -75,8 +76,7 @@ class SelectionRequestorTest : public testing::Test {
event_source_ = PlatformEventSource::CreateDefault(); event_source_ = PlatformEventSource::CreateDefault();
CHECK(PlatformEventSource::GetInstance()); CHECK(PlatformEventSource::GetInstance());
requestor_ = requestor_ = std::make_unique<SelectionRequestor>(x_window_, nullptr);
std::make_unique<SelectionRequestor>(x_display_, x_window_, nullptr);
} }
void TearDown() override { void TearDown() override {
......
...@@ -37,38 +37,23 @@ const char kNetscapeURL[] = "_NETSCAPE_URL"; ...@@ -37,38 +37,23 @@ const char kNetscapeURL[] = "_NETSCAPE_URL";
XOSExchangeDataProvider::XOSExchangeDataProvider( XOSExchangeDataProvider::XOSExchangeDataProvider(
x11::Window x_window, x11::Window x_window,
const SelectionFormatMap& selection) const SelectionFormatMap& selection)
: x_display_(gfx::GetXDisplay()), : connection_(x11::Connection::Get()),
x_root_window_(ui::GetX11RootWindow()), x_root_window_(ui::GetX11RootWindow()),
own_window_(false), own_window_(false),
x_window_(x_window), x_window_(x_window),
format_map_(selection), format_map_(selection),
selection_owner_(x_display_, x_window_, gfx::GetAtom(kDndSelection)) {} selection_owner_(connection_, x_window_, gfx::GetAtom(kDndSelection)) {}
XOSExchangeDataProvider::XOSExchangeDataProvider() XOSExchangeDataProvider::XOSExchangeDataProvider()
: x_display_(gfx::GetXDisplay()), : connection_(x11::Connection::Get()),
x_root_window_(ui::GetX11RootWindow()), x_root_window_(ui::GetX11RootWindow()),
own_window_(true), own_window_(true),
x_window_(static_cast<x11::Window>(XCreateWindow( x_window_(CreateDummyWindow("Chromium Drag & Drop Window")),
x_display_, selection_owner_(connection_, x_window_, gfx::GetAtom(kDndSelection)) {}
static_cast<uint32_t>(x_root_window_),
-100, // x
-100, // y
10, // width
10, // height
0, // border width
static_cast<int>(x11::WindowClass::CopyFromParent), // depth
static_cast<int>(x11::WindowClass::InputOnly),
nullptr, // visual
0,
nullptr))),
selection_owner_(x_display_, x_window_, gfx::GetAtom(kDndSelection)) {
XStoreName(x_display_, static_cast<uint32_t>(x_window_),
"Chromium Drag & Drop Window");
}
XOSExchangeDataProvider::~XOSExchangeDataProvider() { XOSExchangeDataProvider::~XOSExchangeDataProvider() {
if (own_window_) if (own_window_)
XDestroyWindow(x_display_, static_cast<uint32_t>(x_window_)); connection_->DestroyWindow({x_window_});
} }
void XOSExchangeDataProvider::TakeOwnershipOfSelection() const { void XOSExchangeDataProvider::TakeOwnershipOfSelection() const {
......
...@@ -125,7 +125,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XOSExchangeDataProvider ...@@ -125,7 +125,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XOSExchangeDataProvider
gfx::Vector2d drag_image_offset_; gfx::Vector2d drag_image_offset_;
// Our X11 state. // Our X11 state.
Display* x_display_; x11::Connection* connection_;
x11::Window x_root_window_; x11::Window x_root_window_;
// In X11, because the IPC parts of drag operations are implemented by // In X11, because the IPC parts of drag operations are implemented by
......
...@@ -455,6 +455,24 @@ void DefineCursor(x11::Window window, x11::Cursor cursor) { ...@@ -455,6 +455,24 @@ void DefineCursor(x11::Window window, x11::Cursor cursor) {
.Sync(); .Sync();
} }
x11::Window CreateDummyWindow(const std::string& name) {
auto* connection = x11::Connection::Get();
auto window = connection->GenerateId<x11::Window>();
connection->CreateWindow({
.wid = window,
.parent = connection->default_root(),
.x = -100,
.y = -100,
.width = 10,
.height = 10,
.c_class = x11::WindowClass::InputOnly,
.override_redirect = x11::Bool32(true),
});
if (!name.empty())
SetStringProperty(window, x11::Atom::WM_NAME, x11::Atom::STRING, name);
return window;
}
bool IsXInput2Available() { bool IsXInput2Available() {
return DeviceDataManagerX11::GetInstance()->IsXInput2Available(); return DeviceDataManagerX11::GetInstance()->IsXInput2Available();
} }
......
...@@ -184,6 +184,18 @@ void SetProperty(x11::Window window, ...@@ -184,6 +184,18 @@ void SetProperty(x11::Window window,
SetArrayProperty(window, name, type, std::vector<T>{value}); SetArrayProperty(window, name, type, std::vector<T>{value});
} }
template <typename T>
void SendEvent(const T& event, x11::Window target, x11::EventMask mask) {
static_assert(T::type_id > 0, "T must be an x11::*Event type");
auto event_bytes = x11::Write(event);
DCHECK_LE(event_bytes.size(), 32ul);
event_bytes.resize(32);
x11::SendEventRequest send_event{false, target, mask};
std::copy(event_bytes.begin(), event_bytes.end(), send_event.event.begin());
x11::Connection::Get()->SendEvent(send_event);
}
COMPONENT_EXPORT(UI_BASE_X) COMPONENT_EXPORT(UI_BASE_X)
void DeleteProperty(x11::Window window, x11::Atom name); void DeleteProperty(x11::Window window, x11::Atom name);
...@@ -211,6 +223,9 @@ void LowerWindow(x11::Window window); ...@@ -211,6 +223,9 @@ void LowerWindow(x11::Window window);
COMPONENT_EXPORT(UI_BASE_X) COMPONENT_EXPORT(UI_BASE_X)
void DefineCursor(x11::Window window, x11::Cursor cursor); void DefineCursor(x11::Window window, x11::Cursor cursor);
COMPONENT_EXPORT(UI_BASE_X)
x11::Window CreateDummyWindow(const std::string& name = "");
// These functions cache their results --------------------------------- // These functions cache their results ---------------------------------
// Returns true if the system supports XINPUT2. // Returns true if the system supports XINPUT2.
......
...@@ -233,6 +233,7 @@ READ_SPECIAL = set([ ...@@ -233,6 +233,7 @@ READ_SPECIAL = set([
WRITE_SPECIAL = set([ WRITE_SPECIAL = set([
('xcb', 'ClientMessage'), ('xcb', 'ClientMessage'),
('xcb', 'UnmapNotify'), ('xcb', 'UnmapNotify'),
('xcb', 'SelectionNotify'),
]) ])
......
...@@ -12,8 +12,10 @@ ...@@ -12,8 +12,10 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/x/x11_util.h" #include "ui/base/x/x11_util.h"
#include "ui/gfx/x/extension_manager.h"
#include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xproto.h"
using base::Contains; using base::Contains;
...@@ -44,14 +46,6 @@ void ExpandTypes(std::vector<std::string>* list) { ...@@ -44,14 +46,6 @@ void ExpandTypes(std::vector<std::string>* list) {
list->push_back(kMimeTypeTextUtf8); list->push_back(kMimeTypeTextUtf8);
} }
x11::Window FindXEventTarget(const x11::Event& x11_event) {
const XEvent& xev = x11_event.xlib_event();
XID target = xev.xany.window;
if (xev.type == x11::GeGenericEvent::opcode)
target = static_cast<XIDeviceEvent*>(xev.xcookie.data)->event;
return static_cast<x11::Window>(target);
}
} // namespace } // namespace
// Maintains state of a single selection (aka system clipboard buffer). // Maintains state of a single selection (aka system clipboard buffer).
...@@ -82,7 +76,7 @@ struct X11ClipboardOzone::SelectionState { ...@@ -82,7 +76,7 @@ struct X11ClipboardOzone::SelectionState {
PlatformClipboard::RequestDataClosure request_clipboard_data_callback; PlatformClipboard::RequestDataClosure request_clipboard_data_callback;
// The time that this instance took ownership of the clipboard. // The time that this instance took ownership of the clipboard.
Time acquired_selection_timestamp; x11::Time acquired_selection_timestamp;
}; };
X11ClipboardOzone::X11ClipboardOzone() X11ClipboardOzone::X11ClipboardOzone()
...@@ -90,22 +84,10 @@ X11ClipboardOzone::X11ClipboardOzone() ...@@ -90,22 +84,10 @@ X11ClipboardOzone::X11ClipboardOzone()
atom_targets_(gfx::GetAtom(kTargets)), atom_targets_(gfx::GetAtom(kTargets)),
atom_timestamp_(gfx::GetAtom(kTimestamp)), atom_timestamp_(gfx::GetAtom(kTimestamp)),
x_property_(gfx::GetAtom(kChromeSelection)), x_property_(gfx::GetAtom(kChromeSelection)),
x_display_(gfx::GetXDisplay()), connection_(x11::Connection::Get()),
x_window_(static_cast<x11::Window>( x_window_(CreateDummyWindow("Chromium Clipboard Window")) {
XCreateSimpleWindow(x_display_, if (!connection_->xfixes().present())
DefaultRootWindow(x_display_),
/*x=*/-100,
/*y=*/-100,
/*width=*/10,
/*height=*/10,
/*border_width=*/0,
/*border=*/0,
/*background=*/0))) {
int ignored; // xfixes_error_base.
if (!XFixesQueryExtension(x_display_, &xfixes_event_base_, &ignored)) {
LOG(ERROR) << "X server does not support XFixes.";
return; return;
}
using_xfixes_ = true; using_xfixes_ = true;
// Register to receive standard X11 events. // Register to receive standard X11 events.
...@@ -115,9 +97,8 @@ X11ClipboardOzone::X11ClipboardOzone() ...@@ -115,9 +97,8 @@ X11ClipboardOzone::X11ClipboardOzone()
// Register the selection state. // Register the selection state.
selection_state_.emplace(atom, std::make_unique<SelectionState>()); selection_state_.emplace(atom, std::make_unique<SelectionState>());
// Register to receive XFixes notification when selection owner changes. // Register to receive XFixes notification when selection owner changes.
XFixesSelectSelectionInput(x_display_, static_cast<uint32_t>(x_window_), connection_->xfixes().SelectSelectionInput(
static_cast<uint32_t>(atom), {x_window_, atom, x11::XFixes::SelectionEventMask::SetSelectionOwner});
XFixesSetSelectionOwnerNotifyMask);
// Prefetch the current remote clipboard contents. // Prefetch the current remote clipboard contents.
QueryTargets(atom); QueryTargets(atom);
} }
...@@ -127,22 +108,13 @@ X11ClipboardOzone::~X11ClipboardOzone() { ...@@ -127,22 +108,13 @@ X11ClipboardOzone::~X11ClipboardOzone() {
X11EventSource::GetInstance()->RemoveXEventDispatcher(this); X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
} }
bool X11ClipboardOzone::DispatchXEvent(x11::Event* x11_event) { bool X11ClipboardOzone::DispatchXEvent(x11::Event* xev) {
XEvent* xev = &x11_event->xlib_event(); if (auto* request = xev->As<x11::SelectionRequestEvent>())
if (FindXEventTarget(*x11_event) != x_window_) return request->owner == x_window_ && OnSelectionRequest(*request);
return false; if (auto* notify = xev->As<x11::SelectionNotifyEvent>())
return notify->requestor == x_window_ && OnSelectionNotify(*notify);
switch (xev->type) { if (auto* notify = xev->As<x11::XFixes::SelectionNotifyEvent>())
case x11::SelectionRequestEvent::opcode: return notify->owner == x_window_ && OnSetSelectionOwnerNotify(*notify);
return OnSelectionRequest(xev->xselectionrequest);
case x11::SelectionNotifyEvent::opcode:
return OnSelectionNotify(xev->xselection);
}
if (using_xfixes_ &&
xev->type == xfixes_event_base_ + XFixesSetSelectionOwnerNotify) {
return OnSetSelectionOwnerNotify(x11_event);
}
return false; return false;
} }
...@@ -152,9 +124,9 @@ bool X11ClipboardOzone::DispatchXEvent(x11::Event* x11_event) { ...@@ -152,9 +124,9 @@ bool X11ClipboardOzone::DispatchXEvent(x11::Event* x11_event) {
// TIMESTAMP: Time when we took ownership of the clipboard. // TIMESTAMP: Time when we took ownership of the clipboard.
// <mime-type>: Mime type to receive clipboard as. // <mime-type>: Mime type to receive clipboard as.
bool X11ClipboardOzone::OnSelectionRequest( bool X11ClipboardOzone::OnSelectionRequest(
const XSelectionRequestEvent& event) { const x11::SelectionRequestEvent& event) {
// The property must be set. // The property must be set.
if (event.property == x11::None) if (event.property == x11::Atom::None)
return false; return false;
// target=TARGETS. // target=TARGETS.
...@@ -172,25 +144,20 @@ bool X11ClipboardOzone::OnSelectionRequest( ...@@ -172,25 +144,20 @@ bool X11ClipboardOzone::OnSelectionRequest(
// Expand types, then convert from string to atom. // Expand types, then convert from string to atom.
ExpandTypes(&targets); ExpandTypes(&targets);
std::vector<x11::Atom> atoms; std::vector<x11::Atom> atoms;
for (auto& entry : targets) { for (auto& entry : targets)
atoms.push_back(gfx::GetAtom(entry.c_str())); atoms.push_back(gfx::GetAtom(entry.c_str()));
} ui::SetArrayProperty(event.requestor, event.property, x11::Atom::ATOM,
XChangeProperty(x_display_, event.requestor, event.property, XA_ATOM, atoms);
/*format=*/32, PropModeReplace,
reinterpret_cast<unsigned char*>(atoms.data()),
atoms.size());
} else if (target == atom_timestamp_) { } else if (target == atom_timestamp_) {
// target=TIMESTAMP. // target=TIMESTAMP.
XChangeProperty(x_display_, event.requestor, event.property, XA_INTEGER, ui::SetProperty(event.requestor, event.property, x11::Atom::INTEGER,
/*format=*/32, PropModeReplace, selection_state.acquired_selection_timestamp);
reinterpret_cast<unsigned char*>(
&selection_state.acquired_selection_timestamp),
1);
} else { } else {
// Send clipboard data. // Send clipboard data.
char* target_name = XGetAtomName(x_display_, event.target); std::string target_name;
if (auto reply = connection_->GetAtomName({event.target}).Sync())
target_name = std::move(reply->name);
std::string key = target_name; std::string key = target_name;
// Allow conversions for text/plain[;charset=utf-8] <=> [UTF8_]STRING. // Allow conversions for text/plain[;charset=utf-8] <=> [UTF8_]STRING.
...@@ -201,32 +168,29 @@ bool X11ClipboardOzone::OnSelectionRequest( ...@@ -201,32 +168,29 @@ bool X11ClipboardOzone::OnSelectionRequest(
} }
auto it = offer_data_map.find(key); auto it = offer_data_map.find(key);
if (it != offer_data_map.end()) { if (it != offer_data_map.end()) {
XChangeProperty(x_display_, event.requestor, event.property, event.target, ui::SetArrayProperty(event.requestor, event.property, event.target,
/*format=*/8, PropModeReplace, it->second);
const_cast<unsigned char*>(it->second.data()),
it->second.size());
} }
XFree(target_name);
} }
// Notify remote peer that clipboard has been sent. // Notify remote peer that clipboard has been sent.
XSelectionEvent selection_event; x11::SelectionNotifyEvent selection_event{
selection_event.type = SelectionNotify; .time = event.time,
selection_event.display = event.display; .requestor = event.requestor,
selection_event.requestor = event.requestor; .selection = event.selection,
selection_event.selection = event.selection; .target = event.target,
selection_event.target = event.target; .property = event.property,
selection_event.property = event.property; };
selection_event.time = event.time; SendEvent(selection_event, selection_event.requestor,
XSendEvent(x_display_, selection_event.requestor, /*propagate=*/x11::False, x11::EventMask::NoEvent);
/*event_mask=*/0, reinterpret_cast<XEvent*>(&selection_event));
return true; return true;
} }
// A remote peer owns the clipboard. This event is received in response to // A remote peer owns the clipboard. This event is received in response to
// our request for TARGETS (GetAvailableMimeTypes), or a specific mime type // our request for TARGETS (GetAvailableMimeTypes), or a specific mime type
// (RequestClipboardData). // (RequestClipboardData).
bool X11ClipboardOzone::OnSelectionNotify(const XSelectionEvent& event) { bool X11ClipboardOzone::OnSelectionNotify(
const x11::SelectionNotifyEvent& event) {
// GetAvailableMimeTypes. // GetAvailableMimeTypes.
auto selection = static_cast<x11::Atom>(event.selection); auto selection = static_cast<x11::Atom>(event.selection);
auto& selection_state = GetSelectionState(selection); auto& selection_state = GetSelectionState(selection);
...@@ -236,11 +200,8 @@ bool X11ClipboardOzone::OnSelectionNotify(const XSelectionEvent& event) { ...@@ -236,11 +200,8 @@ bool X11ClipboardOzone::OnSelectionNotify(const XSelectionEvent& event) {
selection_state.mime_types.clear(); selection_state.mime_types.clear();
for (auto target : targets) { for (auto target : targets) {
char* atom_name = XGetAtomName(x_display_, static_cast<uint32_t>(target)); if (auto reply = connection_->GetAtomName({target}).Sync())
if (atom_name) { selection_state.mime_types.push_back(std::move(reply->name));
selection_state.mime_types.push_back(atom_name);
XFree(atom_name);
}
} }
// If we have a saved callback, invoke it now with expanded types, otherwise // If we have a saved callback, invoke it now with expanded types, otherwise
...@@ -282,12 +243,10 @@ bool X11ClipboardOzone::OnSelectionNotify(const XSelectionEvent& event) { ...@@ -282,12 +243,10 @@ bool X11ClipboardOzone::OnSelectionNotify(const XSelectionEvent& event) {
return false; return false;
} }
bool X11ClipboardOzone::OnSetSelectionOwnerNotify(x11::Event* xev) { bool X11ClipboardOzone::OnSetSelectionOwnerNotify(
XFixesSelectionNotifyEvent* event = const x11::XFixes::SelectionNotifyEvent& event) {
reinterpret_cast<XFixesSelectionNotifyEvent*>(&xev->xlib_event());
// Reset state and fetch remote clipboard if there is a new remote owner. // Reset state and fetch remote clipboard if there is a new remote owner.
auto selection = static_cast<x11::Atom>(event->selection); x11::Atom selection = event.selection;
if (!IsSelectionOwner(BufferForSelectionAtom(selection))) { if (!IsSelectionOwner(BufferForSelectionAtom(selection))) {
auto& selection_state = GetSelectionState(selection); auto& selection_state = GetSelectionState(selection);
selection_state.mime_types.clear(); selection_state.mime_types.clear();
...@@ -334,10 +293,8 @@ X11ClipboardOzone::SelectionState& X11ClipboardOzone::GetSelectionState( ...@@ -334,10 +293,8 @@ X11ClipboardOzone::SelectionState& X11ClipboardOzone::GetSelectionState(
void X11ClipboardOzone::QueryTargets(x11::Atom selection) { void X11ClipboardOzone::QueryTargets(x11::Atom selection) {
GetSelectionState(selection).mime_types.clear(); GetSelectionState(selection).mime_types.clear();
XConvertSelection(x_display_, static_cast<uint32_t>(selection), connection_->ConvertSelection({x_window_, selection, atom_targets_,
static_cast<uint32_t>(atom_targets_), x_property_, x11::Time::CurrentTime});
static_cast<uint32_t>(x_property_),
static_cast<uint32_t>(x_window_), x11::CurrentTime);
} }
void X11ClipboardOzone::ReadRemoteClipboard(x11::Atom selection) { void X11ClipboardOzone::ReadRemoteClipboard(x11::Atom selection) {
...@@ -353,10 +310,8 @@ void X11ClipboardOzone::ReadRemoteClipboard(x11::Atom selection) { ...@@ -353,10 +310,8 @@ void X11ClipboardOzone::ReadRemoteClipboard(x11::Atom selection) {
} }
} }
XConvertSelection(x_display_, static_cast<uint32_t>(selection), connection_->ConvertSelection({x_window_, selection, gfx::GetAtom(target),
static_cast<uint32_t>(gfx::GetAtom(target)), x_property_, x11::Time::CurrentTime});
static_cast<uint32_t>(x_property_),
static_cast<uint32_t>(x_window_), x11::CurrentTime);
} }
void X11ClipboardOzone::OfferClipboardData( void X11ClipboardOzone::OfferClipboardData(
...@@ -365,14 +320,14 @@ void X11ClipboardOzone::OfferClipboardData( ...@@ -365,14 +320,14 @@ void X11ClipboardOzone::OfferClipboardData(
PlatformClipboard::OfferDataClosure callback) { PlatformClipboard::OfferDataClosure callback) {
const x11::Atom selection = SelectionAtomForBuffer(buffer); const x11::Atom selection = SelectionAtomForBuffer(buffer);
auto& selection_state = GetSelectionState(selection); auto& selection_state = GetSelectionState(selection);
const auto timestamp = X11EventSource::GetInstance()->GetTimestamp(); const auto timestamp =
static_cast<x11::Time>(X11EventSource::GetInstance()->GetTimestamp());
selection_state.acquired_selection_timestamp = timestamp; selection_state.acquired_selection_timestamp = timestamp;
selection_state.offer_data_map = data_map; selection_state.offer_data_map = data_map;
// Only take ownership if we are using xfixes. // Only take ownership if we are using xfixes.
// TODO(joelhockey): Make clipboard work without xfixes. // TODO(joelhockey): Make clipboard work without xfixes.
if (using_xfixes_) { if (using_xfixes_) {
XSetSelectionOwner(x_display_, static_cast<uint32_t>(selection), connection_->SetSelectionOwner({x_window_, selection, timestamp});
static_cast<uint32_t>(x_window_), timestamp);
} }
std::move(callback).Run(); std::move(callback).Run();
} }
...@@ -429,9 +384,9 @@ bool X11ClipboardOzone::IsSelectionOwner(ClipboardBuffer buffer) { ...@@ -429,9 +384,9 @@ bool X11ClipboardOzone::IsSelectionOwner(ClipboardBuffer buffer) {
if (!using_xfixes_) if (!using_xfixes_)
return true; return true;
return XGetSelectionOwner(x_display_, static_cast<uint32_t>( auto reply =
SelectionAtomForBuffer(buffer))) == connection_->GetSelectionOwner({SelectionAtomForBuffer(buffer)}).Sync();
static_cast<uint32_t>(x_window_); return reply && reply->owner == x_window_;
} }
void X11ClipboardOzone::SetSequenceNumberUpdateCb( void X11ClipboardOzone::SetSequenceNumberUpdateCb(
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "ui/gfx/x/event.h" #include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xproto.h"
#include "ui/ozone/public/platform_clipboard.h" #include "ui/ozone/public/platform_clipboard.h"
namespace ui { namespace ui {
...@@ -54,9 +56,10 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher { ...@@ -54,9 +56,10 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher {
// XEventDispatcher: // XEventDispatcher:
bool DispatchXEvent(x11::Event* xev) override; bool DispatchXEvent(x11::Event* xev) override;
bool OnSelectionRequest(const XSelectionRequestEvent& event); bool OnSelectionRequest(const x11::SelectionRequestEvent& event);
bool OnSelectionNotify(const XSelectionEvent& event); bool OnSelectionNotify(const x11::SelectionNotifyEvent& event);
bool OnSetSelectionOwnerNotify(x11::Event* xev); bool OnSetSelectionOwnerNotify(
const x11::XFixes::SelectionNotifyEvent& event);
// Returns an X atom for a clipboard buffer type. // Returns an X atom for a clipboard buffer type.
x11::Atom SelectionAtomForBuffer(ClipboardBuffer buffer) const; x11::Atom SelectionAtomForBuffer(ClipboardBuffer buffer) const;
...@@ -89,7 +92,7 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher { ...@@ -89,7 +92,7 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher {
const x11::Atom x_property_; const x11::Atom x_property_;
// Our X11 state. // Our X11 state.
Display* const x_display_; x11::Connection* connection_;
// Input-only window used as a selection owner. // Input-only window used as a selection owner.
const x11::Window x_window_; const x11::Window x_window_;
...@@ -99,9 +102,6 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher { ...@@ -99,9 +102,6 @@ class X11ClipboardOzone : public PlatformClipboard, public XEventDispatcher {
// TODO(joelhockey): Make clipboard work without xfixes. // TODO(joelhockey): Make clipboard work without xfixes.
bool using_xfixes_ = false; bool using_xfixes_ = false;
// The event base returned by XFixesQueryExtension().
int xfixes_event_base_;
// Notifies whenever clipboard sequence number is changed. // Notifies whenever clipboard sequence number is changed.
PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_; PlatformClipboard::SequenceNumberUpdateCb update_sequence_cb_;
......
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