diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/ui/base/x | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/ui/base/x')
48 files changed, 2932 insertions, 2123 deletions
diff --git a/chromium/ui/base/x/BUILD.gn b/chromium/ui/base/x/BUILD.gn index 0daf5090985..2737a66ff79 100644 --- a/chromium/ui/base/x/BUILD.gn +++ b/chromium/ui/base/x/BUILD.gn @@ -15,12 +15,18 @@ jumbo_component("x") { sources = [ "selection_utils.cc", "selection_utils.h", + "x11_cursor.cc", + "x11_cursor.h", + "x11_cursor_factory.cc", + "x11_cursor_factory.h", "x11_desktop_window_move_client.cc", "x11_desktop_window_move_client.h", "x11_display_manager.cc", "x11_display_manager.h", "x11_display_util.cc", "x11_display_util.h", + "x11_error_handler.cc", + "x11_error_handler.h", "x11_menu_list.cc", "x11_menu_list.h", "x11_menu_registrar.cc", @@ -46,7 +52,7 @@ jumbo_component("x") { "x11_workspace_handler.h", ] - if (is_desktop_linux) { + if (is_desktop_linux || is_chromeos) { sources += [ "selection_owner.cc", "selection_owner.h", @@ -59,8 +65,6 @@ jumbo_component("x") { ] } - public_configs = [ "//build/config/linux:xrandr" ] - defines = [ "IS_UI_BASE_X_IMPL" ] deps = [ @@ -72,6 +76,9 @@ jumbo_component("x") { "//ui/base:hit_test", "//ui/base:wm_role_names", "//ui/base/clipboard:clipboard_types", + "//ui/base/cursor:cursor_base", + "//ui/base/cursor:theme_manager", + "//ui/base/cursor/mojom:cursor_type", "//ui/base/dragdrop/file_info", "//ui/display/util", "//ui/events", @@ -80,6 +87,7 @@ jumbo_component("x") { "//ui/events/platform/x11", "//ui/events/x:x", "//ui/gfx", + "//ui/gfx/geometry", "//ui/gfx/x", "//ui/platform_window/common", ] @@ -115,3 +123,14 @@ source_set("test_support") { "//ui/gfx/x", ] } + +source_set("unittests") { + testonly = true + sources = [ "x11_cursor_factory_unittest.cc" ] + deps = [ + ":x", + "//skia", + "//testing/gtest", + "//ui/gfx/geometry", + ] +} diff --git a/chromium/ui/base/x/selection_owner.cc b/chromium/ui/base/x/selection_owner.cc index 76d95fdd45a..755b502b20a 100644 --- a/chromium/ui/base/x/selection_owner.cc +++ b/chromium/ui/base/x/selection_owner.cc @@ -7,11 +7,14 @@ #include <algorithm> #include "base/logging.h" +#include "base/memory/ref_counted_memory.h" #include "ui/base/x/selection_utils.h" +#include "ui/base/x/x11_util.h" #include "ui/events/platform/x11/x11_event_source.h" #include "ui/events/x/x11_window_event_manager.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" +#include "ui/gfx/x/xproto.h" namespace ui { @@ -38,152 +41,142 @@ static_assert(KSelectionOwnerTimerPeriodMs <= kIncrementalTransferTimeoutMs, // Returns a conservative max size of the data we can pass into // XChangeProperty(). Copied from GTK. -size_t GetMaxRequestSize(XDisplay* display) { - long extended_max_size = XExtendedMaxRequestSize(display); +size_t GetMaxRequestSize(x11::Connection* connection) { + long extended_max_size = connection->extended_max_request_length(); 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), std::max(static_cast<long>(0), max_size)); } // Gets the value of an atom pair array property. On success, true is returned // and the value is stored in |value|. -bool GetAtomPairArrayProperty(XID window, - XAtom property, - std::vector<std::pair<XAtom,XAtom> >* value) { - XAtom type = x11::None; - int format = 0; // size in bits of each item in 'property' - unsigned long num_items = 0; - unsigned char* properties = nullptr; - unsigned long remaining_bytes = 0; - - int result = XGetWindowProperty(gfx::GetXDisplay(), window, property, - 0, // offset into property data to - // read - (~0L), // entire array - x11::False, // deleted - AnyPropertyType, &type, &format, &num_items, - &remaining_bytes, &properties); - gfx::XScopedPtr<unsigned char> scoped_properties(properties); - - if (result != x11::Success) +bool GetAtomPairArrayProperty( + x11::Window window, + x11::Atom property, + std::vector<std::pair<x11::Atom, x11::Atom>>* value) { + std::vector<x11::Atom> atoms; + // Since this is an array of atom pairs, ensure ensure |atoms| + // has an element count that's a multiple of 2. + if (!ui::GetArrayProperty(window, property, &atoms) || atoms.size() % 2 != 0) return false; - // GTK does not require |type| to be kAtomPair. - if (format != 32 || num_items % 2 != 0) - return false; - - XAtom* atom_properties = reinterpret_cast<XAtom*>(properties); value->clear(); - for (size_t i = 0; i < num_items; i+=2) - value->push_back(std::make_pair(atom_properties[i], atom_properties[i+1])); + for (size_t i = 0; i < atoms.size(); i += 2) + value->push_back(std::make_pair(atoms[i], atoms[i + 1])); return true; } +x11::Window GetSelectionOwner(x11::Atom selection) { + auto response = x11::Connection::Get()->GetSelectionOwner({selection}).Sync(); + return response ? response->owner : x11::Window::None; +} + +void SetSelectionOwner(x11::Window window, + x11::Atom selection, + x11::Time time = x11::Time::CurrentTime) { + x11::Connection::Get()->SetSelectionOwner({window, selection, time}); +} + } // namespace -SelectionOwner::SelectionOwner(XDisplay* x_display, - XID x_window, - XAtom selection_name) - : x_display_(x_display), - x_window_(x_window), +SelectionOwner::SelectionOwner(x11::Connection* connection, + x11::Window x_window, + x11::Atom selection_name) + : x_window_(x_window), selection_name_(selection_name), - max_request_size_(GetMaxRequestSize(x_display)) {} + max_request_size_(GetMaxRequestSize(connection)) {} SelectionOwner::~SelectionOwner() { // If we are the selection owner, we need to release the selection so we // don't receive further events. However, we don't call ClearSelectionOwner() // because we don't want to do this indiscriminately. - if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) - XSetSelectionOwner(x_display_, selection_name_, x11::None, - x11::CurrentTime); + if (GetSelectionOwner(selection_name_) == x_window_) + SetSelectionOwner(x11::Window::None, selection_name_); } -void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { +void SelectionOwner::RetrieveTargets(std::vector<x11::Atom>* targets) { for (const auto& format_target : format_map_) targets->push_back(format_target.first); } -void SelectionOwner::TakeOwnershipOfSelection( - const SelectionFormatMap& data) { +void SelectionOwner::TakeOwnershipOfSelection(const SelectionFormatMap& data) { acquired_selection_timestamp_ = X11EventSource::GetInstance()->GetTimestamp(); - XSetSelectionOwner(x_display_, selection_name_, x_window_, - acquired_selection_timestamp_); + SetSelectionOwner(x_window_, selection_name_, + static_cast<x11::Time>(acquired_selection_timestamp_)); - if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) { + if (GetSelectionOwner(selection_name_) == x_window_) { // The X server agrees that we are the selection owner. Commit our data. format_map_ = data; } } void SelectionOwner::ClearSelectionOwner() { - XSetSelectionOwner(x_display_, selection_name_, x11::None, x11::CurrentTime); + SetSelectionOwner(x11::Window::None, selection_name_); format_map_ = SelectionFormatMap(); } -void SelectionOwner::OnSelectionRequest(const XEvent& event) { - XID requestor = event.xselectionrequest.requestor; - XAtom requested_target = event.xselectionrequest.target; - XAtom requested_property = event.xselectionrequest.property; +void SelectionOwner::OnSelectionRequest(const x11::Event& x11_event) { + auto& request = *x11_event.As<x11::SelectionRequestEvent>(); + auto requestor = request.requestor; + x11::Atom requested_target = request.target; + x11::Atom requested_property = request.property; // Incrementally build our selection. By default this is a refusal, and we'll // override the parts indicating success in the different cases. - XEvent reply; - reply.xselection.type = SelectionNotify; - reply.xselection.requestor = requestor; - reply.xselection.selection = event.xselectionrequest.selection; - reply.xselection.target = requested_target; - reply.xselection.property = x11::None; // Indicates failure - reply.xselection.time = event.xselectionrequest.time; + x11::SelectionNotifyEvent reply{ + .time = request.time, + .requestor = requestor, + .selection = request.selection, + .target = requested_target, + .property = x11::Atom::None, // Indicates failure + }; if (requested_target == gfx::GetAtom(kMultiple)) { // The contents of |requested_property| should be a list of // <target,property> pairs. - std::vector<std::pair<XAtom,XAtom> > conversions; - if (GetAtomPairArrayProperty(requestor, - requested_property, - &conversions)) { - std::vector<XAtom> conversion_results; - for (const std::pair<XAtom, XAtom>& conversion : conversions) { + std::vector<std::pair<x11::Atom, x11::Atom>> conversions; + if (GetAtomPairArrayProperty(requestor, requested_property, &conversions)) { + std::vector<x11::Atom> conversion_results; + for (const std::pair<x11::Atom, x11::Atom>& conversion : conversions) { bool conversion_successful = ProcessTarget(conversion.first, requestor, conversion.second); conversion_results.push_back(conversion.first); conversion_results.push_back(conversion_successful ? conversion.second - : x11::None); + : x11::Atom::None); } // Set the property to indicate which conversions succeeded. This matches // what GTK does. - XChangeProperty( - x_display_, requestor, requested_property, gfx::GetAtom(kAtomPair), - 32, PropModeReplace, - reinterpret_cast<const unsigned char*>(&conversion_results.front()), - conversion_results.size()); + ui::SetArrayProperty(requestor, requested_property, + gfx::GetAtom(kAtomPair), conversion_results); - reply.xselection.property = requested_property; + reply.property = requested_property; } } else { if (ProcessTarget(requested_target, requestor, requested_property)) - reply.xselection.property = requested_property; + reply.property = requested_property; } // Send off the reply. - XSendEvent(x_display_, requestor, x11::False, 0, &reply); + ui::SendEvent(reply, requestor, x11::EventMask::NoEvent); } -void SelectionOwner::OnSelectionClear(const XEvent& event) { +void SelectionOwner::OnSelectionClear(const x11::Event& event) { DLOG(ERROR) << "SelectionClear"; // TODO(erg): If we receive a SelectionClear event while we're handling data, // we need to delay clearing. } -bool SelectionOwner::CanDispatchPropertyEvent(const XEvent& event) { - return event.xproperty.state == PropertyDelete && +bool SelectionOwner::CanDispatchPropertyEvent(const x11::Event& event) { + return event.As<x11::PropertyNotifyEvent>()->state == x11::Property::Delete && FindIncrementalTransferForEvent(event) != incremental_transfers_.end(); } -void SelectionOwner::OnPropertyEvent(const XEvent& event) { +void SelectionOwner::OnPropertyEvent(const x11::Event& event) { auto it = FindIncrementalTransferForEvent(event); if (it == incremental_transfers_.end()) return; @@ -193,35 +186,31 @@ void SelectionOwner::OnPropertyEvent(const XEvent& event) { CompleteIncrementalTransfer(it); } -bool SelectionOwner::ProcessTarget(XAtom target, - XID requestor, - XAtom property) { - XAtom multiple_atom = gfx::GetAtom(kMultiple); - XAtom save_targets_atom = gfx::GetAtom(kSaveTargets); - XAtom targets_atom = gfx::GetAtom(kTargets); - XAtom timestamp_atom = gfx::GetAtom(kTimestamp); +bool SelectionOwner::ProcessTarget(x11::Atom target, + x11::Window requestor, + x11::Atom property) { + x11::Atom multiple_atom = gfx::GetAtom(kMultiple); + x11::Atom save_targets_atom = gfx::GetAtom(kSaveTargets); + x11::Atom targets_atom = gfx::GetAtom(kTargets); + x11::Atom timestamp_atom = gfx::GetAtom(kTimestamp); if (target == multiple_atom || target == save_targets_atom) return false; if (target == timestamp_atom) { - XChangeProperty( - x_display_, requestor, property, XA_INTEGER, 32, PropModeReplace, - reinterpret_cast<unsigned char*>(&acquired_selection_timestamp_), 1); + ui::SetProperty(requestor, property, x11::Atom::INTEGER, + acquired_selection_timestamp_); return true; } if (target == targets_atom) { // We have been asked for TARGETS. Send an atom array back with the data // types we support. - std::vector<XAtom> targets = {timestamp_atom, targets_atom, - save_targets_atom, multiple_atom}; + std::vector<x11::Atom> targets = {timestamp_atom, targets_atom, + save_targets_atom, multiple_atom}; RetrieveTargets(&targets); - XChangeProperty(x_display_, requestor, property, XA_ATOM, 32, - PropModeReplace, - reinterpret_cast<unsigned char*>(&targets.front()), - targets.size()); + ui::SetArrayProperty(requestor, property, x11::Atom::ATOM, targets); return true; } @@ -232,10 +221,8 @@ bool SelectionOwner::ProcessTarget(XAtom target, // We must send the data back in several chunks due to a limitation in // the size of X requests. Notify the selection requestor that the data // will be sent incrementally by returning data of type "INCR". - long length = it->second->size(); - XChangeProperty(x_display_, requestor, property, gfx::GetAtom(kIncr), 32, - PropModeReplace, - reinterpret_cast<unsigned char*>(&length), 1); + uint32_t length = it->second->size(); + ui::SetProperty(requestor, property, gfx::GetAtom(kIncr), length); // Wait for the selection requestor to indicate that it has processed // the selection result before sending the first chunk of data. The @@ -243,10 +230,10 @@ bool SelectionOwner::ProcessTarget(XAtom target, base::TimeTicks timeout = base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs); - incremental_transfers_.push_back(IncrementalTransfer( + incremental_transfers_.emplace_back( requestor, target, property, std::make_unique<XScopedEventSelector>(requestor, PropertyChangeMask), - it->second, 0, timeout)); + it->second, 0, timeout); // Start a timer to abort the data transfer in case that the selection // requestor does not support the INCR property or gets destroyed during @@ -258,15 +245,9 @@ bool SelectionOwner::ProcessTarget(XAtom target, this, &SelectionOwner::AbortStaleIncrementalTransfers); } } else { - XChangeProperty( - x_display_, - requestor, - property, - target, - 8, - PropModeReplace, - const_cast<unsigned char*>(it->second->front()), - it->second->size()); + auto& mem = it->second; + std::vector<uint8_t> data(mem->data(), mem->data() + mem->size()); + ui::SetArrayProperty(requestor, property, target, data); } return true; } @@ -279,17 +260,13 @@ bool SelectionOwner::ProcessTarget(XAtom target, void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) { size_t remaining = transfer->data->size() - transfer->offset; size_t chunk_length = std::min(remaining, max_request_size_); - XChangeProperty( - x_display_, - transfer->window, - transfer->property, - transfer->target, - 8, - PropModeReplace, - const_cast<unsigned char*>(transfer->data->front() + transfer->offset), - chunk_length); + const uint8_t* data = transfer->data->front() + transfer->offset; + std::vector<uint8_t> buf(data, data + chunk_length); + ui::SetArrayProperty(transfer->window, transfer->property, transfer->target, + buf); transfer->offset += chunk_length; - transfer->timeout = base::TimeTicks::Now() + + transfer->timeout = + base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(kIncrementalTransferTimeoutMs); // When offset == data->size(), we still need to transfer a zero-sized chunk @@ -302,8 +279,8 @@ void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) { void SelectionOwner::AbortStaleIncrementalTransfers() { base::TimeTicks now = base::TimeTicks::Now(); - for (int i = static_cast<int>(incremental_transfers_.size()) - 1; - i >= 0; --i) { + for (int i = static_cast<int>(incremental_transfers_.size()) - 1; i >= 0; + --i) { if (incremental_transfers_[i].timeout <= now) CompleteIncrementalTransfer(incremental_transfers_.begin() + i); } @@ -318,21 +295,20 @@ void SelectionOwner::CompleteIncrementalTransfer( } std::vector<SelectionOwner::IncrementalTransfer>::iterator - SelectionOwner::FindIncrementalTransferForEvent(const XEvent& event) { +SelectionOwner::FindIncrementalTransferForEvent(const x11::Event& event) { for (auto it = incremental_transfers_.begin(); it != incremental_transfers_.end(); ++it) { - if (it->window == event.xproperty.window && - it->property == event.xproperty.atom) { + const auto* prop = event.As<x11::PropertyNotifyEvent>(); + if (it->window == prop->window && it->property == prop->atom) return it; - } } return incremental_transfers_.end(); } SelectionOwner::IncrementalTransfer::IncrementalTransfer( - XID window, - XAtom target, - XAtom property, + x11::Window window, + x11::Atom target, + x11::Atom property, std::unique_ptr<XScopedEventSelector> event_selector, const scoped_refptr<base::RefCountedMemory>& data, int offset, @@ -348,10 +324,9 @@ SelectionOwner::IncrementalTransfer::IncrementalTransfer( SelectionOwner::IncrementalTransfer::IncrementalTransfer( IncrementalTransfer&& other) = default; -SelectionOwner::IncrementalTransfer& SelectionOwner::IncrementalTransfer:: -operator=(IncrementalTransfer&&) = default; +SelectionOwner::IncrementalTransfer& +SelectionOwner::IncrementalTransfer::operator=(IncrementalTransfer&&) = default; -SelectionOwner::IncrementalTransfer::~IncrementalTransfer() { -} +SelectionOwner::IncrementalTransfer::~IncrementalTransfer() = default; } // namespace ui diff --git a/chromium/ui/base/x/selection_owner.h b/chromium/ui/base/x/selection_owner.h index a048133b9dd..0c715bd53d0 100644 --- a/chromium/ui/base/x/selection_owner.h +++ b/chromium/ui/base/x/selection_owner.h @@ -16,6 +16,7 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "ui/base/x/selection_utils.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11_types.h" namespace ui { @@ -33,16 +34,16 @@ COMPONENT_EXPORT(UI_BASE_X) extern const char kTargets[]; // processes. class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner { public: - SelectionOwner(XDisplay* xdisplay, - XID xwindow, - XAtom selection_name); + SelectionOwner(x11::Connection* connection, + x11::Window xwindow, + x11::Atom selection_name); ~SelectionOwner(); // Returns the current selection data. Useful for fast paths. const SelectionFormatMap& selection_format_map() { return format_map_; } // Appends a list of types we're offering to |targets|. - void RetrieveTargets(std::vector<XAtom>* targets); + void RetrieveTargets(std::vector<x11::Atom>* targets); // Attempts to take ownership of the selection. If we're successful, present // |data| to other windows. @@ -53,21 +54,21 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner { void ClearSelectionOwner(); // It is our owner's responsibility to plumb X11 events on |xwindow_| to us. - void OnSelectionRequest(const XEvent& event); - void OnSelectionClear(const XEvent& event); + void OnSelectionRequest(const x11::Event& event); + void OnSelectionClear(const x11::Event& event); // Returns true if SelectionOwner can process the XPropertyEvent event, // |event|. - bool CanDispatchPropertyEvent(const XEvent& event); + bool CanDispatchPropertyEvent(const x11::Event& event); - void OnPropertyEvent(const XEvent& event); + void OnPropertyEvent(const x11::Event& event); private: // Holds state related to an incremental data transfer. struct IncrementalTransfer { - IncrementalTransfer(XID window, - XAtom target, - XAtom property, + IncrementalTransfer(x11::Window window, + x11::Atom target, + x11::Atom property, std::unique_ptr<XScopedEventSelector> event_selector, const scoped_refptr<base::RefCountedMemory>& data, int offset, @@ -80,9 +81,9 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner { // Parameters from the XSelectionRequest. The data is transferred over // |property| on |window|. - XID window; - XAtom target; - XAtom property; + x11::Window window; + x11::Atom target; + x11::Atom property; // Selects events on |window|. std::unique_ptr<XScopedEventSelector> event_selector; @@ -105,7 +106,9 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner { // Attempts to convert the selection to |target|. If the conversion is // successful, true is returned and the result is stored in the |property| // of |requestor|. - bool ProcessTarget(XAtom target, XID requestor, XAtom property); + bool ProcessTarget(x11::Atom target, + x11::Window requestor, + x11::Atom property); // Sends the next chunk of data for given the incremental data transfer. void ProcessIncrementalTransfer(IncrementalTransfer* transfer); @@ -120,17 +123,16 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner { // Returns the incremental data transfer, if any, which was waiting for // |event|. std::vector<IncrementalTransfer>::iterator FindIncrementalTransferForEvent( - const XEvent& event); + const x11::Event& event); // Our X11 state. - XDisplay* x_display_; - XID x_window_; + x11::Window x_window_; // The X11 selection that this instance communicates on. - XAtom selection_name_; + x11::Atom selection_name_; // The time that this instance took ownership of its selection. - Time acquired_selection_timestamp_; + uint32_t acquired_selection_timestamp_; // The maximum size of data we can put in XChangeProperty(). size_t max_request_size_; diff --git a/chromium/ui/base/x/selection_requestor.cc b/chromium/ui/base/x/selection_requestor.cc index c94e955d363..3e2173b4498 100644 --- a/chromium/ui/base/x/selection_requestor.cc +++ b/chromium/ui/base/x/selection_requestor.cc @@ -6,15 +6,16 @@ #include <algorithm> +#include "base/memory/ref_counted_memory.h" #include "base/run_loop.h" #include "ui/base/x/selection_owner.h" #include "ui/base/x/selection_utils.h" #include "ui/base/x/x11_util.h" #include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/x11/x11_event_source.h" -#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_types.h" +#include "ui/gfx/x/xproto.h" namespace ui { @@ -32,46 +33,40 @@ const int kRequestTimeoutMs = 10000; static_assert(KSelectionRequestorTimerPeriodMs <= kRequestTimeoutMs, "timer period must be <= request timeout"); -// Combines |data| into a single RefCountedMemory object. -scoped_refptr<base::RefCountedMemory> CombineRefCountedMemory( - const std::vector<scoped_refptr<base::RefCountedMemory> >& data) { +// Combines |data| into a single std::vector<uint8_t>. +std::vector<uint8_t> CombineData( + const std::vector<std::vector<uint8_t>>& data) { if (data.size() == 1u) return data[0]; - size_t combined_length = 0; + size_t bytes = 0; for (const auto& datum : data) - combined_length += datum->size(); - std::vector<unsigned char> combined_data; - combined_data.reserve(combined_length); - - for (const auto& datum : data) { - combined_data.insert(combined_data.end(), datum->front(), - datum->front() + datum->size()); - } - return base::RefCountedBytes::TakeVector(&combined_data); + bytes += datum.size(); + std::vector<uint8_t> combined; + combined.reserve(bytes); + for (const auto& datum : data) + std::copy(datum.begin(), datum.end(), std::back_inserter(combined)); + return combined; } } // namespace -SelectionRequestor::SelectionRequestor(XDisplay* x_display, - XID x_window, +SelectionRequestor::SelectionRequestor(x11::Window x_window, XEventDispatcher* dispatcher) - : x_display_(x_display), - x_window_(x_window), - x_property_(x11::None), + : x_window_(x_window), + x_property_(x11::Atom::None), dispatcher_(dispatcher), current_request_index_(0u) { x_property_ = gfx::GetAtom(kChromeSelection); } -SelectionRequestor::~SelectionRequestor() {} +SelectionRequestor::~SelectionRequestor() = default; bool SelectionRequestor::PerformBlockingConvertSelection( - XAtom selection, - XAtom target, - scoped_refptr<base::RefCountedMemory>* out_data, - size_t* out_data_items, - XAtom* out_type) { + x11::Atom selection, + x11::Atom target, + std::vector<uint8_t>* out_data, + x11::Atom* out_type) { base::TimeTicks timeout = base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(kRequestTimeoutMs); @@ -94,9 +89,7 @@ bool SelectionRequestor::PerformBlockingConvertSelection( if (request.success) { if (out_data) - *out_data = CombineRefCountedMemory(request.out_data); - if (out_data_items) - *out_data_items = request.out_data_items; + *out_data = CombineData(request.out_data); if (out_type) *out_type = request.out_type; } @@ -104,109 +97,100 @@ bool SelectionRequestor::PerformBlockingConvertSelection( } void SelectionRequestor::PerformBlockingConvertSelectionWithParameter( - XAtom selection, - XAtom target, - const std::vector<XAtom>& parameter) { + x11::Atom selection, + x11::Atom target, + const std::vector<x11::Atom>& parameter) { SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter); - PerformBlockingConvertSelection(selection, target, nullptr, nullptr, nullptr); + PerformBlockingConvertSelection(selection, target, nullptr, nullptr); } SelectionData SelectionRequestor::RequestAndWaitForTypes( - XAtom selection, - const std::vector<XAtom>& types) { - for (const XAtom& item : types) { - scoped_refptr<base::RefCountedMemory> data; - XAtom type = x11::None; - if (PerformBlockingConvertSelection(selection, item, &data, nullptr, - &type) && type == item) { - return SelectionData(type, data); + x11::Atom selection, + const std::vector<x11::Atom>& types) { + for (const x11::Atom& item : types) { + std::vector<uint8_t> data; + x11::Atom type = x11::Atom::None; + if (PerformBlockingConvertSelection(selection, item, &data, &type) && + type == item) { + return SelectionData(type, base::RefCountedBytes::TakeVector(&data)); } } return SelectionData(); } -void SelectionRequestor::OnSelectionNotify(const XEvent& event) { +void SelectionRequestor::OnSelectionNotify( + const x11::SelectionNotifyEvent& selection) { Request* request = GetCurrentRequest(); - XAtom event_property = event.xselection.property; - if (!request || - request->completed || - request->selection != event.xselection.selection || - request->target != event.xselection.target) { + x11::Atom event_property = selection.property; + if (!request || request->completed || + request->selection != selection.selection || + request->target != selection.target) { // ICCCM requires us to delete the property passed into SelectionNotify. - if (event_property != x11::None) - XDeleteProperty(x_display_, x_window_, event_property); + if (event_property != x11::Atom::None) + ui::DeleteProperty(x_window_, event_property); return; } bool success = false; if (event_property == x_property_) { - scoped_refptr<base::RefCountedMemory> out_data; - success = ui::GetRawBytesOfProperty(x_window_, - x_property_, - &out_data, - &request->out_data_items, + std::vector<uint8_t> out_data; + success = ui::GetRawBytesOfProperty(x_window_, x_property_, &out_data, &request->out_type); if (success) { request->out_data.clear(); request->out_data.push_back(out_data); } } - if (event_property != x11::None) - XDeleteProperty(x_display_, x_window_, event_property); + if (event_property != x11::Atom::None) + ui::DeleteProperty(x_window_, event_property); if (request->out_type == gfx::GetAtom(kIncr)) { request->data_sent_incrementally = true; request->out_data.clear(); - request->out_data_items = 0u; - request->out_type = x11::None; + request->out_type = x11::Atom::None; request->timeout = base::TimeTicks::Now() + - base::TimeDelta::FromMilliseconds(kRequestTimeoutMs); + base::TimeDelta::FromMilliseconds(kRequestTimeoutMs); } else { CompleteRequest(current_request_index_, success); } } -bool SelectionRequestor::CanDispatchPropertyEvent(const XEvent& event) { - return event.xproperty.window == x_window_ && - event.xproperty.atom == x_property_ && - event.xproperty.state == PropertyNewValue; +bool SelectionRequestor::CanDispatchPropertyEvent(const x11::Event& event) { + const auto* prop = event.As<x11::PropertyNotifyEvent>(); + return prop->window == x_window_ && prop->atom == x_property_ && + prop->state == x11::Property::NewValue; } -void SelectionRequestor::OnPropertyEvent(const XEvent& event) { +void SelectionRequestor::OnPropertyEvent(const x11::Event& event) { Request* request = GetCurrentRequest(); if (!request || !request->data_sent_incrementally) return; - scoped_refptr<base::RefCountedMemory> out_data; - size_t out_data_items = 0u; - Atom out_type = x11::None; - bool success = ui::GetRawBytesOfProperty(x_window_, - x_property_, - &out_data, - &out_data_items, - &out_type); + std::vector<uint8_t> out_data; + x11::Atom out_type = x11::Atom::None; + bool success = + ui::GetRawBytesOfProperty(x_window_, x_property_, &out_data, &out_type); if (!success) { CompleteRequest(current_request_index_, false); return; } - if (request->out_type != x11::None && request->out_type != out_type) { + if (request->out_type != x11::Atom::None && request->out_type != out_type) { CompleteRequest(current_request_index_, false); return; } request->out_data.push_back(out_data); - request->out_data_items += out_data_items; request->out_type = out_type; // Delete the property to tell the selection owner to send the next chunk. - XDeleteProperty(x_display_, x_window_, x_property_); + ui::DeleteProperty(x_window_, x_property_); request->timeout = base::TimeTicks::Now() + - base::TimeDelta::FromMilliseconds(kRequestTimeoutMs); + base::TimeDelta::FromMilliseconds(kRequestTimeoutMs); - if (out_data->size() == 0u) + if (out_data.empty()) CompleteRequest(current_request_index_, true); } @@ -219,8 +203,8 @@ void SelectionRequestor::AbortStaleRequests() { } void SelectionRequestor::CompleteRequest(size_t index, bool success) { - if (index >= requests_.size()) - return; + if (index >= requests_.size()) + return; Request* request = requests_[index]; if (request->completed) @@ -241,8 +225,13 @@ void SelectionRequestor::CompleteRequest(size_t index, bool success) { void SelectionRequestor::ConvertSelectionForCurrentRequest() { Request* request = GetCurrentRequest(); if (request) { - XConvertSelection(x_display_, request->selection, request->target, - x_property_, x_window_, x11::CurrentTime); + x11::Connection::Get()->ConvertSelection({ + .requestor = static_cast<x11::Window>(x_window_), + .selection = request->selection, + .target = request->target, + .property = x_property_, + .time = x11::Time::CurrentTime, + }); } } @@ -266,11 +255,14 @@ void SelectionRequestor::BlockTillSelectionNotifyForRequest(Request* request) { } else { // This occurs if PerformBlockingConvertSelection() is called during // shutdown and the X11EventSource has already been destroyed. - while (!request->completed && - request->timeout > base::TimeTicks::Now()) { - if (XPending(x_display_)) { - XEvent event; - XNextEvent(x_display_, &event); + auto* conn = x11::Connection::Get(); + auto& events = conn->events(); + while (!request->completed && request->timeout > base::TimeTicks::Now()) { + conn->Flush(); + conn->ReadResponses(); + if (!conn->events().empty()) { + x11::Event event = std::move(events.front()); + events.pop_front(); dispatcher_->DispatchXEvent(&event); } } @@ -283,19 +275,17 @@ SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() { : requests_[current_request_index_]; } -SelectionRequestor::Request::Request(XAtom selection, - XAtom target, +SelectionRequestor::Request::Request(x11::Atom selection, + x11::Atom target, base::TimeTicks timeout) : selection(selection), target(target), data_sent_incrementally(false), - out_data_items(0u), - out_type(x11::None), + out_type(x11::Atom::None), success(false), timeout(timeout), completed(false) {} -SelectionRequestor::Request::~Request() { -} +SelectionRequestor::Request::~Request() = default; } // namespace ui diff --git a/chromium/ui/base/x/selection_requestor.h b/chromium/ui/base/x/selection_requestor.h index aa5f7a14b3b..9b97d24ff58 100644 --- a/chromium/ui/base/x/selection_requestor.h +++ b/chromium/ui/base/x/selection_requestor.h @@ -10,12 +10,14 @@ #include <vector> #include "base/callback.h" +#include "base/component_export.h" #include "base/macros.h" #include "base/memory/ref_counted_memory.h" #include "base/time/time.h" #include "base/timer/timer.h" -#include "ui/base/ui_base_export.h" #include "ui/events/platform_event.h" +#include "ui/gfx/x/event.h" +#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_types.h" namespace ui { @@ -29,67 +31,62 @@ class SelectionData; // drop. This class interprets messages from the stateful selection request // API. SelectionRequestor should only deal with the X11 details; it does not // implement per-component fast-paths. -class UI_BASE_EXPORT SelectionRequestor { +class COMPONENT_EXPORT(UI_BASE) SelectionRequestor { public: - SelectionRequestor(XDisplay* xdisplay, - XID xwindow, - XEventDispatcher* dispatcher); + SelectionRequestor(x11::Window xwindow, XEventDispatcher* dispatcher); ~SelectionRequestor(); // Does the work of requesting |target| from |selection|, spinning up the // nested run loop, and reading the resulting data back. The result is // stored in |out_data|. // |out_data_items| is the length of |out_data| in |out_type| items. - bool PerformBlockingConvertSelection( - XAtom selection, - XAtom target, - scoped_refptr<base::RefCountedMemory>* out_data, - size_t* out_data_items, - XAtom* out_type); + bool PerformBlockingConvertSelection(x11::Atom selection, + x11::Atom target, + std::vector<uint8_t>* out_data, + x11::Atom* out_type); // Requests |target| from |selection|, passing |parameter| as a parameter to // XConvertSelection(). void PerformBlockingConvertSelectionWithParameter( - XAtom selection, - XAtom target, - const std::vector<XAtom>& parameter); + x11::Atom selection, + x11::Atom target, + const std::vector<x11::Atom>& parameter); // Returns the first of |types| offered by the current owner of |selection|. // Returns an empty SelectionData object if none of |types| are available. - SelectionData RequestAndWaitForTypes(XAtom selection, - const std::vector<XAtom>& types); + SelectionData RequestAndWaitForTypes(x11::Atom selection, + const std::vector<x11::Atom>& types); // It is our owner's responsibility to plumb X11 SelectionNotify events on // |xwindow_| to us. - void OnSelectionNotify(const XEvent& event); + void OnSelectionNotify(const x11::SelectionNotifyEvent& event); // Returns true if SelectionOwner can process the XChangeProperty event, // |event|. - bool CanDispatchPropertyEvent(const XEvent& event); + bool CanDispatchPropertyEvent(const x11::Event& event); - void OnPropertyEvent(const XEvent& event); + void OnPropertyEvent(const x11::Event& event); private: friend class SelectionRequestorTest; // A request that has been issued. struct Request { - Request(XAtom selection, XAtom target, base::TimeTicks timeout); + Request(x11::Atom selection, x11::Atom target, base::TimeTicks timeout); ~Request(); // The target and selection requested in the XConvertSelection() request. // Used for error detection. - XAtom selection; - XAtom target; + x11::Atom selection; + x11::Atom target; // Whether the result of the XConvertSelection() request is being sent // incrementally. bool data_sent_incrementally; // The result data for the XConvertSelection() request. - std::vector<scoped_refptr<base::RefCountedMemory> > out_data; - size_t out_data_items; - XAtom out_type; + std::vector<std::vector<uint8_t>> out_data; + x11::Atom out_type; // Whether the XConvertSelection() request was successful. bool success; @@ -122,12 +119,11 @@ class UI_BASE_EXPORT SelectionRequestor { Request* GetCurrentRequest(); // Our X11 state. - XDisplay* x_display_; - XID x_window_; + x11::Window x_window_; // The property on |x_window_| set by the selection owner with the value of // the selection. - XAtom x_property_; + x11::Atom x_property_; // Dispatcher which handles SelectionNotify and SelectionRequest for // |selection_name_|. PerformBlockingConvertSelection() calls the diff --git a/chromium/ui/base/x/selection_requestor_unittest.cc b/chromium/ui/base/x/selection_requestor_unittest.cc index f4d547e2668..ac538ae6d25 100644 --- a/chromium/ui/base/x/selection_requestor_unittest.cc +++ b/chromium/ui/base/x/selection_requestor_unittest.cc @@ -5,6 +5,8 @@ #include "ui/base/x/selection_requestor.h" #include <stddef.h> +#include <xcb/xcb.h> + #include <memory> #include "base/bind.h" @@ -17,40 +19,44 @@ #include "ui/base/x/selection_utils.h" #include "ui/base/x/x11_util.h" #include "ui/events/platform/platform_event_source.h" +#include "ui/gfx/x/connection.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_types.h" +#include "ui/gfx/x/xproto.h" namespace ui { class SelectionRequestorTest : public testing::Test { public: - SelectionRequestorTest() - : x_display_(gfx::GetXDisplay()), x_window_(x11::None) {} + SelectionRequestorTest() : x_display_(gfx::GetXDisplay()) {} - ~SelectionRequestorTest() override {} + ~SelectionRequestorTest() override = default; // Responds to the SelectionRequestor's XConvertSelection() request by // - Setting the property passed into the XConvertSelection() request to // |value|. // - Sending a SelectionNotify event. - void SendSelectionNotify(XAtom selection, - XAtom target, + void SendSelectionNotify(x11::Atom selection, + x11::Atom target, const std::string& value) { ui::SetStringProperty(x_window_, requestor_->x_property_, gfx::GetAtom("STRING"), value); - XEvent xev; - xev.type = SelectionNotify; - xev.xselection.serial = 0u; - xev.xselection.display = x_display_; - xev.xselection.requestor = x_window_; - xev.xselection.selection = selection; - xev.xselection.target = target; - xev.xselection.property = requestor_->x_property_; - xev.xselection.time = x11::CurrentTime; - xev.xselection.type = SelectionNotify; - requestor_->OnSelectionNotify(xev); + xcb_generic_event_t ge; + memset(&ge, 0, sizeof(ge)); + auto* event = reinterpret_cast<xcb_selection_notify_event_t*>(&ge); + event->response_type = x11::SelectionNotifyEvent::opcode; + event->sequence = 0; + event->requestor = static_cast<uint32_t>(x_window_); + event->selection = static_cast<uint32_t>(selection); + event->target = static_cast<uint32_t>(target); + event->property = static_cast<uint32_t>(requestor_->x_property_); + event->time = x11::CurrentTime; + + x11::Event xev(&ge, x11::Connection::Get()); + requestor_->OnSelectionNotify(*xev.As<x11::SelectionNotifyEvent>()); } protected: @@ -59,33 +65,31 @@ class SelectionRequestorTest : public testing::Test { XSynchronize(x_display_, x11::True); // Create a window for the selection requestor to use. - x_window_ = XCreateWindow(x_display_, - DefaultRootWindow(x_display_), - 0, 0, 10, 10, // x, y, width, height - 0, // border width - CopyFromParent, // depth - InputOnly, - CopyFromParent, // visual - 0, - nullptr); + x_window_ = static_cast<x11::Window>(XCreateWindow( + x_display_, DefaultRootWindow(x_display_), 0, 0, 10, + 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)); event_source_ = PlatformEventSource::CreateDefault(); CHECK(PlatformEventSource::GetInstance()); - requestor_ = - std::make_unique<SelectionRequestor>(x_display_, x_window_, nullptr); + requestor_ = std::make_unique<SelectionRequestor>(x_window_, nullptr); } void TearDown() override { requestor_.reset(); event_source_.reset(); - XDestroyWindow(x_display_, x_window_); + XDestroyWindow(x_display_, static_cast<uint32_t>(x_window_)); XSynchronize(x_display_, x11::False); } Display* x_display_; // |requestor_|'s window. - XID x_window_; + x11::Window x_window_ = x11::Window::None; std::unique_ptr<PlatformEventSource> event_source_; std::unique_ptr<SelectionRequestor> requestor_; @@ -101,16 +105,16 @@ namespace { // Converts |selection| to |target| and checks the returned values. void PerformBlockingConvertSelection(SelectionRequestor* requestor, - XAtom selection, - XAtom target, + x11::Atom selection, + x11::Atom target, const std::string& expected_data) { - scoped_refptr<base::RefCountedMemory> out_data; - size_t out_data_items = 0u; - XAtom out_type = x11::None; - EXPECT_TRUE(requestor->PerformBlockingConvertSelection( - selection, target, &out_data, &out_data_items, &out_type)); - EXPECT_EQ(expected_data, ui::RefCountedMemoryToString(out_data)); - EXPECT_EQ(expected_data.size(), out_data_items); + std::vector<uint8_t> out_data; + x11::Atom out_type = x11::Atom::None; + EXPECT_TRUE(requestor->PerformBlockingConvertSelection(selection, target, + &out_data, &out_type)); + EXPECT_EQ(expected_data.size(), out_data.size()); + EXPECT_EQ(expected_data, ui::RefCountedMemoryToString( + base::RefCountedBytes::TakeVector(&out_data))); EXPECT_EQ(gfx::GetAtom("STRING"), out_type); } @@ -122,10 +126,10 @@ TEST_F(SelectionRequestorTest, NestedRequests) { // Assume that |selection| will have no owner. If there is an owner, the owner // will set the property passed into the XConvertSelection() request which is // undesirable. - XAtom selection = gfx::GetAtom("FAKE_SELECTION"); + x11::Atom selection = gfx::GetAtom("FAKE_SELECTION"); - XAtom target1 = gfx::GetAtom("TARGET1"); - XAtom target2 = gfx::GetAtom("TARGET2"); + x11::Atom target1 = gfx::GetAtom("TARGET1"); + x11::Atom target2 = gfx::GetAtom("TARGET2"); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&PerformBlockingConvertSelection, diff --git a/chromium/ui/base/x/selection_utils.cc b/chromium/ui/base/x/selection_utils.cc index a5eaa7443e0..34533b97d69 100644 --- a/chromium/ui/base/x/selection_utils.cc +++ b/chromium/ui/base/x/selection_utils.cc @@ -25,8 +25,8 @@ const char kTextPlain[] = "text/plain"; const char kTextPlainUtf8[] = "text/plain;charset=utf-8"; const char kUtf8String[] = "UTF8_STRING"; -std::vector<::Atom> GetTextAtomsFrom() { - std::vector< ::Atom> atoms; +std::vector<x11::Atom> GetTextAtomsFrom() { + std::vector<x11::Atom> atoms; atoms.push_back(gfx::GetAtom(kUtf8String)); atoms.push_back(gfx::GetAtom(kString)); atoms.push_back(gfx::GetAtom(kText)); @@ -35,22 +35,22 @@ std::vector<::Atom> GetTextAtomsFrom() { return atoms; } -std::vector<::Atom> GetURLAtomsFrom() { - std::vector< ::Atom> atoms; +std::vector<x11::Atom> GetURLAtomsFrom() { + std::vector<x11::Atom> atoms; atoms.push_back(gfx::GetAtom(kMimeTypeURIList)); atoms.push_back(gfx::GetAtom(kMimeTypeMozillaURL)); return atoms; } -std::vector<::Atom> GetURIListAtomsFrom() { - std::vector< ::Atom> atoms; +std::vector<x11::Atom> GetURIListAtomsFrom() { + std::vector<x11::Atom> atoms; atoms.push_back(gfx::GetAtom(kMimeTypeURIList)); return atoms; } -void GetAtomIntersection(const std::vector< ::Atom>& desired, - const std::vector< ::Atom>& offered, - std::vector< ::Atom>* output) { +void GetAtomIntersection(const std::vector<x11::Atom>& desired, + const std::vector<x11::Atom>& offered, + std::vector<x11::Atom>* output) { for (const auto& desired_atom : desired) { if (base::Contains(offered, desired_atom)) output->push_back(desired_atom); @@ -68,8 +68,8 @@ std::vector<std::string> ParseURIList(const SelectionData& data) { // uri-lists are newline separated file lists in URL encoding. std::string unparsed; data.AssignTo(&unparsed); - return base::SplitString( - unparsed, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + return base::SplitString(unparsed, "\n", base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); } std::string RefCountedMemoryToString( @@ -104,22 +104,22 @@ base::string16 RefCountedMemoryToString16( /////////////////////////////////////////////////////////////////////////////// -SelectionFormatMap::SelectionFormatMap() {} +SelectionFormatMap::SelectionFormatMap() = default; SelectionFormatMap::SelectionFormatMap(const SelectionFormatMap& other) = default; -SelectionFormatMap::~SelectionFormatMap() {} +SelectionFormatMap::~SelectionFormatMap() = default; void SelectionFormatMap::Insert( - ::Atom atom, + x11::Atom atom, const scoped_refptr<base::RefCountedMemory>& item) { data_.erase(atom); data_.emplace(atom, item); } ui::SelectionData SelectionFormatMap::GetFirstOf( - const std::vector< ::Atom>& requested_types) const { + const std::vector<x11::Atom>& requested_types) const { for (const auto& requested_type : requested_types) { auto data_it = data_.find(requested_type); if (data_it != data_.end()) { @@ -130,8 +130,8 @@ ui::SelectionData SelectionFormatMap::GetFirstOf( return SelectionData(); } -std::vector< ::Atom> SelectionFormatMap::GetTypes() const { - std::vector< ::Atom> atoms; +std::vector<x11::Atom> SelectionFormatMap::GetTypes() const { + std::vector<x11::Atom> atoms; for (const auto& datum : data_) atoms.push_back(datum.first); @@ -140,17 +140,16 @@ std::vector< ::Atom> SelectionFormatMap::GetTypes() const { /////////////////////////////////////////////////////////////////////////////// -SelectionData::SelectionData() : type_(x11::None) {} +SelectionData::SelectionData() : type_(x11::Atom::None) {} SelectionData::SelectionData( - ::Atom type, + x11::Atom type, const scoped_refptr<base::RefCountedMemory>& memory) : type_(type), memory_(memory) {} -SelectionData::SelectionData(const SelectionData& rhs) - : type_(rhs.type_), memory_(rhs.memory_) {} +SelectionData::SelectionData(const SelectionData& rhs) = default; -SelectionData::~SelectionData() {} +SelectionData::~SelectionData() = default; SelectionData& SelectionData::operator=(const SelectionData& rhs) { type_ = rhs.type_; @@ -161,10 +160,10 @@ SelectionData& SelectionData::operator=(const SelectionData& rhs) { } bool SelectionData::IsValid() const { - return type_ != x11::None; + return type_ != x11::Atom::None; } -::Atom SelectionData::GetType() const { +x11::Atom SelectionData::GetType() const { return type_; } @@ -184,8 +183,7 @@ std::string SelectionData::GetText() const { type_ == gfx::GetAtom(kTextPlain)) { std::string result; base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_), - base::kCodepageLatin1, - &result); + base::kCodepageLatin1, &result); return result; } else { // BTW, I looked at COMPOUND_TEXT, and there's no way we're going to @@ -204,8 +202,7 @@ base::string16 SelectionData::GetHtml() const { // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is // UTF-16, otherwise assume UTF-8. - if (size >= 2 && - reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) { + if (size >= 2 && reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) { markup.assign(reinterpret_cast<const uint16_t*>(data) + 1, (size / 2) - 1); } else { diff --git a/chromium/ui/base/x/selection_utils.h b/chromium/ui/base/x/selection_utils.h index 5be34cd6414..9ca25b373a0 100644 --- a/chromium/ui/base/x/selection_utils.h +++ b/chromium/ui/base/x/selection_utils.h @@ -20,17 +20,17 @@ COMPONENT_EXPORT(UI_BASE_X) extern const char kText[]; COMPONENT_EXPORT(UI_BASE_X) extern const char kUtf8String[]; // Returns a list of all text atoms that we handle. -COMPONENT_EXPORT(UI_BASE_X) std::vector<::Atom> GetTextAtomsFrom(); +COMPONENT_EXPORT(UI_BASE_X) std::vector<x11::Atom> GetTextAtomsFrom(); -COMPONENT_EXPORT(UI_BASE_X) std::vector<::Atom> GetURLAtomsFrom(); +COMPONENT_EXPORT(UI_BASE_X) std::vector<x11::Atom> GetURLAtomsFrom(); -COMPONENT_EXPORT(UI_BASE_X) std::vector<::Atom> GetURIListAtomsFrom(); +COMPONENT_EXPORT(UI_BASE_X) std::vector<x11::Atom> GetURIListAtomsFrom(); // Places the intersection of |desired| and |offered| into |output|. COMPONENT_EXPORT(UI_BASE_X) -void GetAtomIntersection(const std::vector<::Atom>& desired, - const std::vector<::Atom>& offered, - std::vector<::Atom>* output); +void GetAtomIntersection(const std::vector<x11::Atom>& desired, + const std::vector<x11::Atom>& offered, + std::vector<x11::Atom>* output); // Takes the raw bytes of the base::string16 and copies them into |bytes|. COMPONENT_EXPORT(UI_BASE_X) @@ -56,8 +56,9 @@ base::string16 RefCountedMemoryToString16( class COMPONENT_EXPORT(UI_BASE_X) SelectionFormatMap { public: // Our internal data store, which we only expose through iterators. - typedef std::map< ::Atom, scoped_refptr<base::RefCountedMemory> > InternalMap; - typedef InternalMap::const_iterator const_iterator; + using InternalMap = + std::map<x11::Atom, scoped_refptr<base::RefCountedMemory>>; + using const_iterator = InternalMap::const_iterator; SelectionFormatMap(); SelectionFormatMap(const SelectionFormatMap& other); @@ -66,19 +67,20 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionFormatMap { // Adds the selection in the format |atom|. Ownership of |data| is passed to // us. - void Insert(::Atom atom, const scoped_refptr<base::RefCountedMemory>& item); + void Insert(x11::Atom atom, + const scoped_refptr<base::RefCountedMemory>& item); // Returns the first of the requested_types or NULL if missing. ui::SelectionData GetFirstOf( - const std::vector< ::Atom>& requested_types) const; + const std::vector<x11::Atom>& requested_types) const; // Returns all the selected types. - std::vector< ::Atom> GetTypes() const; + std::vector<x11::Atom> GetTypes() const; // Pass through to STL map. Only allow non-mutation access. const_iterator begin() const { return data_.begin(); } const_iterator end() const { return data_.end(); } - const_iterator find(::Atom atom) const { return data_.find(atom); } + const_iterator find(x11::Atom atom) const { return data_.find(atom); } size_t size() const { return data_.size(); } private: @@ -92,14 +94,14 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionData { public: // |atom_cache| is still owned by caller. SelectionData(); - SelectionData(::Atom type, + SelectionData(x11::Atom type, const scoped_refptr<base::RefCountedMemory>& memory); SelectionData(const SelectionData& rhs); ~SelectionData(); SelectionData& operator=(const SelectionData& rhs); bool IsValid() const; - ::Atom GetType() const; + x11::Atom GetType() const; const unsigned char* GetData() const; size_t GetSize() const; @@ -115,7 +117,7 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionData { void AssignTo(base::string16* result) const; private: - ::Atom type_; + x11::Atom type_; scoped_refptr<base::RefCountedMemory> memory_; }; diff --git a/chromium/ui/base/x/x11_cursor.cc b/chromium/ui/base/x/x11_cursor.cc new file mode 100644 index 00000000000..9d55c5db524 --- /dev/null +++ b/chromium/ui/base/x/x11_cursor.cc @@ -0,0 +1,48 @@ +// Copyright 2016 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/x11_cursor.h" + +#include "base/check_op.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/x/x11_util.h" +#include "ui/gfx/geometry/point.h" + +namespace ui { + +X11Cursor::X11Cursor(const SkBitmap& bitmap, const gfx::Point& hotspot) { + XcursorImage* image = SkBitmapToXcursorImage(bitmap, hotspot); + xcursor_ = XcursorImageLoadCursor(gfx::GetXDisplay(), image); + XcursorImageDestroy(image); +} + +X11Cursor::X11Cursor(const std::vector<SkBitmap>& bitmaps, + const gfx::Point& hotspot, + int frame_delay_ms) { + // Initialize an XCursorImage for each frame, store all of them in + // XCursorImages and load the cursor from that. + XcursorImages* images = XcursorImagesCreate(bitmaps.size()); + images->nimage = bitmaps.size(); + for (size_t frame = 0; frame < bitmaps.size(); ++frame) { + XcursorImage* x_image = SkBitmapToXcursorImage(bitmaps[frame], hotspot); + x_image->delay = frame_delay_ms; + images->images[frame] = x_image; + } + + xcursor_ = XcursorImagesLoadCursor(gfx::GetXDisplay(), images); + XcursorImagesDestroy(images); +} + +X11Cursor::X11Cursor(::Cursor xcursor) : xcursor_(xcursor) {} + +// static +scoped_refptr<X11Cursor> X11Cursor::CreateInvisible() { + return base::MakeRefCounted<X11Cursor>(CreateInvisibleCursor()); +} + +X11Cursor::~X11Cursor() { + XFreeCursor(gfx::GetXDisplay(), xcursor_); +} + +} // namespace ui diff --git a/chromium/ui/base/x/x11_cursor.h b/chromium/ui/base/x/x11_cursor.h new file mode 100644 index 00000000000..1711b947970 --- /dev/null +++ b/chromium/ui/base/x/x11_cursor.h @@ -0,0 +1,55 @@ +// Copyright 2016 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_X11_CURSOR_H_ +#define UI_BASE_X_X11_CURSOR_H_ + +#include <vector> + +#include "base/component_export.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" +#include "ui/gfx/x/x11.h" + +class SkBitmap; + +namespace gfx { +class Point; +} + +namespace ui { + +// Ref counted class to hold an X11 cursor resource. Clears the X11 resources +// on destruction +class COMPONENT_EXPORT(UI_BASE_X) X11Cursor + : public base::RefCounted<X11Cursor> { + public: + REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); + + // Handles creating X11 cursor resources from SkBitmap/hotspot. + X11Cursor(const SkBitmap& bitmap, const gfx::Point& hotspot); + X11Cursor(const X11Cursor&) = delete; + X11Cursor& operator=(const X11Cursor&) = delete; + X11Cursor(const std::vector<SkBitmap>& bitmaps, + const gfx::Point& hotspot, + int frame_delay_ms); + // Wraps an X11 cursor |xcursor|. + explicit X11Cursor(::Cursor xcursor); + + // Creates a new cursor that is invisible. + static scoped_refptr<X11Cursor> CreateInvisible(); + + ::Cursor xcursor() const { return xcursor_; } + + private: + friend class base::RefCounted<X11Cursor>; + + ~X11Cursor(); + + ::Cursor xcursor_ = x11::None; +}; + +} // namespace ui + +#endif // UI_BASE_X_X11_CURSOR_H_ diff --git a/chromium/ui/base/x/x11_cursor_factory.cc b/chromium/ui/base/x/x11_cursor_factory.cc new file mode 100644 index 00000000000..26624776290 --- /dev/null +++ b/chromium/ui/base/x/x11_cursor_factory.cc @@ -0,0 +1,118 @@ +// Copyright 2016 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/x11_cursor_factory.h" + +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" +#include "ui/base/x/x11_cursor.h" +#include "ui/base/x/x11_util.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/x/x11.h" + +namespace ui { + +namespace { + +X11Cursor* ToX11Cursor(PlatformCursor cursor) { + return static_cast<X11Cursor*>(cursor); +} + +PlatformCursor ToPlatformCursor(X11Cursor* cursor) { + return static_cast<PlatformCursor>(cursor); +} + +} // namespace + +X11CursorFactory::X11CursorFactory() + : invisible_cursor_(X11Cursor::CreateInvisible()) {} + +X11CursorFactory::~X11CursorFactory() = default; + +base::Optional<PlatformCursor> X11CursorFactory::GetDefaultCursor( + mojom::CursorType type) { + auto cursor = GetDefaultCursorInternal(type); + if (!cursor) + return base::nullopt; + return ToPlatformCursor(cursor.get()); +} + +PlatformCursor X11CursorFactory::CreateImageCursor(const SkBitmap& bitmap, + const gfx::Point& hotspot) { + // There is a problem with custom cursors that have no custom data. The + // resulting SkBitmap is empty and X crashes when creating a zero size cursor + // image. Return invisible cursor here instead. + if (bitmap.drawsNothing()) { + // The result of |invisible_cursor_| is owned by the caller, and will be + // Unref()ed by code far away. (Usually in web_cursor.cc in content, among + // others.) If we don't manually add another reference before we cast this + // to a void*, we can end up with |invisible_cursor_| being freed out from + // under us. + invisible_cursor_->AddRef(); + return ToPlatformCursor(invisible_cursor_.get()); + } + + auto cursor = base::MakeRefCounted<X11Cursor>(bitmap, hotspot); + cursor->AddRef(); + return ToPlatformCursor(cursor.get()); +} + +PlatformCursor X11CursorFactory::CreateAnimatedCursor( + const std::vector<SkBitmap>& bitmaps, + const gfx::Point& hotspot, + int frame_delay_ms) { + auto cursor = + base::MakeRefCounted<X11Cursor>(bitmaps, hotspot, frame_delay_ms); + cursor->AddRef(); + return ToPlatformCursor(cursor.get()); +} + +void X11CursorFactory::RefImageCursor(PlatformCursor cursor) { + ToX11Cursor(cursor)->AddRef(); +} + +void X11CursorFactory::UnrefImageCursor(PlatformCursor cursor) { + ToX11Cursor(cursor)->Release(); +} + +void X11CursorFactory::ObserveThemeChanges() { + auto* cursor_theme_manager = CursorThemeManager::GetInstance(); + if (cursor_theme_manager) + cursor_theme_observer_.Add(cursor_theme_manager); +} + +void X11CursorFactory::OnCursorThemeNameChanged( + const std::string& cursor_theme_name) { + XcursorSetTheme(gfx::GetXDisplay(), cursor_theme_name.c_str()); + ClearThemeCursors(); +} + +void X11CursorFactory::OnCursorThemeSizeChanged(int cursor_theme_size) { + XcursorSetDefaultSize(gfx::GetXDisplay(), cursor_theme_size); + ClearThemeCursors(); +} + +scoped_refptr<X11Cursor> X11CursorFactory::GetDefaultCursorInternal( + mojom::CursorType type) { + if (type == mojom::CursorType::kNone) + return invisible_cursor_; + + if (!default_cursors_.count(type)) { + // Try to load a predefined X11 cursor. + ::Cursor xcursor = LoadCursorFromType(type); + if (xcursor == x11::None) + return nullptr; + auto cursor = base::MakeRefCounted<X11Cursor>(xcursor); + default_cursors_[type] = cursor; + } + + // Returns owned default cursor for this type. + return default_cursors_[type]; +} + +void X11CursorFactory::ClearThemeCursors() { + default_cursors_.clear(); +} + +} // namespace ui diff --git a/chromium/ui/base/x/x11_cursor_factory.h b/chromium/ui/base/x/x11_cursor_factory.h new file mode 100644 index 00000000000..424511854ef --- /dev/null +++ b/chromium/ui/base/x/x11_cursor_factory.h @@ -0,0 +1,67 @@ +// Copyright 2016 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_X11_CURSOR_FACTORY_H_ +#define UI_BASE_X_X11_CURSOR_FACTORY_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/component_export.h" +#include "base/memory/scoped_refptr.h" +#include "base/scoped_observer.h" +#include "ui/base/cursor/cursor_factory.h" +#include "ui/base/cursor/cursor_theme_manager.h" +#include "ui/base/cursor/cursor_theme_manager_observer.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h" + +namespace ui { +class X11Cursor; + +// CursorFactoryOzone implementation for X11 cursors. +class COMPONENT_EXPORT(UI_BASE_X) X11CursorFactory + : public CursorFactory, + public CursorThemeManagerObserver { + public: + X11CursorFactory(); + X11CursorFactory(const X11CursorFactory&) = delete; + X11CursorFactory& operator=(const X11CursorFactory&) = delete; + ~X11CursorFactory() override; + + // CursorFactoryOzone: + base::Optional<PlatformCursor> GetDefaultCursor( + mojom::CursorType type) override; + PlatformCursor CreateImageCursor(const SkBitmap& bitmap, + const gfx::Point& hotspot) override; + PlatformCursor CreateAnimatedCursor(const std::vector<SkBitmap>& bitmaps, + const gfx::Point& hotspot, + int frame_delay_ms) override; + void RefImageCursor(PlatformCursor cursor) override; + void UnrefImageCursor(PlatformCursor cursor) override; + void ObserveThemeChanges() override; + + private: + // CusorThemeManagerObserver: + void OnCursorThemeNameChanged(const std::string& cursor_theme_name) override; + void OnCursorThemeSizeChanged(int cursor_theme_size) override; + + void ClearThemeCursors(); + + // Loads/caches default cursor or returns cached version. + scoped_refptr<X11Cursor> GetDefaultCursorInternal(mojom::CursorType type); + + // Holds a single instance of the invisible cursor. X11 has no way to hide + // the cursor so an invisible cursor mimics that. + scoped_refptr<X11Cursor> invisible_cursor_; + + std::map<mojom::CursorType, scoped_refptr<X11Cursor>> default_cursors_; + + ScopedObserver<CursorThemeManager, CursorThemeManagerObserver> + cursor_theme_observer_{this}; +}; + +} // namespace ui + +#endif // UI_BASE_X_X11_CURSOR_FACTORY_H_ diff --git a/chromium/ui/base/x/x11_cursor_factory_unittest.cc b/chromium/ui/base/x/x11_cursor_factory_unittest.cc new file mode 100644 index 00000000000..8c317fba402 --- /dev/null +++ b/chromium/ui/base/x/x11_cursor_factory_unittest.cc @@ -0,0 +1,32 @@ +// Copyright 2017 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/x11_cursor_factory.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/x/x11_cursor.h" +#include "ui/gfx/geometry/point.h" + +namespace ui { + +TEST(X11CursorFactoryTest, InvisibleRefcount) { + X11CursorFactory factory; + + // Building an image cursor with an invalid SkBitmap should return the + // invisible cursor in X11. The invisible cursor instance should have more + // than a single reference since the factory should hold a reference and + // CreateImageCursor should return an incremented refcount. + auto* invisible_cursor = static_cast<X11Cursor*>( + factory.CreateImageCursor(SkBitmap(), gfx::Point())); + ASSERT_FALSE(invisible_cursor->HasOneRef()); + + // Release our refcount on the cursor + factory.UnrefImageCursor(invisible_cursor); + + // The invisible cursor should still exist. + EXPECT_TRUE(invisible_cursor->HasOneRef()); +} + +} // namespace ui diff --git a/chromium/ui/base/x/x11_display_manager.cc b/chromium/ui/base/x/x11_display_manager.cc index 5d2475a3315..623d809dd02 100644 --- a/chromium/ui/base/x/x11_display_manager.cc +++ b/chromium/ui/base/x/x11_display_manager.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/threading/thread_task_runner_handle.h" #include "ui/base/x/x11_display_util.h" +#include "ui/gfx/x/randr.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" @@ -22,21 +23,22 @@ constexpr int kMinXrandrVersion = 103; // Need at least xrandr version 1.3 XDisplayManager::XDisplayManager(Delegate* delegate) : delegate_(delegate), - xdisplay_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(xdisplay_)), - xrandr_version_(GetXrandrVersion(xdisplay_)), + connection_(x11::Connection::Get()), + x_root_window_(connection_->default_screen().root), + xrandr_version_(GetXrandrVersion()), workspace_handler_(this) {} XDisplayManager::~XDisplayManager() = default; void XDisplayManager::Init() { if (IsXrandrAvailable()) { - int error_base_ignored = 0; - XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored); + auto& randr = connection_->randr(); + xrandr_event_base_ = randr.first_event(); - XRRSelectInput(xdisplay_, x_root_window_, - RRScreenChangeNotifyMask | RROutputChangeNotifyMask | - RRCrtcChangeNotifyMask); + randr.SelectInput( + {x_root_window_, x11::RandR::NotifyMask::ScreenChange | + x11::RandR::NotifyMask::OutputChange | + x11::RandR::NotifyMask::CrtcChange}); } FetchDisplayList(); } @@ -59,25 +61,25 @@ void XDisplayManager::RemoveObserver(display::DisplayObserver* observer) { change_notifier_.RemoveObserver(observer); } -bool XDisplayManager::CanProcessEvent(const XEvent& xev) { - return xev.type - xrandr_event_base_ == RRScreenChangeNotify || - xev.type - xrandr_event_base_ == RRNotify || +bool XDisplayManager::CanProcessEvent(const x11::Event& x11_event) { + const XEvent& xev = x11_event.xlib_event(); + return xev.type - xrandr_event_base_ == + x11::RandR::ScreenChangeNotifyEvent::opcode || + xev.type - xrandr_event_base_ == x11::RandR::NotifyEvent::opcode || (xev.type == PropertyNotify && - xev.xproperty.window == x_root_window_ && - xev.xproperty.atom == gfx::GetAtom("_NET_WORKAREA")); + static_cast<x11::Window>(xev.xproperty.window) == x_root_window_ && + xev.xproperty.atom == + static_cast<uint32_t>(gfx::GetAtom("_NET_WORKAREA"))); } -bool XDisplayManager::ProcessEvent(XEvent* xev) { - DCHECK(xev); +bool XDisplayManager::ProcessEvent(x11::Event* x11_event) { + DCHECK(x11_event); + XEvent* xev = &x11_event->xlib_event(); int ev_type = xev->type - xrandr_event_base_; - if (ev_type == RRScreenChangeNotify) { - // Pass the event through to xlib. - XRRUpdateConfiguration(xev); - return true; - } - if (ev_type == RRNotify || + if (ev_type == x11::RandR::NotifyEvent::opcode || (xev->type == PropertyNotify && - xev->xproperty.atom == gfx::GetAtom("_NET_WORKAREA"))) { + xev->xproperty.atom == + static_cast<uint32_t>(gfx::GetAtom("_NET_WORKAREA")))) { DispatchDelayedDisplayListUpdate(); return true; } @@ -123,13 +125,9 @@ void XDisplayManager::DispatchDelayedDisplayListUpdate() { } gfx::Point XDisplayManager::GetCursorLocation() const { - XID root, child; - int root_x, root_y, win_x, win_y; - unsigned int mask; - XQueryPointer(xdisplay_, x_root_window_, &root, &child, &root_x, &root_y, - &win_x, &win_y, &mask); - - return gfx::Point(root_x, root_y); + if (auto response = connection_->QueryPointer({x_root_window_}).Sync()) + return {response->root_x, response->root_y}; + return {}; } std::string XDisplayManager::GetCurrentWorkspace() { diff --git a/chromium/ui/base/x/x11_display_manager.h b/chromium/ui/base/x/x11_display_manager.h index 257467daef0..d638460ad1b 100644 --- a/chromium/ui/base/x/x11_display_manager.h +++ b/chromium/ui/base/x/x11_display_manager.h @@ -14,6 +14,7 @@ #include "ui/display/display.h" #include "ui/display/display_change_notifier.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11_types.h" namespace views { @@ -34,7 +35,7 @@ class X11ScreenOzoneTest; // Scale Factor information and simple hooks are delegated to API clients // through |XDisplayManager::Delegate| interface. To get notifications about // dynamic display changes, clients must register |DisplayObserver| instances -// and feed |XDisplayManager| with |XEvent|s. +// and feed |XDisplayManager| with |x11::Event|s. // // All bounds and size values are assumed to be expressed in pixels. class COMPONENT_EXPORT(UI_BASE_X) XDisplayManager @@ -47,8 +48,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XDisplayManager void Init(); bool IsXrandrAvailable() const; - bool CanProcessEvent(const XEvent& xev); - bool ProcessEvent(XEvent* xev); + bool CanProcessEvent(const x11::Event& xev); + bool ProcessEvent(x11::Event* xev); void UpdateDisplayList(); void DispatchDelayedDisplayListUpdate(); display::Display GetPrimaryDisplay() const; @@ -76,8 +77,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XDisplayManager std::vector<display::Display> displays_; display::DisplayChangeNotifier change_notifier_; - XDisplay* const xdisplay_; - XID x_root_window_; + x11::Connection* const connection_; + x11::Window x_root_window_; int64_t primary_display_index_ = 0; // XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present. diff --git a/chromium/ui/base/x/x11_display_util.cc b/chromium/ui/base/x/x11_display_util.cc index fe73b11b30d..0376b5ef9b3 100644 --- a/chromium/ui/base/x/x11_display_util.cc +++ b/chromium/ui/base/x/x11_display_util.cc @@ -18,6 +18,7 @@ #include "ui/gfx/geometry/matrix3_f.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/vector3d_f.h" +#include "ui/gfx/x/randr.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" @@ -27,32 +28,17 @@ namespace { constexpr int kMinVersionXrandr = 103; // Need at least xrandr version 1.3. -typedef XRRMonitorInfo* (*XRRGetMonitors)(::Display*, Window, bool, int*); -typedef void (*XRRFreeMonitors)(XRRMonitorInfo*); +constexpr const char kRandrEdidProperty[] = "EDID"; -NO_SANITIZE("cfi-icall") -std::map<RROutput, int> GetMonitors(int version, - XDisplay* xdisplay, - GLXWindow window) { - std::map<RROutput, int> output_to_monitor; +std::map<x11::RandR::Output, int> GetMonitors(int version, + x11::RandR* randr, + x11::Window window) { + std::map<x11::RandR::Output, int> output_to_monitor; if (version >= 105) { - void* xrandr_lib = dlopen(nullptr, RTLD_NOW); - if (xrandr_lib) { - static XRRGetMonitors XRRGetMonitors_ptr = - reinterpret_cast<XRRGetMonitors>(dlsym(xrandr_lib, "XRRGetMonitors")); - static XRRFreeMonitors XRRFreeMonitors_ptr = - reinterpret_cast<XRRFreeMonitors>( - dlsym(xrandr_lib, "XRRFreeMonitors")); - if (XRRGetMonitors_ptr && XRRFreeMonitors_ptr) { - int nmonitors = 0; - XRRMonitorInfo* monitors = - XRRGetMonitors_ptr(xdisplay, window, false, &nmonitors); - for (int monitor = 0; monitor < nmonitors; monitor++) { - for (int j = 0; j < monitors[monitor].noutput; j++) { - output_to_monitor[monitors[monitor].outputs[j]] = monitor; - } - } - XRRFreeMonitors_ptr(monitors); + if (auto reply = randr->GetMonitors({window}).Sync()) { + for (size_t monitor = 0; monitor < reply->monitors.size(); monitor++) { + for (x11::RandR::Output output : reply->monitors[monitor].outputs) + output_to_monitor[output] = monitor; } } } @@ -65,8 +51,7 @@ std::map<RROutput, int> GetMonitors(int version, void ClipWorkArea(std::vector<display::Display>* displays, int64_t primary_display_index, float scale) { - XDisplay* xdisplay = gfx::GetXDisplay(); - GLXWindow x_root_window = DefaultRootWindow(xdisplay); + x11::Window x_root_window = ui::GetX11RootWindow(); std::vector<int> value; if (!ui::GetIntArrayProperty(x_root_window, "_NET_WORKAREA", &value) || @@ -103,126 +88,89 @@ void ClipWorkArea(std::vector<display::Display>* displays, primary.set_work_area(work_area); } -float GetRefreshRateFromXRRModeInfo(XRRModeInfo* modes, - int num_of_mode, - RRMode current_mode_id) { - for (int i = 0; i < num_of_mode; i++) { - XRRModeInfo mode_info = modes[i]; - if (mode_info.id != current_mode_id) +float GetRefreshRateFromXRRModeInfo( + const std::vector<x11::RandR::ModeInfo>& modes, + x11::RandR::Mode current_mode_id) { + for (const auto& mode_info : modes) { + if (static_cast<x11::RandR::Mode>(mode_info.id) != current_mode_id) continue; - if (!mode_info.hTotal || !mode_info.vTotal) + if (!mode_info.htotal || !mode_info.vtotal) return 0; // Refresh Rate = Pixel Clock / (Horizontal Total * Vertical Total) - return mode_info.dotClock / - static_cast<float>(mode_info.hTotal * mode_info.vTotal); + return mode_info.dot_clock / + static_cast<float>(mode_info.htotal * mode_info.vtotal); } 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::VisualType& visual = connection->default_root_visual(); // The mask fields are only valid for DirectColor and TrueColor classes. - if (visual->c_class == DirectColor || visual->c_class == TrueColor) { + if (visual.c_class == x11::VisualClass::DirectColor || + visual.c_class == x11::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 + // |visual.{red,green,blue}_mask|. Count the number of bits to get the // number of bits per component. auto bits = [](auto mask) { return std::bitset<sizeof(mask) * 8>{mask}.count(); }; - size_t red_bits = bits(visual->red_mask); - size_t green_bits = bits(visual->green_mask); - size_t blue_bits = bits(visual->blue_mask); + size_t red_bits = bits(visual.red_mask); + size_t green_bits = bits(visual.green_mask); + size_t blue_bits = bits(visual.blue_mask); if (red_bits == green_bits && red_bits == blue_bits) return red_bits; } // 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; -} - -bool IsRandRAvailable() { - int randr_version_major = 0; - int randr_version_minor = 0; - static bool is_randr_available = XRRQueryVersion( - gfx::GetXDisplay(), &randr_version_major, &randr_version_minor); - return is_randr_available; + return visual.bits_per_rgb_value; } // Get the EDID data from the |output| and stores to |edid|. -void GetEDIDProperty(XID output, std::vector<uint8_t>* edid) { - if (!IsRandRAvailable()) - return; - - Display* display = gfx::GetXDisplay(); - - Atom edid_property = gfx::GetAtom(RR_PROPERTY_RANDR_EDID); - - bool has_edid_property = false; - int num_properties = 0; - gfx::XScopedPtr<Atom[]> properties( - XRRListOutputProperties(display, output, &num_properties)); - for (int i = 0; i < num_properties; ++i) { - if (properties[i] == edid_property) { - has_edid_property = true; - break; - } - } - if (!has_edid_property) - return; - - Atom actual_type; - int actual_format; - unsigned long bytes_after; - unsigned long nitems = 0; - unsigned char* prop = nullptr; - XRRGetOutputProperty(display, output, edid_property, - 0, // offset - 128, // length - false, // _delete - false, // pending - AnyPropertyType, // req_type - &actual_type, &actual_format, &nitems, &bytes_after, - &prop); - DCHECK_EQ(XA_INTEGER, actual_type); - DCHECK_EQ(8, actual_format); - edid->assign(prop, prop + nitems); - XFree(prop); +std::vector<uint8_t> GetEDIDProperty(x11::RandR* randr, + x11::RandR::Output output) { + auto future = randr->GetOutputProperty({ + .output = output, + .property = gfx::GetAtom(kRandrEdidProperty), + .long_length = 128, + }); + auto response = future.Sync(); + std::vector<uint8_t> edid; + if (response && response->format == 8 && response->type != x11::Atom::None) + edid = std::move(response->data); + return edid; } } // namespace -int GetXrandrVersion(XDisplay* xdisplay) { - int xrandr_version = 0; - // We only support 1.3+. There were library changes before this and we should - // use the new interface instead of the 1.2 one. - int randr_version_major = 0; - int randr_version_minor = 0; - if (XRRQueryVersion(xdisplay, &randr_version_major, &randr_version_minor)) { - xrandr_version = randr_version_major * 100 + randr_version_minor; - } - return xrandr_version; +int GetXrandrVersion() { + auto impl = []() -> int { + auto future = x11::Connection::Get()->randr().QueryVersion( + {x11::RandR::major_version, x11::RandR::minor_version}); + if (auto response = future.Sync()) + return response->major_version * 100 + response->minor_version; + return 0; + }; + static int version = impl(); + return version; } 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); @@ -236,8 +184,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); @@ -250,125 +198,129 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( int64_t* primary_display_index_out) { DCHECK(primary_display_index_out); DCHECK_GE(version, kMinVersionXrandr); - XDisplay* xdisplay = gfx::GetXDisplay(); - GLXWindow x_root_window = DefaultRootWindow(xdisplay); + auto* connection = x11::Connection::Get(); + auto& randr = connection->randr(); + auto x_root_window = static_cast<x11::Window>(ui::GetX11RootWindow()); std::vector<display::Display> displays; - gfx::XScopedPtr< - XRRScreenResources, - gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>> - resources(XRRGetScreenResourcesCurrent(xdisplay, x_root_window)); + auto resources = randr.GetScreenResourcesCurrent({x_root_window}).Sync(); if (!resources) { LOG(ERROR) << "XRandR returned no displays; falling back to root window"; return GetFallbackDisplayList(scale); } - const int depth = DefaultScreenDepth(xdisplay); - const int bits_per_component = DefaultBitsPerComponent(xdisplay); + const int depth = connection->default_screen().root_depth; + const int bits_per_component = DefaultBitsPerComponent(); - std::map<RROutput, int> output_to_monitor = - GetMonitors(version, xdisplay, x_root_window); + std::map<x11::RandR::Output, int> output_to_monitor = + GetMonitors(version, &randr, x_root_window); *primary_display_index_out = 0; - RROutput primary_display_id = XRRGetOutputPrimary(xdisplay, x_root_window); + auto output_primary = randr.GetOutputPrimary({x_root_window}).Sync(); + if (!output_primary) + return GetFallbackDisplayList(scale); + x11::RandR::Output primary_display_id = output_primary->output; int explicit_primary_display_index = -1; int monitor_order_primary_display_index = -1; // As per-display scale factor is not supported right now, // the X11 root window's scale factor is always used. - for (int i = 0; i < resources->noutput; ++i) { - RROutput output_id = resources->outputs[i]; - gfx::XScopedPtr<XRROutputInfo, - gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>> - output_info(XRRGetOutputInfo(xdisplay, resources.get(), output_id)); - - // XRRGetOutputInfo returns null in some cases: https://crbug.com/921490 + for (size_t i = 0; i < resources->outputs.size(); i++) { + x11::RandR::Output output_id = resources->outputs[i]; + auto output_info = + randr.GetOutputInfo({output_id, resources->config_timestamp}).Sync(); if (!output_info) continue; - bool is_connected = (output_info->connection == RR_Connected); - if (!is_connected) + if (output_info->connection != x11::RandR::RandRConnection::Connected) continue; bool is_primary_display = (output_id == primary_display_id); - if (output_info->crtc) { - gfx::XScopedPtr<XRRCrtcInfo, - gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>> - crtc(XRRGetCrtcInfo(xdisplay, resources.get(), output_info->crtc)); - - std::vector<uint8_t> edid_bytes; - GetEDIDProperty(output_id, &edid_bytes); - display::EdidParser edid_parser(edid_bytes); - int64_t display_id = edid_parser.GetDisplayId(output_id); - // It isn't ideal, but if we can't parse the EDID data, fall back on the - // display number. - if (!display_id) - display_id = i; - - gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height); - display::Display display(display_id, crtc_bounds); - - if (!display::Display::HasForceDeviceScaleFactor()) { - display.SetScaleAndBounds(scale, crtc_bounds); - display.set_work_area( - gfx::ScaleToEnclosingRect(crtc_bounds, 1.0f / scale)); - } - - switch (crtc->rotation) { - case RR_Rotate_0: - display.set_rotation(display::Display::ROTATE_0); - break; - case RR_Rotate_90: - display.set_rotation(display::Display::ROTATE_90); - break; - case RR_Rotate_180: - display.set_rotation(display::Display::ROTATE_180); - break; - case RR_Rotate_270: - display.set_rotation(display::Display::ROTATE_270); - break; - } + if (output_info->crtc == static_cast<x11::RandR::Crtc>(0)) + continue; - if (is_primary_display) - explicit_primary_display_index = displays.size(); + auto crtc = + randr.GetCrtcInfo({output_info->crtc, resources->config_timestamp}) + .Sync(); + if (!crtc) + continue; - auto monitor_iter = output_to_monitor.find(output_id); - if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0) - monitor_order_primary_display_index = displays.size(); + display::EdidParser edid_parser( + GetEDIDProperty(&randr, static_cast<x11::RandR::Output>(output_id))); + auto output_32 = static_cast<uint32_t>(output_id); + int64_t display_id = + output_32 > 0xff ? 0 : edid_parser.GetDisplayId(output_32); + // It isn't ideal, but if we can't parse the EDID data, fall back on the + // display number. + if (!display_id) + display_id = i; + + gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height); + display::Display display(display_id, crtc_bounds); + + if (!display::Display::HasForceDeviceScaleFactor()) { + display.SetScaleAndBounds(scale, crtc_bounds); + display.set_work_area( + gfx::ScaleToEnclosingRect(crtc_bounds, 1.0f / scale)); + } - if (!display::Display::HasForceDisplayColorProfile()) { - gfx::ICCProfile icc_profile = ui::GetICCProfileForMonitor( - monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second); - gfx::ColorSpace color_space = icc_profile.GetPrimariesOnlyColorSpace(); + switch (crtc->rotation) { + case x11::RandR::Rotation::Rotate_0: + display.set_rotation(display::Display::ROTATE_0); + break; + case x11::RandR::Rotation::Rotate_90: + display.set_rotation(display::Display::ROTATE_90); + break; + case x11::RandR::Rotation::Rotate_180: + display.set_rotation(display::Display::ROTATE_180); + break; + case x11::RandR::Rotation::Rotate_270: + display.set_rotation(display::Display::ROTATE_270); + break; + case x11::RandR::Rotation::Reflect_X: + case x11::RandR::Rotation::Reflect_Y: + NOTIMPLEMENTED(); + } - // Most folks do not have an ICC profile set up, but we still want to - // detect if a display has a wide color gamut so that HDR videos can be - // enabled. Only do this if |bits_per_component| > 8 or else SDR - // screens may have washed out colors. - if (bits_per_component > 8 && !color_space.IsValid()) - color_space = display::GetColorSpaceFromEdid(edid_parser); + if (is_primary_display) + explicit_primary_display_index = displays.size(); - display.set_color_spaces( - gfx::DisplayColorSpaces(color_space, gfx::BufferFormat::BGRA_8888)); - } + auto monitor_iter = + output_to_monitor.find(static_cast<x11::RandR::Output>(output_id)); + if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0) + monitor_order_primary_display_index = displays.size(); - display.set_color_depth(depth); - display.set_depth_per_component(bits_per_component); + if (!display::Display::HasForceDisplayColorProfile()) { + gfx::ICCProfile icc_profile = ui::GetICCProfileForMonitor( + monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second); + gfx::ColorSpace color_space = icc_profile.GetPrimariesOnlyColorSpace(); - // Set monitor refresh rate - int refresh_rate = static_cast<int>(GetRefreshRateFromXRRModeInfo( - resources->modes, resources->nmode, crtc->mode)); - display.set_display_frequency(refresh_rate); + // Most folks do not have an ICC profile set up, but we still want to + // detect if a display has a wide color gamut so that HDR videos can be + // enabled. Only do this if |bits_per_component| > 8 or else SDR + // screens may have washed out colors. + if (bits_per_component > 8 && !color_space.IsValid()) + color_space = display::GetColorSpaceFromEdid(edid_parser); - displays.push_back(display); + display.set_color_spaces( + gfx::DisplayColorSpaces(color_space, gfx::BufferFormat::BGRA_8888)); } + + display.set_color_depth(depth); + display.set_depth_per_component(bits_per_component); + + // Set monitor refresh rate + int refresh_rate = static_cast<int>( + GetRefreshRateFromXRRModeInfo(resources->modes, crtc->mode)); + display.set_display_frequency(refresh_rate); + + displays.push_back(display); } - if (explicit_primary_display_index != -1) { + if (explicit_primary_display_index != -1) *primary_display_index_out = explicit_primary_display_index; - } else if (monitor_order_primary_display_index != -1) { + else if (monitor_order_primary_display_index != -1) *primary_display_index_out = monitor_order_primary_display_index; - } if (displays.empty()) return GetFallbackDisplayList(scale); @@ -377,32 +329,33 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( return displays; } -base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display) { +base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr() { constexpr base::TimeDelta kDefaultInterval = base::TimeDelta::FromSecondsD(1. / 60); - GLXWindow root = DefaultRootWindow(display); - gfx::XScopedPtr< - XRRScreenResources, - gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>> - resources(XRRGetScreenResourcesCurrent(display, root)); + x11::RandR randr = x11::Connection::Get()->randr(); + auto root = static_cast<x11::Window>(ui::GetX11RootWindow()); + auto resources = randr.GetScreenResourcesCurrent({root}).Sync(); if (!resources) return kDefaultInterval; // TODO(crbug.com/726842): It might make sense here to pick the output that // the window is on. On the other hand, if compositing is enabled, all drawing // might be synced to the primary output anyway. Needs investigation. - RROutput primary_output = XRRGetOutputPrimary(display, root); + auto output_primary = randr.GetOutputPrimary({root}).Sync(); + if (!output_primary) + return kDefaultInterval; + x11::RandR::Output primary_output = output_primary->output; bool disconnected_primary = false; - for (int i = 0; i < resources->noutput; i++) { + for (size_t i = 0; i < resources->outputs.size(); i++) { if (!disconnected_primary && resources->outputs[i] != primary_output) continue; - gfx::XScopedPtr<XRROutputInfo, - gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>> - output_info(XRRGetOutputInfo(display, resources.get(), primary_output)); + auto output_info = + randr.GetOutputInfo({primary_output, resources->config_timestamp}) + .Sync(); if (!output_info) continue; - if (output_info->connection != RR_Connected) { + if (output_info->connection != x11::RandR::RandRConnection::Connected) { // If the primary monitor is disconnected, then start over and choose the // first connected monitor instead. if (!disconnected_primary) { @@ -411,13 +364,13 @@ base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display) { } continue; } - gfx::XScopedPtr<XRRCrtcInfo, - gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>> - crtc(XRRGetCrtcInfo(display, resources.get(), output_info->crtc)); + auto crtc = + randr.GetCrtcInfo({output_info->crtc, resources->config_timestamp}) + .Sync(); if (!crtc) continue; - float refresh_rate = GetRefreshRateFromXRRModeInfo( - resources->modes, resources->nmode, crtc->mode); + float refresh_rate = + GetRefreshRateFromXRRModeInfo(resources->modes, crtc->mode); if (refresh_rate == 0) continue; diff --git a/chromium/ui/base/x/x11_display_util.h b/chromium/ui/base/x/x11_display_util.h index 825d840bab7..7a128004483 100644 --- a/chromium/ui/base/x/x11_display_util.h +++ b/chromium/ui/base/x/x11_display_util.h @@ -16,7 +16,7 @@ namespace ui { // Return the version for xrandr. It multiplies the major number by 100 and // adds the minor like MAJOR * 100 + MINOR. It returns zero if no xrandr is // present. -COMPONENT_EXPORT(UI_BASE_X) int GetXrandrVersion(XDisplay* xdisplay); +COMPONENT_EXPORT(UI_BASE_X) int GetXrandrVersion(); // Builds a list of displays for fallback. COMPONENT_EXPORT(UI_BASE_X) @@ -33,7 +33,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( // Returns the refresh interval of the primary display. If there is no connected // primary display, returns the refresh interval of the first connected display. COMPONENT_EXPORT(UI_BASE_X) -base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display); +base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(); } // namespace ui diff --git a/chromium/ui/base/x/x11_drag_context.cc b/chromium/ui/base/x/x11_drag_context.cc index 3ed9e98b2a2..bdb6df1fd5c 100644 --- a/chromium/ui/base/x/x11_drag_context.cc +++ b/chromium/ui/base/x/x11_drag_context.cc @@ -4,11 +4,15 @@ #include "ui/base/x/x11_drag_context.h" +#include "base/logging.h" +#include "base/memory/ref_counted_memory.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/x/x11_drag_drop_client.h" #include "ui/base/x/x11_util.h" #include "ui/events/platform/platform_event_source.h" +#include "ui/gfx/x/connection.h" #include "ui/gfx/x/x11_atom_cache.h" +#include "ui/gfx/x/xproto.h" namespace ui { @@ -36,15 +40,15 @@ const char kChromiumDragReciever[] = "_CHROMIUM_DRAG_RECEIVER"; } // namespace -XDragContext::XDragContext(XID local_window, - const XClientMessageEvent& event, +XDragContext::XDragContext(x11::Window local_window, + const x11::ClientMessageEvent& event, XDragDropClient* source_client, const SelectionFormatMap& data) : local_window_(local_window), - source_window_(event.data.l[0]), + source_window_(static_cast<x11::Window>(event.data.data32[0])), source_client_(source_client) { if (!source_client_) { - bool get_types_from_property = ((event.data.l[1] & 1) != 0); + bool get_types_from_property = ((event.data.data32[1] & 1) != 0); if (get_types_from_property) { if (!GetAtomArrayProperty(source_window_, kXdndTypeList, @@ -54,20 +58,22 @@ XDragContext::XDragContext(XID local_window, } else { // data.l[2,3,4] contain the first three types. Unused slots can be None. for (size_t i = 2; i < 5; ++i) { - if (event.data.l[i] != x11::None) - unfetched_targets_.push_back(event.data.l[i]); + if (event.data.data32[i]) { + unfetched_targets_.push_back( + static_cast<x11::Atom>(event.data.data32[i])); + } } } #if DCHECK_IS_ON() DVLOG(1) << "XdndEnter has " << unfetched_targets_.size() << " data types"; - for (Atom target : unfetched_targets_) - DVLOG(1) << "XdndEnter data type: " << target; + for (x11::Atom target : unfetched_targets_) + DVLOG(1) << "XdndEnter data type: " << static_cast<uint32_t>(target); #endif // DCHECK_IS_ON() // We must perform a full sync here because we could be racing // |source_window_|. - XSync(gfx::GetXDisplay(), x11::False); + x11::Connection::Get()->Sync(); } else { // This drag originates from an aura window within our process. This means // that we can shortcut the X11 server and ask the owning SelectionOwner @@ -81,9 +87,9 @@ XDragContext::XDragContext(XID local_window, XDragContext::~XDragContext() = default; void XDragContext::OnXdndPositionMessage(XDragDropClient* client, - Atom suggested_action, - XID source_window, - Time time_stamp, + x11::Atom suggested_action, + x11::Window source_window, + x11::Time time_stamp, const gfx::Point& screen_point) { DCHECK_EQ(source_window_, source_window); suggested_action_ = suggested_action; @@ -108,15 +114,15 @@ void XDragContext::RequestNextTarget() { DCHECK(drag_drop_client_); DCHECK(waiting_to_handle_position_); - Atom target = unfetched_targets_.back(); + x11::Atom target = unfetched_targets_.back(); unfetched_targets_.pop_back(); - XConvertSelection(gfx::GetXDisplay(), gfx::GetAtom(kXdndSelection), target, - gfx::GetAtom(kChromiumDragReciever), local_window_, - position_time_stamp_); + x11::Connection::Get()->ConvertSelection( + {local_window_, gfx::GetAtom(kXdndSelection), target, + gfx::GetAtom(kChromiumDragReciever), position_time_stamp_}); } -void XDragContext::OnSelectionNotify(const XSelectionEvent& event) { +void XDragContext::OnSelectionNotify(const x11::SelectionNotifyEvent& event) { if (!waiting_to_handle_position_) { // A misbehaved window may send SelectionNotify without us requesting data // via XConvertSelection(). @@ -124,23 +130,24 @@ void XDragContext::OnSelectionNotify(const XSelectionEvent& event) { } DCHECK(drag_drop_client_); - DVLOG(1) << "SelectionNotify, format " << event.target; + DVLOG(1) << "SelectionNotify, format " << static_cast<uint32_t>(event.target); - if (event.property != x11::None) { - DCHECK_EQ(event.property, gfx::GetAtom(kChromiumDragReciever)); + auto property = static_cast<x11::Atom>(event.property); + auto target = static_cast<x11::Atom>(event.target); - scoped_refptr<base::RefCountedMemory> data; - Atom type = x11::None; - if (GetRawBytesOfProperty(local_window_, event.property, &data, nullptr, - &type)) { - fetched_targets_.Insert(event.target, data); - } + if (event.property != x11::Atom::None) { + DCHECK_EQ(property, gfx::GetAtom(kChromiumDragReciever)); + + std::vector<uint8_t> data; + x11::Atom type = x11::Atom::None; + if (GetRawBytesOfProperty(local_window_, property, &data, &type)) + fetched_targets_.Insert(target, base::RefCountedBytes::TakeVector(&data)); } else { // The source failed to convert the drop data to the format (target in X11 // parlance) that we asked for. This happens, even though we only ask for // the formats advertised by the source. http://crbug.com/628099 LOG(ERROR) << "XConvertSelection failed for source-advertised target " - << event.target; + << static_cast<uint32_t>(event.target); } if (!unfetched_targets_.empty()) { @@ -154,7 +161,7 @@ void XDragContext::OnSelectionNotify(const XSelectionEvent& event) { void XDragContext::ReadActions() { if (!source_client_) { - std::vector<Atom> atom_array; + std::vector<x11::Atom> atom_array; if (!GetAtomArrayProperty(source_window_, kXdndActionList, &atom_array)) actions_.clear(); else @@ -177,7 +184,7 @@ int XDragContext::GetDragOperation() const { return drag_operation; } -void XDragContext::MaskOperation(Atom xdnd_operation, +void XDragContext::MaskOperation(x11::Atom xdnd_operation, int* drag_operation) const { if (xdnd_operation == gfx::GetAtom(kXdndActionCopy)) *drag_operation |= DragDropTypes::DRAG_COPY; @@ -187,9 +194,9 @@ void XDragContext::MaskOperation(Atom xdnd_operation, *drag_operation |= DragDropTypes::DRAG_LINK; } -bool XDragContext::DispatchXEvent(XEvent* xev) { - if (xev->type == PropertyNotify && - xev->xproperty.atom == gfx::GetAtom(kXdndActionList)) { +bool XDragContext::DispatchPropertyNotifyEvent( + const x11::PropertyNotifyEvent& prop) { + if (prop.atom == gfx::GetAtom(kXdndActionList)) { ReadActions(); return true; } diff --git a/chromium/ui/base/x/x11_drag_context.h b/chromium/ui/base/x/x11_drag_context.h index 386ca2810e6..33cfea53651 100644 --- a/chromium/ui/base/x/x11_drag_context.h +++ b/chromium/ui/base/x/x11_drag_context.h @@ -12,7 +12,9 @@ #include "ui/base/x/selection_utils.h" #include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11.h" +#include "ui/gfx/x/xproto.h" namespace ui { @@ -20,8 +22,8 @@ class XDragDropClient; class COMPONENT_EXPORT(UI_BASE_X) XDragContext { public: - XDragContext(XID local_window, - const XClientMessageEvent& event, + XDragContext(x11::Window local_window, + const x11::ClientMessageEvent& event, XDragDropClient* source_client, const SelectionFormatMap& data); ~XDragContext(); @@ -29,7 +31,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragContext { XDragContext(const XDragContext&) = delete; XDragContext& operator=(const XDragContext&) = delete; - XID source_window() const { return source_window_; } + x11::Window source_window() const { return source_window_; } XDragDropClient* source_client() { return source_client_; } const SelectionFormatMap& fetched_targets() const { return fetched_targets_; } @@ -38,13 +40,13 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragContext { // message. If we have that data already, dispatch immediately. Otherwise, // delay dispatching until we do. void OnXdndPositionMessage(XDragDropClient* client, - Atom suggested_action, - XID source_window, - Time time_stamp, + x11::Atom suggested_action, + x11::Window source_window, + x11::Time time_stamp, const gfx::Point& screen_point); // Called when XSelection data has been copied to our process. - void OnSelectionNotify(const XSelectionEvent& xselection); + void OnSelectionNotify(const x11::SelectionNotifyEvent& xselection); // Reads the kXdndActionList property from |source_window_| and copies it // into |actions_|. @@ -54,7 +56,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragContext { // action list. int GetDragOperation() const; - bool DispatchXEvent(XEvent* event); + bool DispatchPropertyNotifyEvent(const x11::PropertyNotifyEvent& event); private: // Called to request the next target from the source window. This is only @@ -64,13 +66,13 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragContext { // Masks the X11 atom |xdnd_operation|'s views representation onto // |drag_operation|. - void MaskOperation(Atom xdnd_operation, int* drag_operation) const; + void MaskOperation(x11::Atom xdnd_operation, int* drag_operation) const; - // The XID of our chrome local aura window handling our events. - XID local_window_; + // The x11::Window of our chrome local aura window handling our events. + x11::Window local_window_; - // The XID of the window that initiated the drag. - XID source_window_; + // The x11::Window of the window that initiated the drag. + x11::Window source_window_; // The DesktopDragDropClientAuraX11 for |source_window_| if |source_window_| // belongs to a Chrome window. @@ -89,21 +91,21 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragContext { // The time stamp of the last XdndPosition event we received. The XDND // specification mandates that we use this time stamp when querying the source // about the drag and drop data. - Time position_time_stamp_; + x11::Time position_time_stamp_; // A SelectionFormatMap of data that we have in our process. SelectionFormatMap fetched_targets_; // The names of various data types offered by the other window that we // haven't fetched and put in |fetched_targets_| yet. - std::vector<Atom> unfetched_targets_; + std::vector<x11::Atom> unfetched_targets_; // XdndPosition messages have a suggested action. Qt applications exclusively // use this, instead of the XdndActionList which is backed by |actions_|. - Atom suggested_action_ = x11::None; + x11::Atom suggested_action_ = x11::Atom::None; // Possible actions. - std::vector<Atom> actions_; + std::vector<x11::Atom> actions_; }; } // namespace ui diff --git a/chromium/ui/base/x/x11_drag_drop_client.cc b/chromium/ui/base/x/x11_drag_drop_client.cc index 6329bd377f0..3eccf0b276d 100644 --- a/chromium/ui/base/x/x11_drag_drop_client.cc +++ b/chromium/ui/base/x/x11_drag_drop_client.cc @@ -5,11 +5,14 @@ #include "ui/base/x/x11_drag_drop_client.h" #include "base/lazy_instance.h" +#include "base/logging.h" #include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/x/x11_os_exchange_data_provider.h" #include "ui/base/x/x11_util.h" +#include "ui/gfx/x/connection.h" #include "ui/gfx/x/x11_atom_cache.h" +#include "ui/gfx/x/xproto.h" // Reading recommended for understanding the implementation in this file: // @@ -112,12 +115,12 @@ const char kXdndPosition[] = "XdndPosition"; // action will be taken if the drop is accepted. const char kXdndStatus[] = "XdndStatus"; -static base::LazyInstance<std::map<XID, XDragDropClient*>>::Leaky +static base::LazyInstance<std::map<x11::Window, XDragDropClient*>>::Leaky g_live_client_map = LAZY_INSTANCE_INITIALIZER; // Converts a bitfield of actions into an Atom that represents what action // we're most likely to take on drop. -Atom XDragOperationToAtom(int drag_operation) { +x11::Atom XDragOperationToAtom(int drag_operation) { if (drag_operation & DragDropTypes::DRAG_COPY) return gfx::GetAtom(kXdndActionCopy); if (drag_operation & DragDropTypes::DRAG_MOVE) @@ -125,11 +128,11 @@ Atom XDragOperationToAtom(int drag_operation) { if (drag_operation & DragDropTypes::DRAG_LINK) return gfx::GetAtom(kXdndActionLink); - return x11::None; + return x11::Atom::None; } // Converts a single action atom to a drag operation. -DragDropTypes::DragOperation XAtomToDragOperation(Atom atom) { +DragDropTypes::DragOperation AtomToDragOperation(x11::Atom atom) { if (atom == gfx::GetAtom(kXdndActionCopy)) return DragDropTypes::DRAG_COPY; if (atom == gfx::GetAtom(kXdndActionMove)) @@ -143,34 +146,34 @@ DragDropTypes::DragOperation XAtomToDragOperation(Atom atom) { } // namespace int XGetMaskAsEventFlags() { - XDisplay* display = gfx::GetXDisplay(); + x11::KeyButMask mask{}; + auto* connection = x11::Connection::Get(); + if (auto reply = + connection->QueryPointer({connection->default_root()}).Sync()) { + mask = reply->mask; + } - XID root, child; - int root_x, root_y, win_x, win_y; - unsigned int mask; - XQueryPointer(display, DefaultRootWindow(display), &root, &child, &root_x, - &root_y, &win_x, &win_y, &mask); int modifiers = ui::EF_NONE; - if (mask & ShiftMask) + if (static_cast<bool>(mask & x11::KeyButMask::Shift)) modifiers |= ui::EF_SHIFT_DOWN; - if (mask & ControlMask) + if (static_cast<bool>(mask & x11::KeyButMask::Control)) modifiers |= ui::EF_CONTROL_DOWN; - if (mask & Mod1Mask) + if (static_cast<bool>(mask & x11::KeyButMask::Mod1)) modifiers |= ui::EF_ALT_DOWN; - if (mask & Mod4Mask) + if (static_cast<bool>(mask & x11::KeyButMask::Mod4)) modifiers |= ui::EF_COMMAND_DOWN; - if (mask & Button1Mask) + if (static_cast<bool>(mask & x11::KeyButMask::Button1)) modifiers |= ui::EF_LEFT_MOUSE_BUTTON; - if (mask & Button2Mask) + if (static_cast<bool>(mask & x11::KeyButMask::Button2)) modifiers |= ui::EF_MIDDLE_MOUSE_BUTTON; - if (mask & Button3Mask) + if (static_cast<bool>(mask & x11::KeyButMask::Button3)) modifiers |= ui::EF_RIGHT_MOUSE_BUTTON; return modifiers; } // static -XDragDropClient* XDragDropClient::GetForWindow(XID window) { - std::map<XID, XDragDropClient*>::const_iterator it = +XDragDropClient* XDragDropClient::GetForWindow(x11::Window window) { + std::map<x11::Window, XDragDropClient*>::const_iterator it = g_live_client_map.Get().find(window); if (it == g_live_client_map.Get().end()) return nullptr; @@ -178,16 +181,14 @@ XDragDropClient* XDragDropClient::GetForWindow(XID window) { } XDragDropClient::XDragDropClient(XDragDropClient::Delegate* delegate, - Display* xdisplay, - XID xwindow) - : delegate_(delegate), xdisplay_(xdisplay), xwindow_(xwindow) { + x11::Window xwindow) + : delegate_(delegate), xwindow_(xwindow) { DCHECK(delegate_); // Mark that we are aware of drag and drop concepts. - unsigned long xdnd_version = kMaxXdndVersion; - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom(kXdndAware), XA_ATOM, 32, - PropModeReplace, - reinterpret_cast<unsigned char*>(&xdnd_version), 1); + uint32_t xdnd_version = kMaxXdndVersion; + ui::SetProperty(xwindow_, gfx::GetAtom(kXdndAware), x11::Atom::ATOM, + xdnd_version); // Some tests change the DesktopDragDropClientAuraX11 associated with an // |xwindow|. @@ -198,8 +199,8 @@ XDragDropClient::~XDragDropClient() { g_live_client_map.Get().erase(xwindow()); } -std::vector<Atom> XDragDropClient::GetOfferedDragOperations() const { - std::vector<Atom> operations; +std::vector<x11::Atom> XDragDropClient::GetOfferedDragOperations() const { + std::vector<x11::Atom> operations; if (drag_operation_ & DragDropTypes::DRAG_COPY) operations.push_back(gfx::GetAtom(kXdndActionCopy)); if (drag_operation_ & DragDropTypes::DRAG_MOVE) @@ -209,7 +210,7 @@ std::vector<Atom> XDragDropClient::GetOfferedDragOperations() const { return operations; } -void XDragDropClient::CompleteXdndPosition(XID source_window, +void XDragDropClient::CompleteXdndPosition(x11::Window source_window, const gfx::Point& screen_point) { int drag_operation = delegate_->UpdateDrag(screen_point); @@ -219,11 +220,12 @@ void XDragDropClient::CompleteXdndPosition(XID source_window, // actually making use of this. A client can return (0, 0) and/or set the // first bit of l[1] to disable the feature, and it appears that gtk neither // sets this nor respects it if set. - XEvent xev = PrepareXdndClientMessage(kXdndStatus, source_window); - xev.xclient.data.l[1] = + auto xev = PrepareXdndClientMessage(kXdndStatus, source_window); + xev.data.data32[1] = (drag_operation != 0) ? (kWantFurtherPosEvents | kWillAcceptDrop) : 0; - xev.xclient.data.l[4] = XDragOperationToAtom(drag_operation); - SendXClientEvent(source_window, &xev); + xev.data.data32[4] = + static_cast<uint32_t>(XDragOperationToAtom(drag_operation)); + SendXClientEvent(source_window, xev); } void XDragDropClient::ProcessMouseMove(const gfx::Point& screen_point, @@ -232,26 +234,26 @@ void XDragDropClient::ProcessMouseMove(const gfx::Point& screen_point, return; // Find the current window the cursor is over. - XID dest_window = FindWindowFor(screen_point); + x11::Window dest_window = FindWindowFor(screen_point); - if (source_current_window_ != dest_window) { - if (source_current_window_ != x11::None) - SendXdndLeave(source_current_window_); + if (target_current_window_ != dest_window) { + if (target_current_window_ != x11::Window::None) + SendXdndLeave(target_current_window_); - source_current_window_ = dest_window; + target_current_window_ = dest_window; waiting_on_status_ = false; next_position_message_.reset(); status_received_since_enter_ = false; negotiated_operation_ = DragDropTypes::DRAG_NONE; - if (source_current_window_ != x11::None) { - std::vector<Atom> targets; + if (target_current_window_ != x11::Window::None) { + std::vector<x11::Atom> targets; source_provider_->RetrieveTargets(&targets); - SendXdndEnter(source_current_window_, targets); + SendXdndEnter(target_current_window_, targets); } } - if (source_current_window_ != x11::None) { + if (target_current_window_ != x11::Window::None) { if (waiting_on_status_) { next_position_message_ = std::make_unique<std::pair<gfx::Point, unsigned long>>(screen_point, @@ -262,30 +264,30 @@ void XDragDropClient::ProcessMouseMove(const gfx::Point& screen_point, } } -bool XDragDropClient::HandleXdndEvent(const XClientMessageEvent& event) { - Atom message_type = event.message_type; - if (message_type == gfx::GetAtom("XdndEnter")) { +bool XDragDropClient::HandleXdndEvent(const x11::ClientMessageEvent& event) { + x11::Atom message_type = event.type; + if (message_type == gfx::GetAtom("XdndEnter")) OnXdndEnter(event); - } else if (message_type == gfx::GetAtom("XdndLeave")) { + else if (message_type == gfx::GetAtom("XdndLeave")) OnXdndLeave(event); - } else if (message_type == gfx::GetAtom("XdndPosition")) { + else if (message_type == gfx::GetAtom("XdndPosition")) OnXdndPosition(event); - } else if (message_type == gfx::GetAtom("XdndStatus")) { + else if (message_type == gfx::GetAtom("XdndStatus")) OnXdndStatus(event); - } else if (message_type == gfx::GetAtom("XdndFinished")) { + else if (message_type == gfx::GetAtom("XdndFinished")) OnXdndFinished(event); - } else if (message_type == gfx::GetAtom("XdndDrop")) { + else if (message_type == gfx::GetAtom("XdndDrop")) OnXdndDrop(event); - } else { + else return false; - } return true; } -void XDragDropClient::OnXdndEnter(const XClientMessageEvent& event) { - DVLOG(1) << "OnXdndEnter, version " << ((event.data.l[1] & 0xff000000) >> 24); +void XDragDropClient::OnXdndEnter(const x11::ClientMessageEvent& event) { + DVLOG(1) << "OnXdndEnter, version " + << ((event.data.data32[1] & 0xff000000) >> 24); - int version = (event.data.l[1] & 0xff000000) >> 24; + int version = (event.data.data32[1] & 0xff000000) >> 24; if (version < kMinXdndVersion) { // This protocol version is not documented in the XDND standard (last // revised in 1999), so we don't support it. Since don't understand the @@ -303,7 +305,8 @@ void XDragDropClient::OnXdndEnter(const XClientMessageEvent& event) { // Make sure that we've run ~X11DragContext() before creating another one. ResetDragContext(); - auto* source_client = GetForWindow(event.data.l[0]); + auto* source_client = + GetForWindow(static_cast<x11::Window>(event.data.data32[0])); DCHECK(!source_client || source_client->source_provider_); target_current_context_ = std::make_unique<XDragContext>( xwindow_, event, source_client, @@ -313,7 +316,8 @@ void XDragDropClient::OnXdndEnter(const XClientMessageEvent& event) { if (!target_current_context()->source_client()) { // The window doesn't have a DesktopDragDropClientAuraX11, which means it's // created by some other process. Listen for messages on it. - delegate_->OnBeginForeignDrag(event.data.l[0]); + delegate_->OnBeginForeignDrag( + static_cast<x11::Window>(event.data.data32[0])); } // In the Windows implementation, we immediately call DesktopDropTargetWin:: @@ -322,14 +326,14 @@ void XDragDropClient::OnXdndEnter(const XClientMessageEvent& event) { // XdndStatus message. } -void XDragDropClient::OnXdndPosition(const XClientMessageEvent& event) { +void XDragDropClient::OnXdndPosition(const x11::ClientMessageEvent& event) { DVLOG(1) << "OnXdndPosition"; - XID source_window = event.data.l[0]; - int x_root_window = event.data.l[2] >> 16; - int y_root_window = event.data.l[2] & 0xffff; - Time time_stamp = event.data.l[3]; - Atom suggested_action = event.data.l[4]; + auto source_window = static_cast<x11::Window>(event.data.data32[0]); + int x_root_window = event.data.data32[2] >> 16; + int y_root_window = event.data.data32[2] & 0xffff; + x11::Time time_stamp = static_cast<x11::Time>(event.data.data32[3]); + x11::Atom suggested_action = static_cast<x11::Atom>(event.data.data32[4]); if (!target_current_context()) { NOTREACHED(); @@ -341,12 +345,12 @@ void XDragDropClient::OnXdndPosition(const XClientMessageEvent& event) { gfx::Point(x_root_window, y_root_window)); } -void XDragDropClient::OnXdndStatus(const XClientMessageEvent& event) { +void XDragDropClient::OnXdndStatus(const x11::ClientMessageEvent& event) { DVLOG(1) << "OnXdndStatus"; - XID source_window = event.data.l[0]; + auto source_window = static_cast<x11::Window>(event.data.data32[0]); - if (source_window != source_current_window_) + if (source_window != target_current_window_) return; if (source_state_ != SourceState::kPendingDrop && @@ -357,9 +361,9 @@ void XDragDropClient::OnXdndStatus(const XClientMessageEvent& event) { waiting_on_status_ = false; status_received_since_enter_ = true; - if (event.data.l[1] & 1) { - Atom atom_operation = event.data.l[4]; - negotiated_operation_ = XAtomToDragOperation(atom_operation); + if (event.data.data32[1] & 1) { + x11::Atom atom_operation = static_cast<x11::Atom>(event.data.data32[4]); + negotiated_operation_ = AtomToDragOperation(atom_operation); } else { negotiated_operation_ = DragDropTypes::DRAG_NONE; } @@ -394,53 +398,55 @@ void XDragDropClient::OnXdndStatus(const XClientMessageEvent& event) { } } -void XDragDropClient::OnXdndLeave(const XClientMessageEvent& event) { +void XDragDropClient::OnXdndLeave(const x11::ClientMessageEvent& event) { DVLOG(1) << "OnXdndLeave"; delegate_->OnBeforeDragLeave(); ResetDragContext(); } -void XDragDropClient::OnXdndDrop(const XClientMessageEvent& event) { +void XDragDropClient::OnXdndDrop(const x11::ClientMessageEvent& event) { DVLOG(1) << "OnXdndDrop"; - XID source_window = event.data.l[0]; + auto source_window = static_cast<x11::Window>(event.data.data32[0]); int drag_operation = delegate_->PerformDrop(); - XEvent xev = PrepareXdndClientMessage(kXdndFinished, source_window); - xev.xclient.data.l[1] = (drag_operation != 0) ? 1 : 0; - xev.xclient.data.l[2] = XDragOperationToAtom(drag_operation); - SendXClientEvent(source_window, &xev); + auto xev = PrepareXdndClientMessage(kXdndFinished, source_window); + xev.data.data32[1] = (drag_operation != 0) ? 1 : 0; + xev.data.data32[2] = + static_cast<uint32_t>(XDragOperationToAtom(drag_operation)); + SendXClientEvent(source_window, xev); } -void XDragDropClient::OnXdndFinished(const XClientMessageEvent& event) { +void XDragDropClient::OnXdndFinished(const x11::ClientMessageEvent& event) { DVLOG(1) << "OnXdndFinished"; - XID source_window = event.data.l[0]; - if (source_current_window_ != source_window) + auto source_window = static_cast<x11::Window>(event.data.data32[0]); + if (target_current_window_ != source_window) return; // Clear |negotiated_operation_| if the drag was rejected. - if ((event.data.l[1] & 1) == 0) + if ((event.data.data32[1] & 1) == 0) negotiated_operation_ = DragDropTypes::DRAG_NONE; - // Clear |source_current_window_| to avoid sending XdndLeave upon ending the + // Clear |target_current_window_| to avoid sending XdndLeave upon ending the // move loop. - source_current_window_ = x11::None; + target_current_window_ = x11::Window::None; EndMoveLoop(); } -void XDragDropClient::OnSelectionNotify(const XSelectionEvent& xselection) { +void XDragDropClient::OnSelectionNotify( + const x11::SelectionNotifyEvent& xselection) { DVLOG(1) << "OnSelectionNotify"; if (target_current_context_) target_current_context_->OnSelectionNotify(xselection); // ICCCM requires us to delete the property passed into SelectionNotify. - if (xselection.property != x11::None) - XDeleteProperty(xdisplay_, xwindow_, xselection.property); + if (xselection.property != x11::Atom::None) + ui::DeleteProperty(xwindow_, xselection.property); } void XDragDropClient::InitDrag(int operation, const OSExchangeData* data) { - source_current_window_ = x11::None; + target_current_window_ = x11::Window::None; source_state_ = SourceState::kOther; waiting_on_status_ = false; next_position_message_.reset(); @@ -452,7 +458,7 @@ void XDragDropClient::InitDrag(int operation, const OSExchangeData* data) { static_cast<const XOSExchangeDataProvider*>(&data->provider()); source_provider_->TakeOwnershipOfSelection(); - std::vector<Atom> actions = GetOfferedDragOperations(); + std::vector<x11::Atom> actions = GetOfferedDragOperations(); if (!source_provider_->file_contents_name().empty()) { actions.push_back(gfx::GetAtom(kXdndActionDirectSave)); SetStringProperty(xwindow_, gfx::GetAtom(kXdndDirectSave0), @@ -464,8 +470,8 @@ void XDragDropClient::InitDrag(int operation, const OSExchangeData* data) { void XDragDropClient::CleanupDrag() { source_provider_ = nullptr; - XDeleteProperty(xdisplay_, xwindow_, gfx::GetAtom(kXdndActionList)); - XDeleteProperty(xdisplay_, xwindow_, gfx::GetAtom(kXdndDirectSave0)); + ui::DeleteProperty(xwindow_, gfx::GetAtom(kXdndActionList)); + ui::DeleteProperty(xwindow_, gfx::GetAtom(kXdndDirectSave0)); } void XDragDropClient::UpdateModifierState(int flags) { @@ -516,7 +522,7 @@ void XDragDropClient::HandleMouseReleased() { return; } - if (source_current_window_ != x11::None) { + if (target_current_window_ != x11::Window::None) { if (waiting_on_status_) { if (status_received_since_enter_) { // If we are waiting for an XdndStatus message, we need to wait for it @@ -543,8 +549,12 @@ void XDragDropClient::HandleMouseReleased() { // We have negotiated an action with the other end. source_state_ = SourceState::kDropped; - SendXdndDrop(source_current_window_); + SendXdndDrop(target_current_window_); return; + } else { + // No transfer is negotiated. We need to tell the target window that we + // are leaving. + SendXdndLeave(target_current_window_); } } @@ -552,36 +562,33 @@ void XDragDropClient::HandleMouseReleased() { } void XDragDropClient::HandleMoveLoopEnded() { - if (source_current_window_ != x11::None) { - SendXdndLeave(source_current_window_); - source_current_window_ = x11::None; + if (target_current_window_ != x11::Window::None) { + SendXdndLeave(target_current_window_); + target_current_window_ = x11::Window::None; } ResetDragContext(); StopRepeatMouseMoveTimer(); StopEndMoveLoopTimer(); } -XEvent XDragDropClient::PrepareXdndClientMessage(const char* message, - XID recipient) const { - XEvent xev; - xev.xclient.type = ClientMessage; - xev.xclient.message_type = gfx::GetAtom(message); - xev.xclient.format = 32; - xev.xclient.window = recipient; - xev.xclient.data.l[0] = xwindow_; - xev.xclient.data.l[1] = 0; - xev.xclient.data.l[2] = 0; - xev.xclient.data.l[3] = 0; - xev.xclient.data.l[4] = 0; +x11::ClientMessageEvent XDragDropClient::PrepareXdndClientMessage( + const char* message, + x11::Window recipient) const { + x11::ClientMessageEvent xev; + xev.type = gfx::GetAtom(message); + xev.window = recipient; + xev.format = 32; + xev.data.data32.fill(0); + xev.data.data32[0] = static_cast<uint32_t>(xwindow_); return xev; } -XID XDragDropClient::FindWindowFor(const gfx::Point& screen_point) { +x11::Window XDragDropClient::FindWindowFor(const gfx::Point& screen_point) { auto finder = delegate_->CreateWindowFinder(); - XID target = finder->FindWindowAt(screen_point); + x11::Window target = finder->FindWindowAt(screen_point); - if (target == x11::None) - return x11::None; + if (target == x11::Window::None) + return x11::Window::None; // TODO(crbug/651775): The proxy window should be reported separately from the // target window. XDND messages should be sent to the proxy, and their @@ -590,22 +597,21 @@ XID XDragDropClient::FindWindowFor(const gfx::Point& screen_point) { // Figure out which window we should test as XdndAware. If |target| has // XdndProxy, it will set that proxy on target, and if not, |target|'s // original value will remain. - GetXIDProperty(target, kXdndProxy, &target); + GetProperty(target, gfx::GetAtom(kXdndProxy), &target); int version; if (GetIntProperty(target, kXdndAware, &version) && version >= kMaxXdndVersion) { return target; } - return x11::None; + return x11::Window::None; } -void XDragDropClient::SendXClientEvent(XID xid, XEvent* xev) { - DCHECK_EQ(ClientMessage, xev->type); - +void XDragDropClient::SendXClientEvent(x11::Window window, + const x11::ClientMessageEvent& xev) { // Don't send messages to the X11 message queue if we can help it. - XDragDropClient* short_circuit = GetForWindow(xid); - if (short_circuit && short_circuit->HandleXdndEvent(xev->xclient)) + XDragDropClient* short_circuit = GetForWindow(window); + if (short_circuit && short_circuit->HandleXdndEvent(xev)) return; // I don't understand why the GTK+ code is doing what it's doing here. It @@ -617,36 +623,37 @@ void XDragDropClient::SendXClientEvent(XID xid, XEvent* xev) { // // I'm unsure if I have to jump through those hoops, or if XSendEvent is // sufficient. - XSendEvent(xdisplay_, xid, x11::False, 0, xev); + ui::SendEvent(xev, window, x11::EventMask::NoEvent); } -void XDragDropClient::SendXdndEnter(XID dest_window, - const std::vector<Atom>& targets) { - XEvent xev = PrepareXdndClientMessage(kXdndEnter, dest_window); - xev.xclient.data.l[1] = (kMaxXdndVersion << 24); // The version number. +void XDragDropClient::SendXdndEnter(x11::Window dest_window, + const std::vector<x11::Atom>& targets) { + auto xev = PrepareXdndClientMessage(kXdndEnter, dest_window); + xev.data.data32[1] = (kMaxXdndVersion << 24); // The version number. if (targets.size() > 3) { - xev.xclient.data.l[1] |= 1; + xev.data.data32[1] |= 1; SetAtomArrayProperty(xwindow(), kXdndTypeList, "ATOM", targets); } else { // Pack the targets into the enter message. for (size_t i = 0; i < targets.size(); ++i) - xev.xclient.data.l[2 + i] = targets[i]; + xev.data.data32[2 + i] = static_cast<uint32_t>(targets[i]); } - SendXClientEvent(dest_window, &xev); + SendXClientEvent(dest_window, xev); } -void XDragDropClient::SendXdndPosition(XID dest_window, +void XDragDropClient::SendXdndPosition(x11::Window dest_window, const gfx::Point& screen_point, unsigned long event_time) { waiting_on_status_ = true; - XEvent xev = PrepareXdndClientMessage(kXdndPosition, dest_window); - xev.xclient.data.l[2] = (screen_point.x() << 16) | screen_point.y(); - xev.xclient.data.l[3] = event_time; - xev.xclient.data.l[4] = XDragOperationToAtom(drag_operation_); - SendXClientEvent(dest_window, &xev); + auto xev = PrepareXdndClientMessage(kXdndPosition, dest_window); + xev.data.data32[2] = (screen_point.x() << 16) | screen_point.y(); + xev.data.data32[3] = event_time; + xev.data.data32[4] = + static_cast<uint32_t>(XDragOperationToAtom(drag_operation_)); + SendXClientEvent(dest_window, xev); // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html and // the Xdnd protocol both recommend that drag events should be sent @@ -657,20 +664,20 @@ void XDragDropClient::SendXdndPosition(XID dest_window, screen_point, event_time)); } -void XDragDropClient::SendXdndLeave(XID dest_window) { - XEvent xev = PrepareXdndClientMessage(kXdndLeave, dest_window); - SendXClientEvent(dest_window, &xev); +void XDragDropClient::SendXdndLeave(x11::Window dest_window) { + auto xev = PrepareXdndClientMessage(kXdndLeave, dest_window); + SendXClientEvent(dest_window, xev); } -void XDragDropClient::SendXdndDrop(XID dest_window) { - XEvent xev = PrepareXdndClientMessage(kXdndDrop, dest_window); - xev.xclient.data.l[2] = x11::CurrentTime; - SendXClientEvent(dest_window, &xev); +void XDragDropClient::SendXdndDrop(x11::Window dest_window) { + auto xev = PrepareXdndClientMessage(kXdndDrop, dest_window); + xev.data.data32[2] = x11::CurrentTime; + SendXClientEvent(dest_window, xev); } void XDragDropClient::EndMoveLoop() { StopEndMoveLoopTimer(); - delegate_->EndMoveLoop(); + delegate_->EndDragLoop(); } } // namespace ui diff --git a/chromium/ui/base/x/x11_drag_drop_client.h b/chromium/ui/base/x/x11_drag_drop_client.h index 9a0df14cf71..1d7e6a32caf 100644 --- a/chromium/ui/base/x/x11_drag_drop_client.h +++ b/chromium/ui/base/x/x11_drag_drop_client.h @@ -15,6 +15,7 @@ #include "ui/base/x/x11_topmost_window_finder.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/x/x11.h" +#include "ui/gfx/x/xproto.h" namespace ui { @@ -49,7 +50,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient { DragDropTypes::DragOperation negotiated_operation) = 0; // Called when data from another application enters the window. - virtual void OnBeginForeignDrag(XID window) = 0; + virtual void OnBeginForeignDrag(x11::Window window) = 0; // Called when data from another application is about to leave the window. virtual void OnEndForeignDrag() = 0; @@ -60,19 +61,19 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient { // Drops data at the current location and returns the resulting operation. virtual int PerformDrop() = 0; - // Called to end the move loop that is maintained by the subclass. - virtual void EndMoveLoop() = 0; + // Called to end the drag loop that is maintained by the subclass. + virtual void EndDragLoop() = 0; protected: virtual ~Delegate() = default; }; - XDragDropClient(Delegate* delegate, Display* xdisplay, XID xwindow); + XDragDropClient(Delegate* delegate, x11::Window xwindow); virtual ~XDragDropClient(); XDragDropClient(const XDragDropClient&) = delete; XDragDropClient& operator=(const XDragDropClient&) = delete; - XID xwindow() const { return xwindow_; } + x11::Window xwindow() const { return xwindow_; } XDragContext* target_current_context() { return target_current_context_.get(); } @@ -84,7 +85,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient { // Handling XdndPosition can be paused while waiting for more data; this is // called either synchronously from OnXdndPosition, or asynchronously after // we've received data requested from the other window. - void CompleteXdndPosition(XID source_window, const gfx::Point& screen_point); + void CompleteXdndPosition(x11::Window source_window, + const gfx::Point& screen_point); void ProcessMouseMove(const gfx::Point& screen_point, unsigned long event_time); @@ -92,12 +94,12 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient { // During the blocking StartDragAndDrop() call, this converts the views-style // |drag_operation_| bitfield into a vector of Atoms to offer to other // processes. - std::vector<Atom> GetOfferedDragOperations() const; + std::vector<x11::Atom> GetOfferedDragOperations() const; // Tries to handle the XDND event. Returns true for all known event types: // XdndEnter, XdndLeave, XdndPosition, XdndStatus, XdndDrop, and XdndFinished; // returns false if an event of an unexpected type has been passed. - bool HandleXdndEvent(const XClientMessageEvent& event); + bool HandleXdndEvent(const x11::ClientMessageEvent& event); // These |Handle...| methods essentially implement the // views::X11MoveLoopDelegate interface. @@ -108,7 +110,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient { void HandleMoveLoopEnded(); // Called when XSelection data has been copied to our process. - void OnSelectionNotify(const XSelectionEvent& xselection); + void OnSelectionNotify(const x11::SelectionNotifyEvent& xselection); // Resets the drag state so the object is ready to handle the drag. Sets // X window properties so that the desktop environment is aware of available @@ -156,53 +158,54 @@ class COMPONENT_EXPORT(UI_BASE_X) XDragDropClient { private: // These methods handle the various X11 client messages from the platform. - void OnXdndEnter(const XClientMessageEvent& event); - void OnXdndPosition(const XClientMessageEvent& event); - void OnXdndStatus(const XClientMessageEvent& event); - void OnXdndLeave(const XClientMessageEvent& event); - void OnXdndDrop(const XClientMessageEvent& event); - void OnXdndFinished(const XClientMessageEvent& event); + void OnXdndEnter(const x11::ClientMessageEvent& event); + void OnXdndPosition(const x11::ClientMessageEvent& event); + void OnXdndStatus(const x11::ClientMessageEvent& event); + void OnXdndLeave(const x11::ClientMessageEvent& event); + void OnXdndDrop(const x11::ClientMessageEvent& event); + void OnXdndFinished(const x11::ClientMessageEvent& event); // Creates an XEvent and fills it in with values typical for XDND messages: // the type of event is set to ClientMessage, the format is set to 32 (longs), // and the zero member of data payload is set to |xwindow_|. All other data // members are zeroed, as per XDND specification. - XEvent PrepareXdndClientMessage(const char* message, XID recipient) const; + x11::ClientMessageEvent PrepareXdndClientMessage(const char* message, + x11::Window recipient) const; // Finds the topmost X11 window at |screen_point| and returns it if it is // Xdnd aware. Returns x11::None otherwise. // Virtual for testing. - virtual XID FindWindowFor(const gfx::Point& screen_point); + virtual x11::Window FindWindowFor(const gfx::Point& screen_point); - // Sends |xev| to |xid|, optionally short circuiting the round trip to the X - // server. - // Virtual for testing. - virtual void SendXClientEvent(XID xid, XEvent* xev); + // Sends |xev| to |window|, optionally short circuiting the round trip to the + // X server. Virtual for testing. + virtual void SendXClientEvent(x11::Window window, + const x11::ClientMessageEvent& xev); - void SendXdndEnter(XID dest_window, const std::vector<Atom>& targets); - void SendXdndPosition(XID dest_window, + void SendXdndEnter(x11::Window dest_window, + const std::vector<x11::Atom>& targets); + void SendXdndPosition(x11::Window dest_window, const gfx::Point& screen_point, unsigned long event_time); - void SendXdndLeave(XID dest_window); - void SendXdndDrop(XID dest_window); + void SendXdndLeave(x11::Window dest_window); + void SendXdndDrop(x11::Window dest_window); // We maintain a mapping of live XDragDropClient objects to their X11 windows, // so that we'd able to short circuit sending X11 messages to windows in our // process. - static XDragDropClient* GetForWindow(XID window); + static XDragDropClient* GetForWindow(x11::Window window); void EndMoveLoop(); Delegate* const delegate_; - Display* const xdisplay_; - const XID xwindow_; + const x11::Window xwindow_; // Target side information. + x11::Window target_current_window_ = x11::Window::None; std::unique_ptr<XDragContext> target_current_context_; // Source side information. - XID source_current_window_ = x11::None; SourceState source_state_ = SourceState::kOther; const XOSExchangeDataProvider* source_provider_ = nullptr; diff --git a/chromium/ui/base/x/x11_error_handler.cc b/chromium/ui/base/x/x11_error_handler.cc new file mode 100644 index 00000000000..d1babb0bcbd --- /dev/null +++ b/chromium/ui/base/x/x11_error_handler.cc @@ -0,0 +1,104 @@ +// 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/x11_error_handler.h" + +#include "base/check.h" +#include "base/compiler_specific.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/message_loop/message_loop_current.h" +#include "base/sequenced_task_runner.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "ui/base/x/x11_util.h" +#include "ui/base/x/x11_util_internal.h" +#include "ui/gfx/x/xproto_util.h" + +namespace ui { + +namespace { + +// Indicates that we're currently responding to an IO error (by shutting down). +bool g_in_x11_io_error_handler = false; + +base::LazyInstance<base::OnceClosure>::Leaky g_shutdown_cb = + LAZY_INSTANCE_INITIALIZER; + +// Number of seconds to wait for UI thread to get an IO error if we get it on +// the background thread. +const int kWaitForUIThreadSeconds = 10; + +int BrowserX11ErrorHandler(Display* d, XErrorEvent* error) { + if (!g_in_x11_io_error_handler) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&x11::LogErrorEventDescription, *error)); + } + return 0; +} + +// This function is used to help us diagnose crash dumps that happen +// during the shutdown process. +NOINLINE void WaitingForUIThreadToHandleIOError() { + // Ensure function isn't optimized away. + asm(""); + sleep(kWaitForUIThreadSeconds); +} + +int BrowserX11IOErrorHandler(Display* d) { + if (!base::MessageLoopCurrentForUI::IsSet()) { + // Wait for the UI thread (which has a different connection to the X server) + // to get the error. We can't call shutdown from this thread without + // tripping an error. Doing it through a function so that we'll be able + // to see it in any crash dumps. + WaitingForUIThreadToHandleIOError(); + return 0; + } + + // If there's an IO error it likely means the X server has gone away. + // If this CHECK fails, then that means SessionEnding() below triggered some + // code that tried to talk to the X server, resulting in yet another error. + CHECK(!g_in_x11_io_error_handler); + + g_in_x11_io_error_handler = true; + LOG(ERROR) << "X IO error received (X server probably went away)"; + DCHECK(!g_shutdown_cb.Get().is_null()); + std::move(g_shutdown_cb.Get()).Run(); + + return 0; +} + +int X11EmptyErrorHandler(Display* d, XErrorEvent* error) { + return 0; +} + +int X11EmptyIOErrorHandler(Display* d) { + return 0; +} + +} // namespace + +void SetNullErrorHandlers() { + // Installs the X11 error handlers for the browser process used during + // startup. They simply print error messages and exit because + // we can't shutdown properly while creating and initializing services. + ui::SetX11ErrorHandlers(nullptr, nullptr); +} + +void SetErrorHandlers(base::OnceCallback<void()> shutdown_cb) { + // Installs the X11 error handlers for the browser process after the + // main message loop has started. This will allow us to exit cleanly + // if X exits before we do. + DCHECK(g_shutdown_cb.Get().is_null()); + g_shutdown_cb.Get() = std::move(shutdown_cb); + ui::SetX11ErrorHandlers(BrowserX11ErrorHandler, BrowserX11IOErrorHandler); +} + +void SetEmptyErrorHandlers() { + // Unset the X11 error handlers. The X11 error handlers log the errors using a + // |PostTask()| on the message-loop. But since the message-loop is in the + // process of terminating, this can cause errors. + ui::SetX11ErrorHandlers(X11EmptyErrorHandler, X11EmptyIOErrorHandler); +} + +} // namespace ui diff --git a/chromium/ui/base/x/x11_error_handler.h b/chromium/ui/base/x/x11_error_handler.h new file mode 100644 index 00000000000..49011beb3d8 --- /dev/null +++ b/chromium/ui/base/x/x11_error_handler.h @@ -0,0 +1,26 @@ +// 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_X11_ERROR_HANDLER_H_ +#define UI_BASE_X_X11_ERROR_HANDLER_H_ + +#include "base/callback.h" +#include "base/component_export.h" + +namespace ui { + +// Sets null error handlers that just catch error messages. +COMPONENT_EXPORT(UI_BASE_X) void SetNullErrorHandlers(); + +// Sets error handlers that catch the error messages on ui thread, waits until +// errors are received on io thread, and stops the browser. +COMPONENT_EXPORT(UI_BASE_X) +void SetErrorHandlers(base::OnceCallback<void()> shutdown_cb); + +// Unsets the error handlers. +COMPONENT_EXPORT(UI_BASE_X) void SetEmptyErrorHandlers(); + +} // namespace ui + +#endif // UI_BASE_X_X11_ERROR_HANDLER_H_ diff --git a/chromium/ui/base/x/x11_gl_egl_utility.cc b/chromium/ui/base/x/x11_gl_egl_utility.cc index 2a7fd03779f..197f8e4c553 100644 --- a/chromium/ui/base/x/x11_gl_egl_utility.cc +++ b/chromium/ui/base/x/x11_gl_egl_utility.cc @@ -25,11 +25,11 @@ void GetPlatformExtraDisplayAttribs(EGLenum platform_type, // ANGLE_NULL doesn't use the visual, and may run without X11 where we can't // get it anyway. if (platform_type != EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE) { - Visual* visual; - ui::XVisualManager::GetInstance()->ChooseVisualForWindow( - true, &visual, nullptr, nullptr, nullptr); + x11::VisualId visual_id; + ui::XVisualManager::GetInstance()->ChooseVisualForWindow(true, &visual_id, + nullptr, nullptr); attributes->push_back(EGL_X11_VISUAL_ID_ANGLE); - attributes->push_back(static_cast<EGLAttrib>(XVisualIDFromVisual(visual))); + attributes->push_back(static_cast<EGLAttrib>(visual_id)); } } @@ -38,8 +38,10 @@ void ChoosePlatformCustomAlphaAndBufferSize(EGLint* alpha_size, // If we're using ANGLE_NULL, we may not have a display, in which case we // can't use XVisualManager. if (gl::GLSurfaceEGL::GetNativeDisplay() != EGL_DEFAULT_DISPLAY) { - ui::XVisualManager::GetInstance()->ChooseVisualForWindow( - true, nullptr, buffer_size, nullptr, nullptr); + uint8_t depth; + ui::XVisualManager::GetInstance()->ChooseVisualForWindow(true, nullptr, + &depth, nullptr); + *buffer_size = depth; *alpha_size = *buffer_size == 32 ? 8 : 0; } } diff --git a/chromium/ui/base/x/x11_menu_list.cc b/chromium/ui/base/x/x11_menu_list.cc index 83a5522437b..5cea1a41421 100644 --- a/chromium/ui/base/x/x11_menu_list.cc +++ b/chromium/ui/base/x/x11_menu_list.cc @@ -24,23 +24,23 @@ XMenuList::~XMenuList() { menus_.clear(); } -void XMenuList::MaybeRegisterMenu(XID menu) { +void XMenuList::MaybeRegisterMenu(x11::Window menu) { int value = 0; if (!GetIntProperty(menu, "_NET_WM_WINDOW_TYPE", &value) || - static_cast<XAtom>(value) != menu_type_atom_) { + static_cast<x11::Atom>(value) != menu_type_atom_) { return; } menus_.push_back(menu); } -void XMenuList::MaybeUnregisterMenu(XID menu) { +void XMenuList::MaybeUnregisterMenu(x11::Window menu) { auto iter = std::find(menus_.begin(), menus_.end(), menu); if (iter == menus_.end()) return; menus_.erase(iter); } -void XMenuList::InsertMenuWindowXIDs(std::vector<XID>* stack) { +void XMenuList::InsertMenuWindows(std::vector<x11::Window>* stack) { stack->insert(stack->begin(), menus_.begin(), menus_.end()); } diff --git a/chromium/ui/base/x/x11_menu_list.h b/chromium/ui/base/x/x11_menu_list.h index f4882b8dcb0..8f45b83e50d 100644 --- a/chromium/ui/base/x/x11_menu_list.h +++ b/chromium/ui/base/x/x11_menu_list.h @@ -13,7 +13,8 @@ // A process wide singleton cache for X menus. namespace base { -template <typename T> struct DefaultSingletonTraits; +template <typename T> +struct DefaultSingletonTraits; } namespace ui { @@ -25,21 +26,21 @@ class COMPONENT_EXPORT(UI_BASE_X) XMenuList { // Checks if |menu| has _NET_WM_WINDOW_TYPE property set to // "_NET_WM_WINDOW_TYPE_MENU" atom and if so caches it. - void MaybeRegisterMenu(XID menu); + void MaybeRegisterMenu(x11::Window menu); // Finds |menu| in cache and if found removes it. - void MaybeUnregisterMenu(XID menu); + void MaybeUnregisterMenu(x11::Window menu); - // Inserts cached menu XIDs at the beginning of |stack|. - void InsertMenuWindowXIDs(std::vector<XID>* stack); + // Inserts cached menu x11::Windows at the beginning of |stack|. + void InsertMenuWindows(std::vector<x11::Window>* stack); private: friend struct base::DefaultSingletonTraits<XMenuList>; XMenuList(); ~XMenuList(); - std::vector<XID> menus_; - XAtom menu_type_atom_; + std::vector<x11::Window> menus_; + x11::Atom menu_type_atom_; DISALLOW_COPY_AND_ASSIGN(XMenuList); }; diff --git a/chromium/ui/base/x/x11_menu_registrar.cc b/chromium/ui/base/x/x11_menu_registrar.cc index 2d1d23ff714..2264b4b465b 100644 --- a/chromium/ui/base/x/x11_menu_registrar.cc +++ b/chromium/ui/base/x/x11_menu_registrar.cc @@ -32,8 +32,7 @@ X11MenuRegistrar* X11MenuRegistrar::Get() { } X11MenuRegistrar::X11MenuRegistrar() - : xdisplay_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(xdisplay_)) { + : xdisplay_(gfx::GetXDisplay()), x_root_window_(ui::GetX11RootWindow()) { if (ui::X11EventSource::HasInstance()) ui::X11EventSource::GetInstance()->AddXEventDispatcher(this); @@ -46,16 +45,19 @@ X11MenuRegistrar::~X11MenuRegistrar() { ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this); } -bool X11MenuRegistrar::DispatchXEvent(XEvent* event) { +bool X11MenuRegistrar::DispatchXEvent(x11::Event* x11_event) { + XEvent* event = &x11_event->xlib_event(); if (event->type != CreateNotify && event->type != DestroyNotify) { return false; } switch (event->type) { case CreateNotify: - OnWindowCreatedOrDestroyed(event->type, event->xcreatewindow.window); + OnWindowCreatedOrDestroyed( + event->type, x11_event->As<x11::CreateNotifyEvent>()->window); break; case DestroyNotify: - OnWindowCreatedOrDestroyed(event->type, event->xdestroywindow.window); + OnWindowCreatedOrDestroyed( + event->type, x11_event->As<x11::DestroyNotifyEvent>()->window); break; default: NOTREACHED(); @@ -63,7 +65,8 @@ bool X11MenuRegistrar::DispatchXEvent(XEvent* event) { return false; } -void X11MenuRegistrar::OnWindowCreatedOrDestroyed(int event_type, XID window) { +void X11MenuRegistrar::OnWindowCreatedOrDestroyed(int event_type, + x11::Window window) { // Menus created by Chrome can be drag and drop targets. Since they are // direct children of the screen root window and have override_redirect // we cannot use regular _NET_CLIENT_LIST_STACKING property to find them diff --git a/chromium/ui/base/x/x11_menu_registrar.h b/chromium/ui/base/x/x11_menu_registrar.h index b3a30a24167..0fe0a83e727 100644 --- a/chromium/ui/base/x/x11_menu_registrar.h +++ b/chromium/ui/base/x/x11_menu_registrar.h @@ -12,6 +12,7 @@ #include <vector> #include "ui/events/platform/x11/x11_event_source.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_types.h" @@ -29,7 +30,7 @@ class X11MenuRegistrar : public ui::XEventDispatcher { static X11MenuRegistrar* Get(); // ui::XEventDispatcher - bool DispatchXEvent(XEvent* event) override; + bool DispatchXEvent(x11::Event* event) override; private: X11MenuRegistrar(); @@ -37,13 +38,13 @@ class X11MenuRegistrar : public ui::XEventDispatcher { // Called when |window| has been created or destroyed. |window| may not be // managed by Chrome. - void OnWindowCreatedOrDestroyed(int event_type, XID window); + void OnWindowCreatedOrDestroyed(int event_type, x11::Window window); // The display and the native X window hosting the root window. XDisplay* xdisplay_; // The native root window. - ::Window x_root_window_; + x11::Window x_root_window_; // Events selected on |x_root_window_|. std::unique_ptr<ui::XScopedEventSelector> x_root_window_events_; diff --git a/chromium/ui/base/x/x11_os_exchange_data_provider.cc b/chromium/ui/base/x/x11_os_exchange_data_provider.cc index 88a24bab57b..5a38c3f841b 100644 --- a/chromium/ui/base/x/x11_os_exchange_data_provider.cc +++ b/chromium/ui/base/x/x11_os_exchange_data_provider.cc @@ -15,6 +15,7 @@ #include "ui/base/clipboard/clipboard_format_type.h" #include "ui/base/dragdrop/file_info/file_info.h" #include "ui/base/x/selection_utils.h" +#include "ui/base/x/x11_util.h" #include "ui/gfx/x/x11_atom_cache.h" // Note: the GetBlah() methods are used immediately by the @@ -34,38 +35,25 @@ const char kNetscapeURL[] = "_NETSCAPE_URL"; } // namespace XOSExchangeDataProvider::XOSExchangeDataProvider( - XID x_window, + x11::Window x_window, const SelectionFormatMap& selection) - : x_display_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(x_display_)), + : connection_(x11::Connection::Get()), + x_root_window_(ui::GetX11RootWindow()), own_window_(false), x_window_(x_window), format_map_(selection), - selection_owner_(x_display_, x_window_, gfx::GetAtom(kDndSelection)) {} + selection_owner_(connection_, x_window_, gfx::GetAtom(kDndSelection)) {} XOSExchangeDataProvider::XOSExchangeDataProvider() - : x_display_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(x_display_)), + : connection_(x11::Connection::Get()), + x_root_window_(ui::GetX11RootWindow()), own_window_(true), - x_window_(XCreateWindow(x_display_, - x_root_window_, - -100, // x - -100, // y - 10, // width - 10, // height - 0, // border width - CopyFromParent, // depth - InputOnly, - CopyFromParent, // visual - 0, - nullptr)), - selection_owner_(x_display_, x_window_, gfx::GetAtom(kDndSelection)) { - XStoreName(x_display_, x_window_, "Chromium Drag & Drop Window"); -} + x_window_(CreateDummyWindow("Chromium Drag & Drop Window")), + selection_owner_(connection_, x_window_, gfx::GetAtom(kDndSelection)) {} XOSExchangeDataProvider::~XOSExchangeDataProvider() { if (own_window_) - XDestroyWindow(x_display_, x_window_); + connection_->DestroyWindow({x_window_}); } void XOSExchangeDataProvider::TakeOwnershipOfSelection() const { @@ -73,7 +61,7 @@ void XOSExchangeDataProvider::TakeOwnershipOfSelection() const { } void XOSExchangeDataProvider::RetrieveTargets( - std::vector<Atom>* targets) const { + std::vector<x11::Atom>* targets) const { selection_owner_.RetrieveTargets(targets); } @@ -159,7 +147,7 @@ void XOSExchangeDataProvider::SetURL(const GURL& url, void XOSExchangeDataProvider::SetFilename(const base::FilePath& path) { std::vector<FileInfo> data; - data.push_back(FileInfo(path, base::FilePath())); + data.emplace_back(path, base::FilePath()); SetFilenames(data); } @@ -199,8 +187,8 @@ bool XOSExchangeDataProvider::GetString(base::string16* result) const { return false; } - std::vector<Atom> text_atoms = ui::GetTextAtomsFrom(); - std::vector<Atom> requested_types; + std::vector<x11::Atom> text_atoms = ui::GetTextAtomsFrom(); + std::vector<x11::Atom> requested_types; GetAtomIntersection(text_atoms, GetTargets(), &requested_types); ui::SelectionData data(format_map_.GetFirstOf(requested_types)); @@ -216,8 +204,8 @@ bool XOSExchangeDataProvider::GetString(base::string16* result) const { bool XOSExchangeDataProvider::GetURLAndTitle(FilenameToURLPolicy policy, GURL* url, base::string16* title) const { - std::vector<Atom> url_atoms = ui::GetURLAtomsFrom(); - std::vector<Atom> requested_types; + std::vector<x11::Atom> url_atoms = ui::GetURLAtomsFrom(); + std::vector<x11::Atom> requested_types; GetAtomIntersection(url_atoms, GetTargets(), &requested_types); ui::SelectionData data(format_map_.GetFirstOf(requested_types)); @@ -247,7 +235,8 @@ bool XOSExchangeDataProvider::GetURLAndTitle(FilenameToURLPolicy policy, std::vector<std::string> tokens = ui::ParseURIList(data); for (const std::string& token : tokens) { GURL test_url(token); - if (!test_url.SchemeIsFile() || policy == CONVERT_FILENAMES) { + if (!test_url.SchemeIsFile() || + policy == FilenameToURLPolicy::CONVERT_FILENAMES) { *url = test_url; *title = base::string16(); return true; @@ -271,8 +260,8 @@ bool XOSExchangeDataProvider::GetFilename(base::FilePath* path) const { bool XOSExchangeDataProvider::GetFilenames( std::vector<FileInfo>* filenames) const { - std::vector<Atom> url_atoms = ui::GetURIListAtomsFrom(); - std::vector<Atom> requested_types; + std::vector<x11::Atom> url_atoms = ui::GetURIListAtomsFrom(); + std::vector<x11::Atom> requested_types; GetAtomIntersection(url_atoms, GetTargets(), &requested_types); filenames->clear(); @@ -293,7 +282,7 @@ bool XOSExchangeDataProvider::GetFilenames( bool XOSExchangeDataProvider::GetPickledData(const ClipboardFormatType& format, base::Pickle* pickle) const { - std::vector<Atom> requested_types; + std::vector<x11::Atom> requested_types; requested_types.push_back(gfx::GetAtom(format.GetName().c_str())); ui::SelectionData data(format_map_.GetFirstOf(requested_types)); @@ -309,15 +298,15 @@ bool XOSExchangeDataProvider::GetPickledData(const ClipboardFormatType& format, } bool XOSExchangeDataProvider::HasString() const { - std::vector<Atom> text_atoms = ui::GetTextAtomsFrom(); - std::vector<Atom> requested_types; + std::vector<x11::Atom> text_atoms = ui::GetTextAtomsFrom(); + std::vector<x11::Atom> requested_types; GetAtomIntersection(text_atoms, GetTargets(), &requested_types); return !requested_types.empty() && !HasFile(); } bool XOSExchangeDataProvider::HasURL(FilenameToURLPolicy policy) const { - std::vector<Atom> url_atoms = ui::GetURLAtomsFrom(); - std::vector<Atom> requested_types; + std::vector<x11::Atom> url_atoms = ui::GetURLAtomsFrom(); + std::vector<x11::Atom> requested_types; GetAtomIntersection(url_atoms, GetTargets(), &requested_types); if (requested_types.empty()) @@ -333,7 +322,8 @@ bool XOSExchangeDataProvider::HasURL(FilenameToURLPolicy policy) const { } else if (data.GetType() == gfx::GetAtom(ui::kMimeTypeURIList)) { std::vector<std::string> tokens = ui::ParseURIList(data); for (const std::string& token : tokens) { - if (!GURL(token).SchemeIsFile() || policy == CONVERT_FILENAMES) + if (!GURL(token).SchemeIsFile() || + policy == FilenameToURLPolicy::CONVERT_FILENAMES) return true; } @@ -345,8 +335,8 @@ bool XOSExchangeDataProvider::HasURL(FilenameToURLPolicy policy) const { } bool XOSExchangeDataProvider::HasFile() const { - std::vector<Atom> url_atoms = ui::GetURIListAtomsFrom(); - std::vector<Atom> requested_types; + std::vector<x11::Atom> url_atoms = ui::GetURIListAtomsFrom(); + std::vector<x11::Atom> requested_types; GetAtomIntersection(url_atoms, GetTargets(), &requested_types); if (requested_types.empty()) @@ -371,9 +361,9 @@ bool XOSExchangeDataProvider::HasFile() const { bool XOSExchangeDataProvider::HasCustomFormat( const ClipboardFormatType& format) const { - std::vector<Atom> url_atoms; + std::vector<x11::Atom> url_atoms; url_atoms.push_back(gfx::GetAtom(format.GetName().c_str())); - std::vector<Atom> requested_types; + std::vector<x11::Atom> requested_types; GetAtomIntersection(url_atoms, GetTargets(), &requested_types); return !requested_types.empty(); @@ -395,9 +385,9 @@ void XOSExchangeDataProvider::SetHtml(const base::string16& html, bool XOSExchangeDataProvider::GetHtml(base::string16* html, GURL* base_url) const { - std::vector<Atom> url_atoms; + std::vector<x11::Atom> url_atoms; url_atoms.push_back(gfx::GetAtom(kMimeTypeHTML)); - std::vector<Atom> requested_types; + std::vector<x11::Atom> requested_types; GetAtomIntersection(url_atoms, GetTargets(), &requested_types); ui::SelectionData data(format_map_.GetFirstOf(requested_types)); @@ -411,9 +401,9 @@ bool XOSExchangeDataProvider::GetHtml(base::string16* html, } bool XOSExchangeDataProvider::HasHtml() const { - std::vector<Atom> url_atoms; + std::vector<x11::Atom> url_atoms; url_atoms.push_back(gfx::GetAtom(kMimeTypeHTML)); - std::vector<Atom> requested_types; + std::vector<x11::Atom> requested_types; GetAtomIntersection(url_atoms, GetTargets(), &requested_types); return !requested_types.empty(); @@ -446,12 +436,12 @@ bool XOSExchangeDataProvider::GetPlainTextURL(GURL* url) const { return false; } -std::vector<Atom> XOSExchangeDataProvider::GetTargets() const { +std::vector<x11::Atom> XOSExchangeDataProvider::GetTargets() const { return format_map_.GetTypes(); } void XOSExchangeDataProvider::InsertData( - Atom format, + x11::Atom format, const scoped_refptr<base::RefCountedMemory>& data) { format_map_.Insert(format, data); } diff --git a/chromium/ui/base/x/x11_os_exchange_data_provider.h b/chromium/ui/base/x/x11_os_exchange_data_provider.h index 6763eb0aea7..214bf950ba1 100644 --- a/chromium/ui/base/x/x11_os_exchange_data_provider.h +++ b/chromium/ui/base/x/x11_os_exchange_data_provider.h @@ -33,7 +33,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XOSExchangeDataProvider public: // |x_window| is the window the cursor is over, and |selection| is the set of // data being offered. - XOSExchangeDataProvider(XID x_window, const SelectionFormatMap& selection); + XOSExchangeDataProvider(x11::Window x_window, + const SelectionFormatMap& selection); // Creates a Provider for sending drag information. This creates its own, // hidden X11 window to own send data. @@ -50,7 +51,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XOSExchangeDataProvider // Retrieves a list of types we're offering. Noop if we haven't taken the // selection. - void RetrieveTargets(std::vector<Atom>* targets) const; + void RetrieveTargets(std::vector<x11::Atom>* targets) const; // Makes a copy of the format map currently being offered. SelectionFormatMap GetFormatMap() const; @@ -97,7 +98,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XOSExchangeDataProvider using PickleData = std::map<ClipboardFormatType, base::Pickle>; bool own_window() const { return own_window_; } - XID x_window() const { return x_window_; } + x11::Window x_window() const { return x_window_; } const SelectionFormatMap& format_map() const { return format_map_; } void set_format_map(const SelectionFormatMap& format_map) { format_map_ = format_map; @@ -112,10 +113,10 @@ class COMPONENT_EXPORT(UI_BASE_X) XOSExchangeDataProvider bool GetPlainTextURL(GURL* url) const; // Returns the targets in |format_map_|. - std::vector<Atom> GetTargets() const; + std::vector<x11::Atom> GetTargets() const; // Inserts data into the format map. - void InsertData(Atom format, + void InsertData(x11::Atom format, const scoped_refptr<base::RefCountedMemory>& data); private: @@ -124,8 +125,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XOSExchangeDataProvider gfx::Vector2d drag_image_offset_; // Our X11 state. - Display* x_display_; - XID x_root_window_; + x11::Connection* connection_; + x11::Window x_root_window_; // In X11, because the IPC parts of drag operations are implemented by // XSelection, we require an x11 window to receive drag messages on. The @@ -135,7 +136,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XOSExchangeDataProvider // our own xwindow just to receive events on it. const bool own_window_; - XID x_window_; + x11::Window x_window_; // A representation of data. This is either passed to us from the other // process, or built up through a sequence of Set*() calls. It can be passed diff --git a/chromium/ui/base/x/x11_pointer_grab.cc b/chromium/ui/base/x/x11_pointer_grab.cc index 01c0efb666b..b7a65240c02 100644 --- a/chromium/ui/base/x/x11_pointer_grab.cc +++ b/chromium/ui/base/x/x11_pointer_grab.cc @@ -14,14 +14,14 @@ namespace ui { namespace { // The grab window. None if there are no active pointer grabs. -XID g_grab_window = x11::None; +x11::Window g_grab_window = x11::Window::None; // The "owner events" parameter used to grab the pointer. bool g_owner_events = false; } // namespace -int GrabPointer(XID window, bool owner_events, ::Cursor cursor) { +int GrabPointer(x11::Window window, bool owner_events, ::Cursor cursor) { int result = GrabInvalidTime; if (ui::IsXInput2Available()) { // Do an XInput2 pointer grab. If there is an active XInput2 pointer grab @@ -42,9 +42,10 @@ int GrabPointer(XID window, bool owner_events, ::Cursor cursor) { ui::DeviceDataManagerX11::GetInstance()->master_pointers(); for (int master_pointer : master_pointers) { evmask.deviceid = master_pointer; - result = XIGrabDevice(gfx::GetXDisplay(), master_pointer, window, - x11::CurrentTime, cursor, GrabModeAsync, - GrabModeAsync, owner_events, &evmask); + result = + XIGrabDevice(gfx::GetXDisplay(), master_pointer, + static_cast<uint32_t>(window), x11::CurrentTime, cursor, + GrabModeAsync, GrabModeAsync, owner_events, &evmask); // Assume that the grab will succeed on either all or none of the master // pointers. if (result != GrabSuccess) { @@ -56,9 +57,9 @@ int GrabPointer(XID window, bool owner_events, ::Cursor cursor) { if (result != GrabSuccess) { int event_mask = PointerMotionMask | ButtonReleaseMask | ButtonPressMask; - result = XGrabPointer(gfx::GetXDisplay(), window, owner_events, event_mask, - GrabModeAsync, GrabModeAsync, x11::None, cursor, - x11::CurrentTime); + result = XGrabPointer(gfx::GetXDisplay(), static_cast<uint32_t>(window), + owner_events, event_mask, GrabModeAsync, + GrabModeAsync, x11::None, cursor, x11::CurrentTime); } if (result == GrabSuccess) { @@ -69,12 +70,12 @@ int GrabPointer(XID window, bool owner_events, ::Cursor cursor) { } void ChangeActivePointerGrabCursor(::Cursor cursor) { - DCHECK(g_grab_window != x11::None); + DCHECK(g_grab_window != x11::Window::None); GrabPointer(g_grab_window, g_owner_events, cursor); } void UngrabPointer() { - g_grab_window = x11::None; + g_grab_window = x11::Window::None; if (ui::IsXInput2Available()) { const std::vector<int>& master_pointers = ui::DeviceDataManagerX11::GetInstance()->master_pointers(); diff --git a/chromium/ui/base/x/x11_pointer_grab.h b/chromium/ui/base/x/x11_pointer_grab.h index 9f34e28193c..8df814098e3 100644 --- a/chromium/ui/base/x/x11_pointer_grab.h +++ b/chromium/ui/base/x/x11_pointer_grab.h @@ -15,7 +15,7 @@ namespace ui { // Grabs the pointer. It is unnecessary to ungrab the pointer prior to grabbing // it. COMPONENT_EXPORT(UI_BASE_X) -int GrabPointer(XID window, bool owner_events, ::Cursor cursor); +int GrabPointer(x11::Window window, bool owner_events, ::Cursor cursor); // Sets the cursor to use for the duration of the active pointer grab. COMPONENT_EXPORT(UI_BASE_X) void ChangeActivePointerGrabCursor(::Cursor cursor); diff --git a/chromium/ui/base/x/x11_shm_image_pool.cc b/chromium/ui/base/x/x11_shm_image_pool.cc index 4719fbf261c..1824426e5bb 100644 --- a/chromium/ui/base/x/x11_shm_image_pool.cc +++ b/chromium/ui/base/x/x11_shm_image_pool.cc @@ -116,7 +116,7 @@ XShmImagePool::XShmImagePool( scoped_refptr<base::SequencedTaskRunner> host_task_runner, scoped_refptr<base::SequencedTaskRunner> event_task_runner, XDisplay* display, - XID drawable, + x11::Drawable drawable, Visual* visual, int depth, std::size_t frames_pending) @@ -163,9 +163,9 @@ bool XShmImagePool::Resize(const gfx::Size& pixel_size) { std::size_t needed_frame_bytes; for (std::size_t i = 0; i < frame_states_.size(); ++i) { FrameState& state = frame_states_[i]; - state.image.reset(XShmCreateImage(display_, visual_, depth_, ZPixmap, - nullptr, &state.shminfo_, - pixel_size.width(), pixel_size.height())); + state.image.reset(XShmCreateImage( + display_, visual_, depth_, static_cast<int>(x11::ImageFormat::ZPixmap), + nullptr, &state.shminfo_, pixel_size.width(), pixel_size.height())); if (!state.image) return false; std::size_t current_frame_bytes = @@ -312,18 +312,20 @@ void XShmImagePool::DispatchShmCompletionEvent(XShmCompletionEvent event) { } } -bool XShmImagePool::CanDispatchXEvent(XEvent* xev) { +bool XShmImagePool::CanDispatchXEvent(x11::Event* x11_event) { + const XEvent* xev = &x11_event->xlib_event(); DCHECK(event_task_runner_->RunsTasksInCurrentSequence()); if (xev->type != ui::ShmEventBase() + ShmCompletion) return false; - XShmCompletionEvent* shm_event = reinterpret_cast<XShmCompletionEvent*>(xev); - return shm_event->drawable == drawable_; + const auto* shm_event = reinterpret_cast<const XShmCompletionEvent*>(xev); + return shm_event->drawable == drawable_.value; } -bool XShmImagePool::DispatchXEvent(XEvent* xev) { - if (!CanDispatchXEvent(xev)) +bool XShmImagePool::DispatchXEvent(x11::Event* x11_event) { + XEvent* xev = &x11_event->xlib_event(); + if (!CanDispatchXEvent(x11_event)) return false; XShmCompletionEvent* shm_event = reinterpret_cast<XShmCompletionEvent*>(xev); diff --git a/chromium/ui/base/x/x11_shm_image_pool.h b/chromium/ui/base/x/x11_shm_image_pool.h index c74ff171d34..b50331d5c9b 100644 --- a/chromium/ui/base/x/x11_shm_image_pool.h +++ b/chromium/ui/base/x/x11_shm_image_pool.h @@ -19,6 +19,7 @@ #include "ui/base/x/x11_util.h" #include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11.h" namespace ui { @@ -34,7 +35,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool XShmImagePool(scoped_refptr<base::SequencedTaskRunner> host_task_runner, scoped_refptr<base::SequencedTaskRunner> event_task_runner, XDisplay* display, - XID drawable, + x11::Drawable drawable, Visual* visual, int depth, std::size_t max_frames_pending); @@ -66,7 +67,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool void DispatchShmCompletionEvent(XShmCompletionEvent event); - bool CanDispatchXEvent(XEvent* xev); + bool CanDispatchXEvent(x11::Event* xev); const scoped_refptr<base::SequencedTaskRunner> host_task_runner_; const scoped_refptr<base::SequencedTaskRunner> event_task_runner_; @@ -98,7 +99,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool }; // XEventDispatcher: - bool DispatchXEvent(XEvent* xev) override; + bool DispatchXEvent(x11::Event* xev) override; void InitializeOnGpu(); void TeardownOnGpu(); @@ -106,7 +107,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool void Cleanup(); XDisplay* const display_; - const XID drawable_; + const x11::Drawable drawable_; Visual* const visual_; const int depth_; diff --git a/chromium/ui/base/x/x11_software_bitmap_presenter.cc b/chromium/ui/base/x/x11_software_bitmap_presenter.cc index f72b5b3ac6b..1974c5bfac8 100644 --- a/chromium/ui/base/x/x11_software_bitmap_presenter.cc +++ b/chromium/ui/base/x/x11_software_bitmap_presenter.cc @@ -13,6 +13,7 @@ #include <utility> #include "base/bind.h" +#include "base/logging.h" #include "base/macros.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkImageInfo.h" @@ -20,6 +21,7 @@ #include "ui/base/x/x11_shm_image_pool.h" #include "ui/base/x/x11_util.h" #include "ui/base/x/x11_util_internal.h" +#include "ui/gfx/native_widget_types.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_error_tracker.h" #include "ui/gfx/x/x11_types.h" @@ -65,8 +67,8 @@ bool X11SoftwareBitmapPresenter::CompositeBitmap(XDisplay* display, ui::XScopedImage bg; { gfx::X11ErrorTracker ignore_x_errors; - bg.reset( - XGetImage(display, widget, x, y, width, height, AllPlanes, ZPixmap)); + bg.reset(XGetImage(display, widget, x, y, width, height, AllPlanes, + static_cast<int>(x11::ImageFormat::ZPixmap))); } // XGetImage() may fail if the drawable is a window and the window is not @@ -78,27 +80,28 @@ bool X11SoftwareBitmapPresenter::CompositeBitmap(XDisplay* display, return false; XGCValues gcv; - gcv.subwindow_mode = IncludeInferiors; + gcv.subwindow_mode = static_cast<int>(x11::SubwindowMode::IncludeInferiors); XChangeGC(display, gc, GCSubwindowMode, &gcv); XCopyArea(display, widget, pixmap, gc, x, y, width, height, 0, 0); - gcv.subwindow_mode = ClipByChildren; + gcv.subwindow_mode = static_cast<int>(x11::SubwindowMode::ClipByChildren); XChangeGC(display, gc, GCSubwindowMode, &gcv); - bg.reset( - XGetImage(display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap)); + bg.reset(XGetImage(display, pixmap, 0, 0, width, height, AllPlanes, + static_cast<int>(x11::ImageFormat::ZPixmap))); } if (!bg) return false; SkBitmap bg_bitmap; - SkImageInfo image_info = - SkImageInfo::Make(bg->width, bg->height, - bg->byte_order == LSBFirst ? kBGRA_8888_SkColorType - : kRGBA_8888_SkColorType, - kPremul_SkAlphaType); + SkImageInfo image_info = SkImageInfo::Make( + bg->width, bg->height, + bg->byte_order == static_cast<int>(x11::ImageOrder::LSBFirst) + ? kBGRA_8888_SkColorType + : kRGBA_8888_SkColorType, + kPremul_SkAlphaType); if (!bg_bitmap.installPixels(image_info, bg->data, bg->bytes_per_line)) return false; SkCanvas canvas(bg_bitmap); @@ -120,16 +123,18 @@ X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter( gfx::AcceleratedWidget widget, scoped_refptr<base::SequencedTaskRunner> host_task_runner, scoped_refptr<base::SequencedTaskRunner> event_task_runner) - : widget_(widget), + : widget_(static_cast<x11::Window>(widget)), display_(gfx::GetXDisplay()), gc_(nullptr), host_task_runner_(host_task_runner), event_task_runner_(event_task_runner) { - DCHECK_NE(widget_, gfx::kNullAcceleratedWidget); - gc_ = XCreateGC(display_, widget_, 0, nullptr); + DCHECK(widget_ != x11::Window::None); + gc_ = XCreateGC(display_, static_cast<uint32_t>(widget_), 0, nullptr); memset(&attributes_, 0, sizeof(attributes_)); - if (!XGetWindowAttributes(display_, widget_, &attributes_)) { - LOG(ERROR) << "XGetWindowAttributes failed for window " << widget_; + if (!XGetWindowAttributes(display_, static_cast<uint32_t>(widget_), + &attributes_)) { + LOG(ERROR) << "XGetWindowAttributes failed for window " + << static_cast<uint32_t>(widget_); return; } @@ -219,9 +224,9 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) { if (ShmPoolReady()) { // TODO(thomasanderson): Investigate direct rendering with DRI3 to avoid any // unnecessary X11 IPC or buffer copying. - if (XShmPutImage(display_, widget_, gc_, shm_pool_->CurrentImage(), - rect.x(), rect.y(), rect.x(), rect.y(), rect.width(), - rect.height(), x11::True)) { + if (XShmPutImage(display_, static_cast<uint32_t>(widget_), gc_, + shm_pool_->CurrentImage(), rect.x(), rect.y(), rect.x(), + rect.y(), rect.width(), rect.height(), x11::True)) { needs_swap_ = true; FlushAfterPutImage(); return; @@ -231,10 +236,13 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) { surface_->peekPixels(&skia_pixmap); } + if (!skia_pixmap.addr()) + return; + if (composite_ && - CompositeBitmap(display_, widget_, rect.x(), rect.y(), rect.width(), - rect.height(), attributes_.depth, gc_, - skia_pixmap.addr())) { + CompositeBitmap(display_, static_cast<uint32_t>(widget_), rect.x(), + rect.y(), rect.width(), rect.height(), attributes_.depth, + gc_, skia_pixmap.addr())) { FlushAfterPutImage(); return; } @@ -242,10 +250,10 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) { XImage image = {}; image.width = viewport_pixel_size_.width(); image.height = viewport_pixel_size_.height(); - image.format = ZPixmap; - image.byte_order = LSBFirst; + image.format = static_cast<int>(x11::ImageFormat::ZPixmap); + image.byte_order = static_cast<int>(x11::ImageOrder::LSBFirst); image.bitmap_unit = 8; - image.bitmap_bit_order = LSBFirst; + image.bitmap_bit_order = static_cast<int>(x11::ImageOrder::LSBFirst); image.depth = attributes_.depth; image.bits_per_pixel = attributes_.visual->bits_per_rgb; @@ -257,8 +265,8 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) { image.blue_mask = attributes_.visual->blue_mask; image.data = reinterpret_cast<char*>(const_cast<void*>(skia_pixmap.addr())); - XPutImage(display_, widget_, gc_, &image, rect.x(), rect.y(), rect.x(), - rect.y(), rect.width(), rect.height()); + XPutImage(display_, static_cast<uint32_t>(widget_), gc_, &image, rect.x(), + rect.y(), rect.x(), rect.y(), rect.width(), rect.height()); FlushAfterPutImage(); } diff --git a/chromium/ui/base/x/x11_software_bitmap_presenter.h b/chromium/ui/base/x/x11_software_bitmap_presenter.h index c100fddc463..4f405653b19 100644 --- a/chromium/ui/base/x/x11_software_bitmap_presenter.h +++ b/chromium/ui/base/x/x11_software_bitmap_presenter.h @@ -58,7 +58,7 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter { void FlushAfterPutImage(); - gfx::AcceleratedWidget widget_; + x11::Window widget_; XDisplay* display_; GC gc_; XWindowAttributes attributes_; diff --git a/chromium/ui/base/x/x11_topmost_window_finder.h b/chromium/ui/base/x/x11_topmost_window_finder.h index fd5305da988..8099ce8bbcb 100644 --- a/chromium/ui/base/x/x11_topmost_window_finder.h +++ b/chromium/ui/base/x/x11_topmost_window_finder.h @@ -19,7 +19,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XTopmostWindowFinder { virtual ~XTopmostWindowFinder(); // Returns the topmost window at |screen_loc_px|. - virtual XID FindWindowAt(const gfx::Point& screen_loc_px) = 0; + virtual x11::Window FindWindowAt(const gfx::Point& screen_loc_px) = 0; }; } // namespace ui diff --git a/chromium/ui/base/x/x11_util.cc b/chromium/ui/base/x/x11_util.cc index 4f35d362363..e09f75b75c0 100644 --- a/chromium/ui/base/x/x11_util.cc +++ b/chromium/ui/base/x/x11_util.cc @@ -21,12 +21,14 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/compiler_specific.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/singleton.h" #include "base/message_loop/message_loop_current.h" #include "base/metrics/histogram_macros.h" #include "base/no_destructor.h" +#include "base/notreached.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" @@ -42,6 +44,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkTypes.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" #include "ui/base/x/x11_menu_list.h" #include "ui/base/x/x11_util_internal.h" #include "ui/events/devices/x11/device_data_manager_x11.h" @@ -62,6 +65,7 @@ #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_error_tracker.h" +#include "ui/gfx/x/xproto.h" #include "ui/gfx/x/xproto_util.h" #if defined(OS_FREEBSD) @@ -84,10 +88,6 @@ namespace { constexpr int kNetWMStateAdd = 1; constexpr int kNetWMStateRemove = 0; -// Length in 32-bit multiples of the data to be retrieved for -// XGetWindowProperty. -constexpr int kLongLength = 0x1FFFFFFF; /* MAXINT32 / 4 */ - int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) { // This callback can be invoked by drivers very late in thread destruction, // when Chrome TLS is no longer usable. https://crbug.com/849225. @@ -113,58 +113,15 @@ int DefaultX11IOErrorHandler(XDisplay* d) { _exit(1); } -template <typename T> -bool GetProperty(XID window, const std::string& property_name, T* value) { - static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, ""); - auto response = x11::Connection::Get() - ->GetProperty({ - .window = static_cast<x11::Window>(window), - .property = static_cast<x11::Atom>( - gfx::GetAtom(property_name.c_str())), - .long_length = std::max<uint32_t>(1, sizeof(T) / 4), - }) - .Sync(); - if (!response || response->format != 8 * sizeof(T) || - response->value.size() != sizeof(T)) { - return false; - } - - DCHECK_EQ(response->format / 8 * response->value_len, response->value.size()); - memcpy(value, response->value.data(), sizeof(T)); - return true; -} - -template <typename T> -bool GetArrayProperty(XID window, - const std::string& property_name, - std::vector<T>* value) { - static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, ""); - auto response = x11::Connection::Get() - ->GetProperty({ - .window = static_cast<x11::Window>(window), - .property = static_cast<x11::Atom>( - gfx::GetAtom(property_name.c_str())), - .long_length = std::numeric_limits<uint32_t>::max(), - }) - .Sync(); - if (!response || response->format != 8 * sizeof(T)) - return false; - - DCHECK_EQ(response->format / 8 * response->value_len, response->value.size()); - value->resize(response->value_len); - memcpy(value->data(), response->value.data(), response->value.size()); - return true; -} - bool SupportsEWMH() { static bool supports_ewmh = false; static bool supports_ewmh_cached = false; if (!supports_ewmh_cached) { supports_ewmh_cached = true; - int wm_window = 0u; - if (!GetIntProperty(GetX11RootWindow(), "_NET_SUPPORTING_WM_CHECK", - &wm_window)) { + x11::Window wm_window = x11::Window::None; + if (!GetProperty(GetX11RootWindow(), + gfx::GetAtom("_NET_SUPPORTING_WM_CHECK"), &wm_window)) { supports_ewmh = false; return false; } @@ -179,9 +136,10 @@ bool SupportsEWMH() { // property referencing an ID that's been recycled for another window), so // we check that too. gfx::X11ErrorTracker err_tracker; - int wm_window_property = 0; - bool result = GetIntProperty(wm_window, "_NET_SUPPORTING_WM_CHECK", - &wm_window_property); + x11::Window wm_window_property = x11::Window::None; + bool result = + GetProperty(wm_window, gfx::GetAtom("_NET_SUPPORTING_WM_CHECK"), + &wm_window_property); supports_ewmh = !err_tracker.FoundNewError() && result && wm_window_property == wm_window; } @@ -194,32 +152,29 @@ bool GetWindowManagerName(std::string* wm_name) { if (!SupportsEWMH()) return false; - int wm_window = 0; - if (!GetIntProperty(GetX11RootWindow(), "_NET_SUPPORTING_WM_CHECK", - &wm_window)) { + x11::Window wm_window = x11::Window::None; + if (!GetProperty(GetX11RootWindow(), gfx::GetAtom("_NET_SUPPORTING_WM_CHECK"), + &wm_window)) { return false; } gfx::X11ErrorTracker err_tracker; - bool result = - GetStringProperty(static_cast<XID>(wm_window), "_NET_WM_NAME", wm_name); + bool result = GetStringProperty(wm_window, "_NET_WM_NAME", wm_name); return !err_tracker.FoundNewError() && result; } unsigned int GetMaxCursorSize() { - // Although XQueryBestCursor() takes unsigned ints, the width and height will - // be sent over the wire as 16 bit integers. constexpr unsigned int kQuerySize = std::numeric_limits<uint16_t>::max(); - XDisplay* display = gfx::GetXDisplay(); - unsigned int width = 0; - unsigned int height = 0; - XQueryBestCursor(display, DefaultRootWindow(display), kQuerySize, kQuerySize, - &width, &height); - unsigned int min_dimension = std::min(width, height); + auto* connection = x11::Connection::Get(); + x11::QueryBestSizeRequest request{ + x11::QueryShapeOf::LargestCursor, + static_cast<x11::Window>(GetX11RootWindow()), kQuerySize, kQuerySize}; + if (auto response = connection->QueryBestSize(request).Sync()) + return std::min(response->width, response->height); // libXcursor defines MAX_BITMAP_CURSOR_SIZE to 64 in src/xcursorint.h, so use // this as a fallback in case the X server returns zero size, which can happen // on some buggy implementations of XWayland/XMir. - return min_dimension > 0 ? min_dimension : 64; + return 64; } // A process wide singleton cache for custom X cursors. @@ -308,8 +263,235 @@ SkBitmap ConvertSkBitmapToUnpremul(const SkBitmap& bitmap) { return converted_bitmap; } +// Returns a cursor name, compatible with either X11 or the FreeDesktop.org +// cursor spec +// (https://www.x.org/releases/current/doc/libX11/libX11/libX11.html#x_font_cursors +// and https://www.freedesktop.org/wiki/Specifications/cursor-spec/), followed +// by fallbacks that can work as replacements in some environments where the +// original may not be available (e.g. desktop environments other than +// GNOME and KDE). +// TODO(hferreiro): each list starts with the FreeDesktop.org icon name but +// "ns-resize", "ew-resize", "nesw-resize", "nwse-resize", "grab", "grabbing", +// which were not available in older versions of Breeze, the default KDE theme. +std::vector<const char*> CursorNamesFromType(mojom::CursorType type) { + switch (type) { + case mojom::CursorType::kMove: + // Returning "move" is the correct thing here, but Blink doesn't make a + // distinction between move and all-scroll. Other platforms use a cursor + // more consistent with all-scroll, so use that. + case mojom::CursorType::kMiddlePanning: + case mojom::CursorType::kMiddlePanningVertical: + case mojom::CursorType::kMiddlePanningHorizontal: + return {"all-scroll", "fleur"}; + case mojom::CursorType::kEastPanning: + case mojom::CursorType::kEastResize: + return {"e-resize", "right_side"}; + case mojom::CursorType::kNorthPanning: + case mojom::CursorType::kNorthResize: + return {"n-resize", "top_side"}; + case mojom::CursorType::kNorthEastPanning: + case mojom::CursorType::kNorthEastResize: + return {"ne-resize", "top_right_corner"}; + case mojom::CursorType::kNorthWestPanning: + case mojom::CursorType::kNorthWestResize: + return {"nw-resize", "top_left_corner"}; + case mojom::CursorType::kSouthPanning: + case mojom::CursorType::kSouthResize: + return {"s-resize", "bottom_side"}; + case mojom::CursorType::kSouthEastPanning: + case mojom::CursorType::kSouthEastResize: + return {"se-resize", "bottom_right_corner"}; + case mojom::CursorType::kSouthWestPanning: + case mojom::CursorType::kSouthWestResize: + return {"sw-resize", "bottom_left_corner"}; + case mojom::CursorType::kWestPanning: + case mojom::CursorType::kWestResize: + return {"w-resize", "left_side"}; + case mojom::CursorType::kNone: + return {"none"}; + case mojom::CursorType::kGrab: + return {"openhand", "grab"}; + case mojom::CursorType::kGrabbing: + return {"closedhand", "grabbing", "hand2"}; + case mojom::CursorType::kCross: + return {"crosshair", "cross"}; + case mojom::CursorType::kHand: + return {"pointer", "hand", "hand2"}; + case mojom::CursorType::kIBeam: + return {"text", "xterm"}; + case mojom::CursorType::kProgress: + return {"progress", "left_ptr_watch", "watch"}; + case mojom::CursorType::kWait: + return {"wait", "watch"}; + case mojom::CursorType::kHelp: + return {"help"}; + case mojom::CursorType::kNorthSouthResize: + return {"sb_v_double_arrow", "ns-resize"}; + case mojom::CursorType::kEastWestResize: + return {"sb_h_double_arrow", "ew-resize"}; + case mojom::CursorType::kColumnResize: + return {"col-resize", "sb_h_double_arrow"}; + case mojom::CursorType::kRowResize: + return {"row-resize", "sb_v_double_arrow"}; + case mojom::CursorType::kNorthEastSouthWestResize: + return {"size_bdiag", "nesw-resize", "fd_double_arrow"}; + case mojom::CursorType::kNorthWestSouthEastResize: + return {"size_fdiag", "nwse-resize", "bd_double_arrow"}; + case mojom::CursorType::kVerticalText: + return {"vertical-text"}; + case mojom::CursorType::kZoomIn: + return {"zoom-in"}; + case mojom::CursorType::kZoomOut: + return {"zoom-out"}; + case mojom::CursorType::kCell: + return {"cell", "plus"}; + case mojom::CursorType::kContextMenu: + return {"context-menu"}; + case mojom::CursorType::kAlias: + return {"alias"}; + case mojom::CursorType::kNoDrop: + return {"no-drop"}; + case mojom::CursorType::kCopy: + return {"copy"}; + case mojom::CursorType::kNotAllowed: + return {"not-allowed", "crossed_circle"}; + case mojom::CursorType::kDndNone: + return {"dnd-none", "hand2"}; + case mojom::CursorType::kDndMove: + return {"dnd-move", "hand2"}; + case mojom::CursorType::kDndCopy: + return {"dnd-copy", "hand2"}; + case mojom::CursorType::kDndLink: + return {"dnd-link", "hand2"}; + case mojom::CursorType::kCustom: + // kCustom is for custom image cursors. The platform cursor will be set + // at WebCursor::GetPlatformCursor(). + NOTREACHED(); + FALLTHROUGH; + case mojom::CursorType::kNull: + case mojom::CursorType::kPointer: + return {"left_ptr"}; + } + NOTREACHED(); + return {"left_ptr"}; +} + } // namespace +void DeleteProperty(x11::Window window, x11::Atom name) { + x11::Connection::Get()->DeleteProperty({ + .window = static_cast<x11::Window>(window), + .property = name, + }); +} + +bool GetWmNormalHints(x11::Window window, SizeHints* hints) { + std::vector<uint32_t> hints32; + if (!GetArrayProperty(window, gfx::GetAtom("WM_NORMAL_HINTS"), &hints32)) + return false; + if (hints32.size() != sizeof(SizeHints) / 4) + return false; + memcpy(hints, hints32.data(), sizeof(*hints)); + return true; +} + +void SetWmNormalHints(x11::Window window, const SizeHints& hints) { + std::vector<uint32_t> hints32(sizeof(SizeHints) / 4); + memcpy(hints32.data(), &hints, sizeof(SizeHints)); + ui::SetArrayProperty(window, gfx::GetAtom("WM_NORMAL_HINTS"), + gfx::GetAtom("WM_SIZE_HINTS"), hints32); +} + +bool GetWmHints(x11::Window window, WmHints* hints) { + std::vector<uint32_t> hints32; + if (!GetArrayProperty(window, gfx::GetAtom("WM_HINTS"), &hints32)) + return false; + if (hints32.size() != sizeof(WmHints) / 4) + return false; + memcpy(hints, hints32.data(), sizeof(*hints)); + return true; +} + +void SetWmHints(x11::Window window, const WmHints& hints) { + std::vector<uint32_t> hints32(sizeof(WmHints) / 4); + memcpy(hints32.data(), &hints, sizeof(WmHints)); + ui::SetArrayProperty(window, gfx::GetAtom("WM_HINTS"), + gfx::GetAtom("WM_HINTS"), hints32); +} + +void WithdrawWindow(x11::Window window) { + auto* connection = x11::Connection::Get(); + connection->UnmapWindow({window}); + + auto root = connection->default_root(); + x11::UnmapNotifyEvent event{.event = root, .window = window}; + auto event_bytes = x11::Write(event); + event_bytes.resize(32); + + auto mask = + x11::EventMask::SubstructureNotify | x11::EventMask::SubstructureRedirect; + x11::SendEventRequest request{false, root, mask}; + std::copy(event_bytes.begin(), event_bytes.end(), request.event.begin()); + connection->SendEvent(request); +} + +void RaiseWindow(x11::Window window) { + x11::Connection::Get()->ConfigureWindow( + {.window = window, .stack_mode = x11::StackMode::Above}); +} + +void LowerWindow(x11::Window window) { + x11::Connection::Get()->ConfigureWindow( + {.window = window, .stack_mode = x11::StackMode::Below}); +} + +void DefineCursor(x11::Window window, x11::Cursor cursor) { + // TODO(https://crbug.com/1066670): Sync() should be removed. It's added for + // now because Xlib's XDefineCursor() sync'ed and removing it perturbs the + // timing on BookmarkBarViewTest8.DNDBackToOriginatingMenu on + // linux-chromeos-rel, causing it to flake. + x11::Connection::Get() + ->ChangeWindowAttributes({.window = window, .cursor = cursor}) + .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; +} + +x11::KeyCode KeysymToKeycode(x11::Connection* connection, x11::KeySym keysym) { + uint8_t min_keycode = static_cast<uint8_t>(connection->setup().min_keycode); + uint8_t max_keycode = static_cast<uint8_t>(connection->setup().max_keycode); + uint8_t count = max_keycode - min_keycode + 1; + auto future = + connection->GetKeyboardMapping({connection->setup().min_keycode, count}); + if (auto reply = future.Sync()) { + DCHECK_EQ(count * reply->keysyms_per_keycode, + static_cast<int>(reply->keysyms.size())); + for (size_t i = 0; i < reply->keysyms.size(); i++) { + if (reply->keysyms[i] == keysym) { + return static_cast<x11::KeyCode>(min_keycode + + i / reply->keysyms_per_keycode); + } + } + } + return {}; +} + bool IsXInput2Available() { return DeviceDataManagerX11::GetInstance()->IsXInput2Available(); } @@ -396,24 +578,37 @@ XcursorImage* SkBitmapToXcursorImage(const SkBitmap& cursor_image, return image; } -int CoalescePendingMotionEvents(const XEvent* xev, XEvent* last_event) { - DCHECK(xev->type == MotionNotify || xev->type == GenericEvent); - XDisplay* display = xev->xany.display; - XEvent next_event; +::Cursor LoadCursorFromType(mojom::CursorType type) { + for (auto* name : CursorNamesFromType(type)) { + ::Cursor cursor = XcursorLibraryLoadCursor(gfx::GetXDisplay(), name); + if (cursor != x11::None) + return cursor; + } + return x11::None; +} + +int CoalescePendingMotionEvents(const x11::Event* x11_event, + x11::Event* last_event) { + const XEvent* xev = &x11_event->xlib_event(); + DCHECK(xev->type == x11::MotionNotifyEvent::opcode || + xev->type == x11::GeGenericEvent::opcode); + auto* conn = x11::Connection::Get(); bool is_motion = false; int num_coalesced = 0; - if (xev->type == MotionNotify) { + conn->ReadResponses(); + if (xev->type == x11::MotionNotifyEvent::opcode) { is_motion = true; - while (XPending(display)) { - XPeekEvent(xev->xany.display, &next_event); + for (auto it = conn->events().begin(); it != conn->events().end();) { + const auto& next_event = it->xlib_event(); // Discard all but the most recent motion event that targets the same // window with unchanged state. - if (next_event.type == MotionNotify && + if (next_event.type == x11::MotionNotifyEvent::opcode && next_event.xmotion.window == xev->xmotion.window && next_event.xmotion.subwindow == xev->xmotion.subwindow && next_event.xmotion.state == xev->xmotion.state) { - XNextEvent(xev->xany.display, last_event); + *last_event = std::move(*it); + it = conn->events().erase(it); } else { break; } @@ -424,12 +619,14 @@ int CoalescePendingMotionEvents(const XEvent* xev, XEvent* last_event) { DCHECK(event_type == XI_Motion || event_type == XI_TouchUpdate); is_motion = event_type == XI_Motion; - while (XPending(display)) { - XPeekEvent(display, &next_event); + auto* ddmx11 = ui::DeviceDataManagerX11::GetInstance(); + for (auto it = conn->events().begin(); it != conn->events().end();) { + auto& next_event = it->xlib_event(); - // If we can't get the cookie, abort the check. - if (!XGetEventData(next_event.xgeneric.display, &next_event.xcookie)) - return num_coalesced; + if (next_event.type != x11::GeGenericEvent::opcode || + !next_event.xcookie.data) { + break; + } // If this isn't from a valid device, throw the event away, as // that's what the message pump would do. Device events come in pairs @@ -437,17 +634,14 @@ int CoalescePendingMotionEvents(const XEvent* xev, XEvent* last_event) { // always be at least one pending. if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event( &next_event)) { - XFreeEventData(display, &next_event.xcookie); - XNextEvent(display, &next_event); + it = conn->events().erase(it); continue; } - if (next_event.type == GenericEvent && + if (next_event.type == x11::GeGenericEvent::opcode && next_event.xgeneric.evtype == event_type && - !ui::DeviceDataManagerX11::GetInstance()->IsCMTGestureEvent( - next_event) && - ui::DeviceDataManagerX11::GetInstance()->GetScrollClassEventDetail( - next_event) == SCROLL_TYPE_NO_SCROLL) { + !ddmx11->IsCMTGestureEvent(*it) && + ddmx11->GetScrollClassEventDetail(*it) == SCROLL_TYPE_NO_SCROLL) { XIDeviceEvent* next_xievent = static_cast<XIDeviceEvent*>(next_event.xcookie.data); // Confirm that the motion event is targeted at the same window @@ -462,25 +656,16 @@ int CoalescePendingMotionEvents(const XEvent* xev, XEvent* last_event) { xievent->mods.latched == next_xievent->mods.latched && xievent->mods.locked == next_xievent->mods.locked && xievent->mods.effective == next_xievent->mods.effective) { - XFreeEventData(display, &next_event.xcookie); - // Free the previous cookie. - if (num_coalesced > 0) - XFreeEventData(display, &last_event->xcookie); - // Get the event and its cookie data. - XNextEvent(display, last_event); - XGetEventData(display, &last_event->xcookie); - ++num_coalesced; + *last_event = std::move(*it); + it = conn->events().erase(it); + num_coalesced++; continue; } } - // This isn't an event we want so free its cookie data. - XFreeEventData(display, &next_event.xcookie); break; } } - if (is_motion && num_coalesced > 0) - UMA_HISTOGRAM_COUNTS_10000("Event.CoalescedCount.Mouse", num_coalesced); return num_coalesced; } @@ -505,62 +690,53 @@ void HideHostCursor() { return invisible_cursor; } -void SetUseOSWindowFrame(XID window, bool use_os_window_frame) { +void SetUseOSWindowFrame(x11::Window window, bool use_os_window_frame) { // This data structure represents additional hints that we send to the window // manager and has a direct lineage back to Motif, which defined this de facto - // standard. This struct doesn't seem 64-bit safe though, but it's what GDK - // does. + // standard. We define this struct to match the wire-format (32-bit fields) + // rather than the Xlib API (XChangeProperty) format (long fields). typedef struct { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; + uint32_t flags; + uint32_t functions; + uint32_t decorations; + int32_t input_mode; + uint32_t status; } MotifWmHints; MotifWmHints motif_hints; memset(&motif_hints, 0, sizeof(motif_hints)); // Signals that the reader of the _MOTIF_WM_HINTS property should pay // attention to the value of |decorations|. - motif_hints.flags = (1L << 1); + motif_hints.flags = (1u << 1); motif_hints.decorations = use_os_window_frame ? 1 : 0; - XAtom hint_atom = gfx::GetAtom("_MOTIF_WM_HINTS"); - XChangeProperty(gfx::GetXDisplay(), window, hint_atom, hint_atom, 32, - PropModeReplace, - reinterpret_cast<unsigned char*>(&motif_hints), - sizeof(MotifWmHints) / sizeof(long)); + std::vector<uint32_t> hints(sizeof(MotifWmHints) / sizeof(uint32_t)); + memcpy(hints.data(), &motif_hints, sizeof(MotifWmHints)); + x11::Atom hint_atom = gfx::GetAtom("_MOTIF_WM_HINTS"); + SetArrayProperty(window, hint_atom, hint_atom, hints); } bool IsShapeExtensionAvailable() { - int dummy; - static bool is_shape_available = - XShapeQueryExtension(gfx::GetXDisplay(), &dummy, &dummy); - return is_shape_available; + return x11::Connection::Get()->shape().present(); } -XID GetX11RootWindow() { - return DefaultRootWindow(gfx::GetXDisplay()); +x11::Window GetX11RootWindow() { + return x11::Connection::Get()->default_screen().root; } bool GetCurrentDesktop(int* desktop) { return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop); } -void SetHideTitlebarWhenMaximizedProperty(XID window, +void SetHideTitlebarWhenMaximizedProperty(x11::Window window, HideTitlebarWhenMaximized property) { - // XChangeProperty() expects "hide" to be long. - unsigned long hide = property; - XChangeProperty(gfx::GetXDisplay(), window, - gfx::GetAtom("_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"), - XA_CARDINAL, - 32, // size in bits - PropModeReplace, reinterpret_cast<unsigned char*>(&hide), 1); + SetProperty(window, gfx::GetAtom("_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"), + x11::Atom::CARDINAL, static_cast<uint32_t>(property)); } void ClearX11DefaultRootWindow() { XDisplay* display = gfx::GetXDisplay(); - XID root_window = GetX11RootWindow(); + x11::Window root_window = GetX11RootWindow(); gfx::Rect root_bounds; if (!GetOuterWindowBounds(root_window, &root_bounds)) { LOG(ERROR) << "Failed to get the bounds of the X11 root window"; @@ -569,25 +745,27 @@ void ClearX11DefaultRootWindow() { XGCValues gc_values = {0}; gc_values.foreground = BlackPixel(display, DefaultScreen(display)); - GC gc = XCreateGC(display, root_window, GCForeground, &gc_values); - XFillRectangle(display, root_window, gc, root_bounds.x(), root_bounds.y(), - root_bounds.width(), root_bounds.height()); + GC gc = XCreateGC(display, static_cast<uint32_t>(root_window), GCForeground, + &gc_values); + XFillRectangle(display, static_cast<uint32_t>(root_window), gc, + root_bounds.x(), root_bounds.y(), root_bounds.width(), + root_bounds.height()); XFreeGC(display, gc); } -bool IsWindowVisible(XID window) { +bool IsWindowVisible(x11::Window window) { TRACE_EVENT0("ui", "IsWindowVisible"); - XWindowAttributes win_attributes; - if (!XGetWindowAttributes(gfx::GetXDisplay(), window, &win_attributes)) - return false; - if (win_attributes.map_state != IsViewable) + auto x11_window = static_cast<x11::Window>(window); + auto* connection = x11::Connection::Get(); + auto response = connection->GetWindowAttributes({x11_window}).Sync(); + if (!response || response->map_state != x11::MapState::Viewable) return false; // Minimized windows are not visible. - std::vector<XAtom> wm_states; + std::vector<x11::Atom> wm_states; if (GetAtomArrayProperty(window, "_NET_WM_STATE", &wm_states)) { - XAtom hidden_atom = gfx::GetAtom("_NET_WM_STATE_HIDDEN"); + x11::Atom hidden_atom = gfx::GetAtom("_NET_WM_STATE_HIDDEN"); if (base::Contains(wm_states, hidden_atom)) return false; } @@ -600,26 +778,27 @@ bool IsWindowVisible(XID window) { window_desktop == kAllDesktops || window_desktop == current_desktop); } -bool GetInnerWindowBounds(XID window, gfx::Rect* rect) { - Window root, child; - int x, y; - unsigned int width, height; - unsigned int border_width, depth; +bool GetInnerWindowBounds(x11::Window window, gfx::Rect* rect) { + auto x11_window = static_cast<x11::Window>(window); + auto root = static_cast<x11::Window>(GetX11RootWindow()); - if (!XGetGeometry(gfx::GetXDisplay(), window, &root, &x, &y, &width, &height, - &border_width, &depth)) - return false; + x11::Connection* connection = x11::Connection::Get(); + auto get_geometry = connection->GetGeometry({x11_window}); + auto translate_coords = connection->TranslateCoordinates({x11_window, root}); - if (!XTranslateCoordinates(gfx::GetXDisplay(), window, root, 0, 0, &x, &y, - &child)) - return false; + // Sync after making both requests so only one round-trip is made. + auto geometry = get_geometry.Sync(); + auto coords = translate_coords.Sync(); - *rect = gfx::Rect(x, y, width, height); + if (!geometry || !coords) + return false; + *rect = gfx::Rect(coords->dst_x, coords->dst_y, geometry->width, + geometry->height); return true; } -bool GetWindowExtents(XID window, gfx::Insets* extents) { +bool GetWindowExtents(x11::Window window, gfx::Insets* extents) { std::vector<int> insets; if (!GetIntArrayProperty(window, "_NET_FRAME_EXTENTS", &insets)) return false; @@ -634,7 +813,7 @@ bool GetWindowExtents(XID window, gfx::Insets* extents) { return true; } -bool GetOuterWindowBounds(XID window, gfx::Rect* rect) { +bool GetOuterWindowBounds(x11::Window window, gfx::Rect* rect) { if (!GetInnerWindowBounds(window, rect)) return false; @@ -647,7 +826,7 @@ bool GetOuterWindowBounds(XID window, gfx::Rect* rect) { return true; } -bool WindowContainsPoint(XID window, gfx::Point screen_loc) { +bool WindowContainsPoint(x11::Window window, gfx::Point screen_loc) { TRACE_EVENT0("ui", "WindowContainsPoint"); gfx::Rect window_rect; @@ -673,22 +852,21 @@ bool WindowContainsPoint(XID window, gfx::Point screen_loc) { // client bounding region. Any portion of the client input region that is not // included in both the default input region and the client bounding region // will not be included in the effective input region on the screen. - int rectangle_kind[] = {ShapeInput, ShapeBounding}; - for (int kind_index : rectangle_kind) { - int dummy; - int shape_rects_size = 0; - gfx::XScopedPtr<XRectangle[]> shape_rects(XShapeGetRectangles( - gfx::GetXDisplay(), window, kind_index, &shape_rects_size, &dummy)); - if (!shape_rects) { - // The shape is empty. This can occur when |window| is minimized. - DCHECK_EQ(0, shape_rects_size); + x11::Shape::Sk rectangle_kind[] = {x11::Shape::Sk::Input, + x11::Shape::Sk::Bounding}; + for (auto kind : rectangle_kind) { + auto shape = + x11::Connection::Get()->shape().GetRectangles({window, kind}).Sync(); + if (!shape) + return true; + if (shape->rectangles.empty()) { + // The shape can be empty when |window| is minimized. return false; } bool is_in_shape_rects = false; - for (int i = 0; i < shape_rects_size; ++i) { + for (const auto& rect : shape->rectangles) { // The ShapeInput and ShapeBounding rects are to be in window space, so we // have to translate by the window_rect's offset to map to screen space. - const XRectangle& rect = shape_rects[i]; gfx::Rect shape_rect = gfx::Rect(rect.x + window_rect.x(), rect.y + window_rect.y(), rect.width, rect.height); @@ -703,182 +881,105 @@ bool WindowContainsPoint(XID window, gfx::Point screen_loc) { return true; } -bool PropertyExists(XID window, const std::string& property_name) { +bool PropertyExists(x11::Window window, const std::string& property_name) { auto response = x11::Connection::Get() ->GetProperty({ .window = static_cast<x11::Window>(window), - .property = static_cast<x11::Atom>( - gfx::GetAtom(property_name.c_str())), + .property = gfx::GetAtom(property_name), .long_length = 1, }) .Sync(); return response && response->format; } -bool GetRawBytesOfProperty(XID window, - XAtom property, - scoped_refptr<base::RefCountedMemory>* out_data, - size_t* out_data_items, - XAtom* out_type) { - // Retrieve the data from our window. - unsigned long nitems = 0; - unsigned long nbytes = 0; - XAtom prop_type = x11::None; - int prop_format = 0; - unsigned char* property_data = nullptr; - if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0, kLongLength, - x11::False, AnyPropertyType, &prop_type, &prop_format, - &nitems, &nbytes, &property_data) != x11::Success) { - return false; - } - gfx::XScopedPtr<unsigned char> scoped_property(property_data); - - if (prop_type == x11::None) +bool GetRawBytesOfProperty(x11::Window window, + x11::Atom property, + std::vector<uint8_t>* out_data, + x11::Atom* out_type) { + auto future = x11::Connection::Get()->GetProperty({ + .window = static_cast<x11::Window>(window), + .property = property, + // Don't limit the amount of returned data. + .long_length = std::numeric_limits<uint32_t>::max(), + }); + auto response = future.Sync(); + if (!response || !response->format) return false; - - size_t bytes = 0; - // So even though we should theoretically have nbytes (and we can't - // pass nullptr there), we need to manually calculate the byte length here - // because nbytes always returns zero. - switch (prop_format) { - case 8: - bytes = nitems; - break; - case 16: - bytes = sizeof(short) * nitems; - break; - case 32: - bytes = sizeof(long) * nitems; - break; - default: - NOTREACHED(); - break; - } - - if (out_data) - *out_data = new XRefcountedMemory(scoped_property.release(), bytes); - - if (out_data_items) - *out_data_items = nitems; - + *out_data = std::move(response->value); if (out_type) - *out_type = prop_type; - + *out_type = response->type; return true; } -bool GetIntProperty(XID window, const std::string& property_name, int* value) { - return GetProperty(window, property_name, value); +bool GetIntProperty(x11::Window window, + const std::string& property_name, + int* value) { + return GetProperty(window, gfx::GetAtom(property_name), value); } -bool GetXIDProperty(XID window, const std::string& property_name, XID* value) { - uint32_t xid; - if (!GetProperty(window, property_name, &xid)) - return false; - *value = xid; - return true; -} - -bool GetIntArrayProperty(XID window, +bool GetIntArrayProperty(x11::Window window, const std::string& property_name, - std::vector<int>* value) { - return GetArrayProperty(window, property_name, value); + std::vector<int32_t>* value) { + return GetArrayProperty(window, gfx::GetAtom(property_name), value); } -bool GetAtomArrayProperty(XID window, +bool GetAtomArrayProperty(x11::Window window, const std::string& property_name, - std::vector<XAtom>* value) { - std::vector<uint32_t> value32; - if (!GetArrayProperty(window, property_name, &value32)) - return false; - *value = std::vector<XAtom>(value32.begin(), value32.end()); - return true; + std::vector<x11::Atom>* value) { + return GetArrayProperty(window, gfx::GetAtom(property_name), value); } -bool GetStringProperty(XID window, +bool GetStringProperty(x11::Window window, const std::string& property_name, std::string* value) { std::vector<char> str; - if (!GetArrayProperty(window, property_name, &str)) + if (!GetArrayProperty(window, gfx::GetAtom(property_name), &str)) return false; value->assign(str.data(), str.size()); return true; } -bool SetIntProperty(XID window, +void SetIntProperty(x11::Window window, const std::string& name, const std::string& type, - int value) { + int32_t value) { std::vector<int> values(1, value); return SetIntArrayProperty(window, name, type, values); } -bool SetIntArrayProperty(XID window, +void SetIntArrayProperty(x11::Window window, const std::string& name, const std::string& type, - const std::vector<int>& value) { - DCHECK(!value.empty()); - XAtom name_atom = gfx::GetAtom(name.c_str()); - XAtom type_atom = gfx::GetAtom(type.c_str()); - - // XChangeProperty() expects values of type 32 to be longs. - std::unique_ptr<long[]> data(new long[value.size()]); - for (size_t i = 0; i < value.size(); ++i) - data[i] = value[i]; - - gfx::X11ErrorTracker err_tracker; - XChangeProperty(gfx::GetXDisplay(), window, name_atom, type_atom, - 32, // size in bits of items in 'value' - PropModeReplace, - reinterpret_cast<const unsigned char*>(data.get()), - value.size()); // num items - return !err_tracker.FoundNewError(); + const std::vector<int32_t>& value) { + SetArrayProperty(window, gfx::GetAtom(name), gfx::GetAtom(type), value); } -bool SetAtomProperty(XID window, +void SetAtomProperty(x11::Window window, const std::string& name, const std::string& type, - XAtom value) { - std::vector<XAtom> values(1, value); + x11::Atom value) { + std::vector<x11::Atom> values(1, value); return SetAtomArrayProperty(window, name, type, values); } -bool SetAtomArrayProperty(XID window, +void SetAtomArrayProperty(x11::Window window, const std::string& name, const std::string& type, - const std::vector<XAtom>& value) { - DCHECK(!value.empty()); - XAtom name_atom = gfx::GetAtom(name.c_str()); - XAtom type_atom = gfx::GetAtom(type.c_str()); - - // XChangeProperty() expects values of type 32 to be longs. - std::unique_ptr<XAtom[]> data(new XAtom[value.size()]); - for (size_t i = 0; i < value.size(); ++i) - data[i] = value[i]; - - gfx::X11ErrorTracker err_tracker; - XChangeProperty(gfx::GetXDisplay(), window, name_atom, type_atom, - 32, // size in bits of items in 'value' - PropModeReplace, - reinterpret_cast<const unsigned char*>(data.get()), - value.size()); // num items - return !err_tracker.FoundNewError(); + const std::vector<x11::Atom>& value) { + SetArrayProperty(window, gfx::GetAtom(name), gfx::GetAtom(type), value); } -bool SetStringProperty(XID window, - XAtom property, - XAtom type, +void SetStringProperty(x11::Window window, + x11::Atom property, + x11::Atom type, const std::string& value) { - gfx::X11ErrorTracker err_tracker; - XChangeProperty( - gfx::GetXDisplay(), window, property, type, 8, PropModeReplace, - reinterpret_cast<const unsigned char*>(value.c_str()), value.size()); - return !err_tracker.FoundNewError(); + std::vector<char> str(value.begin(), value.end()); + SetArrayProperty(window, property, type, str); } -void SetWindowClassHint(XDisplay* display, - XID window, +void SetWindowClassHint(x11::Connection* connection, + x11::Window window, const std::string& res_name, const std::string& res_class) { XClassHint class_hints; @@ -887,66 +988,45 @@ void SetWindowClassHint(XDisplay* display, // not const references. class_hints.res_name = const_cast<char*>(res_name.c_str()); class_hints.res_class = const_cast<char*>(res_class.c_str()); - XSetClassHint(display, window, &class_hints); + XSetClassHint(connection->display(), static_cast<uint32_t>(window), + &class_hints); } -void SetWindowRole(XDisplay* display, XID window, const std::string& role) { - if (role.empty()) { - XDeleteProperty(display, window, gfx::GetAtom("WM_WINDOW_ROLE")); - } else { - char* role_c = const_cast<char*>(role.c_str()); - XChangeProperty(display, window, gfx::GetAtom("WM_WINDOW_ROLE"), XA_STRING, - 8, PropModeReplace, - reinterpret_cast<unsigned char*>(role_c), role.size()); - } +void SetWindowRole(x11::Window window, const std::string& role) { + x11::Atom prop = gfx::GetAtom("WM_WINDOW_ROLE"); + if (role.empty()) + DeleteProperty(window, prop); + else + SetStringProperty(window, prop, x11::Atom::STRING, role); +} + +void SetWMSpecState(x11::Window window, + bool enabled, + x11::Atom state1, + x11::Atom state2) { + SendClientMessage( + window, GetX11RootWindow(), gfx::GetAtom("_NET_WM_STATE"), + {enabled ? kNetWMStateAdd : kNetWMStateRemove, + static_cast<uint32_t>(state1), static_cast<uint32_t>(state2), 1, 0}); } -void SetWMSpecState(XID window, bool enabled, XAtom state1, XAtom state2) { - XEvent xclient; - memset(&xclient, 0, sizeof(xclient)); - xclient.type = ClientMessage; - xclient.xclient.window = window; - xclient.xclient.message_type = gfx::GetAtom("_NET_WM_STATE"); - // The data should be viewed as a list of longs, because XAtom is a typedef of - // long. - xclient.xclient.format = 32; - xclient.xclient.data.l[0] = enabled ? kNetWMStateAdd : kNetWMStateRemove; - xclient.xclient.data.l[1] = state1; - xclient.xclient.data.l[2] = state2; - xclient.xclient.data.l[3] = 1; - xclient.xclient.data.l[4] = 0; - - XSendEvent(gfx::GetXDisplay(), GetX11RootWindow(), x11::False, - SubstructureRedirectMask | SubstructureNotifyMask, &xclient); -} - -void DoWMMoveResize(XDisplay* display, - XID root_window, - XID window, +void DoWMMoveResize(x11::Connection* connection, + x11::Window root_window, + x11::Window window, const gfx::Point& location_px, int direction) { // This handler is usually sent when the window has the implicit grab. We // need to dump it because what we're about to do is tell the window manager // that it's now responsible for moving the window around; it immediately // grabs when it receives the event below. - XUngrabPointer(display, x11::CurrentTime); + connection->UngrabPointer({x11::Time::CurrentTime}); - XEvent event; - memset(&event, 0, sizeof(event)); - event.xclient.type = ClientMessage; - event.xclient.display = display; - event.xclient.window = window; - event.xclient.message_type = 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<XAtom>& properties, XAtom atom) { +bool HasWMSpecProperty(const base::flat_set<x11::Atom>& properties, + x11::Atom atom) { return properties.find(atom) != properties.end(); } @@ -1014,7 +1094,7 @@ bool IsWmTiling(WindowManagerName window_manager) { } } -bool GetWindowDesktop(XID window, int* desktop) { +bool GetWindowDesktop(x11::Window window, int* desktop) { return GetIntProperty(window, "_NET_WM_DESKTOP", desktop); } @@ -1025,26 +1105,21 @@ std::string GetX11ErrorString(XDisplay* display, int err) { } // Returns true if |window| is a named window. -bool IsWindowNamed(XID window) { - XTextProperty prop; - if (!XGetWMName(gfx::GetXDisplay(), window, &prop) || !prop.value) - return false; - - XFree(prop.value); - return true; +bool IsWindowNamed(x11::Window window) { + return PropertyExists(window, "WM_NAME"); } bool EnumerateChildren(EnumerateWindowsDelegate* delegate, - XID window, + x11::Window window, const int max_depth, int depth) { if (depth > max_depth) return false; - std::vector<XID> windows; - std::vector<XID>::iterator iter; + std::vector<x11::Window> windows; + std::vector<x11::Window>::iterator iter; if (depth == 0) { - XMenuList::GetInstance()->InsertMenuWindowXIDs(&windows); + XMenuList::GetInstance()->InsertMenuWindows(&windows); // Enumerate the menus first. for (iter = windows.begin(); iter != windows.end(); iter++) { if (delegate->ShouldStopIterating(*iter)) @@ -1053,17 +1128,10 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, windows.clear(); } - XID root, parent, *children; - unsigned int num_children; - int status = XQueryTree(gfx::GetXDisplay(), window, &root, &parent, &children, - &num_children); - if (status == 0) + auto query_tree = x11::Connection::Get()->QueryTree({window}).Sync(); + if (!query_tree) return false; - - for (int i = static_cast<int>(num_children) - 1; i >= 0; i--) - windows.push_back(children[i]); - - XFree(children); + windows = std::move(query_tree->children); // XQueryTree returns the children of |window| in bottom-to-top order, so // reverse-iterate the list to check the windows from top-to-bottom. @@ -1087,12 +1155,12 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, } bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) { - XID root = GetX11RootWindow(); + x11::Window root = GetX11RootWindow(); return EnumerateChildren(delegate, root, max_depth, 0); } void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) { - std::vector<XID> stack; + std::vector<x11::Window> stack; if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) { // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back // to old school enumeration of all X windows. Some WMs parent 'top-level' @@ -1102,22 +1170,23 @@ void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) { ui::EnumerateAllWindows(delegate, kMaxSearchDepth); return; } - XMenuList::GetInstance()->InsertMenuWindowXIDs(&stack); + XMenuList::GetInstance()->InsertMenuWindows(&stack); - std::vector<XID>::iterator iter; + std::vector<x11::Window>::iterator iter; for (iter = stack.begin(); iter != stack.end(); iter++) { if (delegate->ShouldStopIterating(*iter)) return; } } -bool GetXWindowStack(Window window, std::vector<XID>* windows) { - std::vector<uint32_t> value32; - if (!GetArrayProperty(window, "_NET_CLIENT_LIST_STACKING", &value32)) +bool GetXWindowStack(x11::Window window, std::vector<x11::Window>* windows) { + if (!GetArrayProperty(window, gfx::GetAtom("_NET_CLIENT_LIST_STACKING"), + windows)) { return false; + } // It's more common to iterate from lowest window to highest, // so reverse the vector. - *windows = std::vector<XID>(value32.rbegin(), value32.rend()); + std::reverse(windows->begin(), windows->end()); return true; } @@ -1181,9 +1250,15 @@ std::string GuessWindowManagerName() { } bool IsCompositingManagerPresent() { + auto is_compositing_manager_present_impl = []() { + auto response = x11::Connection::Get() + ->GetSelectionOwner({gfx::GetAtom("_NET_WM_CM_S0")}) + .Sync(); + return response && response->owner != x11::Window::None; + }; + static bool is_compositing_manager_present = - XGetSelectionOwner(gfx::GetXDisplay(), gfx::GetAtom("_NET_WM_CM_S0")) != - x11::None; + is_compositing_manager_present_impl(); return is_compositing_manager_present; } @@ -1191,13 +1266,13 @@ void SetDefaultX11ErrorHandlers() { SetX11ErrorHandlers(nullptr, nullptr); } -bool IsX11WindowFullScreen(XID window) { +bool IsX11WindowFullScreen(x11::Window window) { // If _NET_WM_STATE_FULLSCREEN is in _NET_SUPPORTED, use the presence or // absence of _NET_WM_STATE_FULLSCREEN in _NET_WM_STATE to determine // whether we're fullscreen. - XAtom fullscreen_atom = gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"); + x11::Atom fullscreen_atom = gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"); if (WmSupportsHint(fullscreen_atom)) { - std::vector<XAtom> atom_properties; + std::vector<x11::Atom> atom_properties; if (GetAtomArrayProperty(window, "_NET_WM_STATE", &atom_properties)) { return base::Contains(atom_properties, fullscreen_atom); } @@ -1207,23 +1282,20 @@ bool IsX11WindowFullScreen(XID window) { if (!ui::GetOuterWindowBounds(window, &window_rect)) return false; - // We can't use display::Screen here because we don't have an aura::Window. So - // instead just look at the size of the default display. - // - // TODO(erg): Actually doing this correctly would require pulling out xrandr, - // which we don't even do in the desktop screen yet. - ::XDisplay* display = gfx::GetXDisplay(); - ::Screen* screen = DefaultScreenOfDisplay(display); - int width = WidthOfScreen(screen); - int height = HeightOfScreen(screen); + // TODO(thomasanderson): We should use + // display::Screen::GetDisplayNearestWindow() instead of using the + // connection screen size, which encompasses all displays. + auto* connection = x11::Connection::Get(); + int width = connection->default_screen().width_in_pixels; + int height = connection->default_screen().height_in_pixels; return window_rect.size() == gfx::Size(width, height); } -bool WmSupportsHint(XAtom atom) { +bool WmSupportsHint(x11::Atom atom) { if (!SupportsEWMH()) return false; - std::vector<XAtom> supported_atoms; + std::vector<x11::Atom> supported_atoms; if (!GetAtomArrayProperty(GetX11RootWindow(), "_NET_SUPPORTED", &supported_atoms)) { return false; @@ -1236,27 +1308,13 @@ gfx::ICCProfile GetICCProfileForMonitor(int monitor) { gfx::ICCProfile icc_profile; if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless)) return icc_profile; - std::string atom_name; - if (monitor == 0) { - atom_name = "_ICC_PROFILE"; - } else { - atom_name = base::StringPrintf("_ICC_PROFILE_%d", monitor); - } - Atom property = gfx::GetAtom(atom_name.c_str()); - if (property != x11::None) { - Atom prop_type = x11::None; - int prop_format = 0; - unsigned long nitems = 0; - unsigned long nbytes = 0; - char* property_data = nullptr; - int result = XGetWindowProperty( - gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()), property, 0, - kLongLength, x11::False, AnyPropertyType, &prop_type, &prop_format, - &nitems, &nbytes, reinterpret_cast<unsigned char**>(&property_data)); - if (result == x11::Success) { - icc_profile = gfx::ICCProfile::FromData(property_data, nitems); - XFree(property_data); - } + std::string atom_name = monitor == 0 + ? "_ICC_PROFILE" + : base::StringPrintf("_ICC_PROFILE_%d", monitor); + std::vector<uint8_t> data; + if (GetRawBytesOfProperty(GetX11RootWindow(), gfx::GetAtom(atom_name), &data, + nullptr)) { + icc_profile = gfx::ICCProfile::FromData(data.data(), data.size()); } return icc_profile; } @@ -1298,7 +1356,7 @@ SkColorType ColorTypeForVisual(void* visual) { }; Visual* vis = reinterpret_cast<Visual*>(visual); // When running under Xvfb, a visual may not be set. - if (!vis->red_mask && !vis->green_mask && !vis->blue_mask) + if (!vis || !vis->red_mask || !vis->green_mask || !vis->blue_mask) return kUnknown_SkColorType; for (const auto& color_info : color_infos) { if (vis->red_mask == color_info.red_mask && @@ -1314,6 +1372,22 @@ SkColorType ColorTypeForVisual(void* visual) { return kUnknown_SkColorType; } +x11::Future<void> SendClientMessage(x11::Window window, + x11::Window target, + x11::Atom type, + const std::array<uint32_t, 5> data, + x11::EventMask event_mask) { + x11::ClientMessageEvent event{.format = 32, .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::SendEventRequest request{false, 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) {} @@ -1404,32 +1478,20 @@ XVisualManager* XVisualManager::GetInstance() { return base::Singleton<XVisualManager>::get(); } -XVisualManager::XVisualManager() - : display_(gfx::GetXDisplay()), - default_visual_id_(0), - system_visual_id_(0), - transparent_visual_id_(0), - using_software_rendering_(false), - have_gpu_argb_visual_(false) { +XVisualManager::XVisualManager() : connection_(x11::Connection::Get()) { base::AutoLock lock(lock_); - int visuals_len = 0; - XVisualInfo visual_template; - visual_template.screen = DefaultScreen(display_); - gfx::XScopedPtr<XVisualInfo[]> visual_list(XGetVisualInfo( - display_, VisualScreenMask, &visual_template, &visuals_len)); - for (int i = 0; i < visuals_len; ++i) - visuals_[visual_list[i].visualid] = - std::make_unique<XVisualData>(visual_list[i]); - - XAtom NET_WM_CM_S0 = gfx::GetAtom("_NET_WM_CM_S0"); - using_compositing_wm_ = - XGetSelectionOwner(display_, NET_WM_CM_S0) != x11::None; + + for (const auto& depth : connection_->default_screen().allowed_depths) { + for (const auto& visual : depth.visuals) { + visuals_[visual.visual_id] = + std::make_unique<XVisualData>(depth.depth, &visual); + } + } // Choose the opaque visual. - default_visual_id_ = - XVisualIDFromVisual(DefaultVisual(display_, DefaultScreen(display_))); + default_visual_id_ = connection_->default_screen().root_visual; system_visual_id_ = default_visual_id_; - DCHECK(system_visual_id_); + DCHECK_NE(system_visual_id_, x11::VisualId{}); DCHECK(visuals_.find(system_visual_id_) != visuals_.end()); // Choose the transparent visual. @@ -1437,119 +1499,98 @@ XVisualManager::XVisualManager() // Why support only 8888 ARGB? Because it's all that GTK+ supports. In // gdkvisual-x11.cc, they look for this specific visual and use it for // all their alpha channel using needs. - const XVisualInfo& info = pair.second->visual_info; - if (info.depth == 32 && info.visual->red_mask == 0xff0000 && - info.visual->green_mask == 0x00ff00 && - info.visual->blue_mask == 0x0000ff) { - transparent_visual_id_ = info.visualid; + const auto& data = *pair.second; + if (data.depth == 32 && data.info->red_mask == 0xff0000 && + data.info->green_mask == 0x00ff00 && data.info->blue_mask == 0x0000ff) { + transparent_visual_id_ = pair.first; break; } } - if (transparent_visual_id_) + if (transparent_visual_id_ != x11::VisualId{}) DCHECK(visuals_.find(transparent_visual_id_) != visuals_.end()); } XVisualManager::~XVisualManager() = default; void XVisualManager::ChooseVisualForWindow(bool want_argb_visual, - Visual** visual, - int* depth, - Colormap* colormap, + x11::VisualId* visual_id, + uint8_t* depth, bool* visual_has_alpha) { base::AutoLock lock(lock_); - bool use_argb = want_argb_visual && using_compositing_wm_ && + bool use_argb = want_argb_visual && IsCompositingManagerPresent() && (using_software_rendering_ || have_gpu_argb_visual_); - VisualID visual_id = use_argb && transparent_visual_id_ - ? transparent_visual_id_ - : system_visual_id_; + x11::VisualId visual = use_argb && transparent_visual_id_ != x11::VisualId{} + ? transparent_visual_id_ + : system_visual_id_; - bool success = - GetVisualInfoImpl(visual_id, visual, depth, colormap, visual_has_alpha); + if (visual_id) + *visual_id = visual; + bool success = GetVisualInfoImpl(visual, depth, visual_has_alpha); DCHECK(success); } -bool XVisualManager::GetVisualInfo(VisualID visual_id, - Visual** visual, - int* depth, - Colormap* colormap, +bool XVisualManager::GetVisualInfo(x11::VisualId visual_id, + uint8_t* depth, bool* visual_has_alpha) { base::AutoLock lock(lock_); - return GetVisualInfoImpl(visual_id, visual, depth, colormap, - visual_has_alpha); + return GetVisualInfoImpl(visual_id, depth, visual_has_alpha); } bool XVisualManager::OnGPUInfoChanged(bool software_rendering, - VisualID system_visual_id, - VisualID transparent_visual_id) { + x11::VisualId system_visual_id, + x11::VisualId transparent_visual_id) { base::AutoLock lock(lock_); // TODO(thomasanderson): Cache these visual IDs as a property of the root // window so that newly created browser processes can get them immediately. - if ((system_visual_id && !visuals_.count(system_visual_id)) || - (transparent_visual_id && !visuals_.count(transparent_visual_id))) + if ((system_visual_id != x11::VisualId{} && + !visuals_.count(system_visual_id)) || + (transparent_visual_id != x11::VisualId{} && + !visuals_.count(transparent_visual_id))) return false; using_software_rendering_ = software_rendering; - have_gpu_argb_visual_ = have_gpu_argb_visual_ || transparent_visual_id; - if (system_visual_id) + have_gpu_argb_visual_ = + have_gpu_argb_visual_ || transparent_visual_id != x11::VisualId{}; + if (system_visual_id != x11::VisualId{}) system_visual_id_ = system_visual_id; - if (transparent_visual_id) + if (transparent_visual_id != x11::VisualId{}) transparent_visual_id_ = transparent_visual_id; return true; } bool XVisualManager::ArgbVisualAvailable() const { base::AutoLock lock(lock_); - return using_compositing_wm_ && + return IsCompositingManagerPresent() && (using_software_rendering_ || have_gpu_argb_visual_); } -bool XVisualManager::GetVisualInfoImpl(VisualID visual_id, - Visual** visual, - int* depth, - Colormap* colormap, +bool XVisualManager::GetVisualInfoImpl(x11::VisualId visual_id, + uint8_t* depth, bool* visual_has_alpha) { auto it = visuals_.find(visual_id); if (it == visuals_.end()) return false; - XVisualData& visual_data = *it->second; - const XVisualInfo& visual_info = visual_data.visual_info; - - bool is_default_visual = visual_id == default_visual_id_; + XVisualData& data = *it->second; + const x11::VisualType& info = *data.info; - if (visual) - *visual = visual_info.visual; if (depth) - *depth = visual_info.depth; - if (colormap) - *colormap = - is_default_visual ? 0 /* CopyFromParent */ : visual_data.GetColormap(); + *depth = data.depth; if (visual_has_alpha) { auto popcount = [](auto x) { return std::bitset<8 * sizeof(decltype(x))>(x).count(); }; - *visual_has_alpha = popcount(visual_info.red_mask) + - popcount(visual_info.green_mask) + - popcount(visual_info.blue_mask) < - static_cast<std::size_t>(visual_info.depth); + *visual_has_alpha = popcount(info.red_mask) + popcount(info.green_mask) + + popcount(info.blue_mask) < + static_cast<std::size_t>(data.depth); } return true; } -XVisualManager::XVisualData::XVisualData(XVisualInfo visual_info) - : visual_info(visual_info), colormap_(0 /* CopyFromParent */) {} +XVisualManager::XVisualData::XVisualData(uint8_t depth, + const x11::VisualType* info) + : depth(depth), info(info) {} -// Do not XFreeColormap as this would uninstall the colormap even for -// non-Chromium clients. XVisualManager::XVisualData::~XVisualData() = default; -Colormap XVisualManager::XVisualData::GetColormap() { - XDisplay* display = gfx::GetXDisplay(); - if (colormap_ == 0 /* CopyFromParent */) { - colormap_ = XCreateColormap(display, DefaultRootWindow(display), - visual_info.visual, AllocNone); - } - return colormap_; -} - // ---------------------------------------------------------------------------- // End of x11_util_internal.h diff --git a/chromium/ui/base/x/x11_util.h b/chromium/ui/base/x/x11_util.h index ff1dd2c5635..4c7c574a921 100644 --- a/chromium/ui/base/x/x11_util.h +++ b/chromium/ui/base/x/x11_util.h @@ -21,10 +21,12 @@ #include "base/containers/flat_set.h" #include "base/macros.h" #include "base/memory/ref_counted_memory.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/platform_event.h" #include "ui/gfx/icc_profile.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11_types.h" typedef unsigned long Cursor; @@ -38,9 +40,195 @@ class SkBitmap; namespace ui { +enum WmState : uint32_t { + WM_STATE_WITHDRAWN = 0, + WM_STATE_NORMAL = 1, + WM_STATE_ICONIC = 3, +}; + +enum SizeHintsFlags : int32_t { + SIZE_HINT_US_POSITION = 1 << 0, + SIZE_HINT_US_SIZE = 1 << 1, + SIZE_HINT_P_POSITION = 1 << 2, + SIZE_HINT_P_SIZE = 1 << 3, + SIZE_HINT_P_MIN_SIZE = 1 << 4, + SIZE_HINT_P_MAX_SIZE = 1 << 5, + SIZE_HINT_P_RESIZE_INC = 1 << 6, + SIZE_HINT_P_ASPECT = 1 << 7, + SIZE_HINT_BASE_SIZE = 1 << 8, + SIZE_HINT_P_WIN_GRAVITY = 1 << 9, +}; + +struct SizeHints { + // User specified flags + int32_t flags; + // User-specified position + int32_t x, y; + // User-specified size + int32_t width, height; + // Program-specified minimum size + int32_t min_width, min_height; + // Program-specified maximum size + int32_t max_width, max_height; + // Program-specified resize increments + int32_t width_inc, height_inc; + // Program-specified minimum aspect ratios + int32_t min_aspect_num, min_aspect_den; + // Program-specified maximum aspect ratios + int32_t max_aspect_num, max_aspect_den; + // Program-specified base size + int32_t base_width, base_height; + // Program-specified window gravity + uint32_t win_gravity; +}; + +enum WmHintsFlags : uint32_t { + WM_HINT_INPUT = 1L << 0, + WM_HINT_STATE = 1L << 1, + WM_HINT_ICON_PIXMAP = 1L << 2, + WM_HINT_ICON_WINDOW = 1L << 3, + WM_HINT_ICON_POSITION = 1L << 4, + WM_HINT_ICON_MASK = 1L << 5, + WM_HINT_WINDOW_GROUP = 1L << 6, + // 1L << 7 doesn't have any defined meaning + WM_HINT_X_URGENCY = 1L << 8 +}; + +struct WmHints { + // Marks which fields in this structure are defined + int32_t flags; + // Does this application rely on the window manager to get keyboard input? + uint32_t input; + // See below + int32_t initial_state; + // Pixmap to be used as icon + xcb_pixmap_t icon_pixmap; + // Window to be used as icon + xcb_window_t icon_window; + // Initial position of icon + int32_t icon_x, icon_y; + // Icon mask bitmap + xcb_pixmap_t icon_mask; + // Identifier of related window group + xcb_window_t window_group; +}; + // These functions use the default display and this /must/ be called from // the UI thread. Thus, they don't support multiple displays. +template <typename T> +bool GetArrayProperty(x11::Window window, + x11::Atom name, + std::vector<T>* value, + x11::Atom* out_type = nullptr, + size_t amount = 0) { + static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, ""); + + size_t bytes = amount * sizeof(T); + // The length field specifies the maximum amount of data we would like the + // server to give us. It's specified in units of 4 bytes, so divide by 4. + // Add 3 before division to round up. + size_t length = (bytes + 3) / 4; + using lentype = decltype(x11::GetPropertyRequest::long_length); + auto response = + x11::Connection::Get() + ->GetProperty( + {.window = static_cast<x11::Window>(window), + .property = name, + .long_length = + amount ? length : std::numeric_limits<lentype>::max()}) + .Sync(); + if (!response || response->format != CHAR_BIT * sizeof(T)) + return false; + + DCHECK_EQ(response->format / CHAR_BIT * response->value_len, + response->value.size()); + value->resize(response->value_len); + memcpy(value->data(), response->value.data(), response->value.size()); + if (out_type) + *out_type = response->type; + return true; +} + +template <typename T> +bool GetProperty(x11::Window window, const x11::Atom name, T* value) { + std::vector<T> values; + if (!GetArrayProperty(window, name, &values, nullptr, 1) || values.empty()) + return false; + *value = values[0]; + return true; +} + +template <typename T> +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( + {.window = static_cast<x11::Window>(window), + .property = name, + .type = type, + .format = CHAR_BIT * sizeof(T), + .data_len = values.size(), + .data = data}); +} + +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}); +} + +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) +void DeleteProperty(x11::Window window, x11::Atom name); + +COMPONENT_EXPORT(UI_BASE_X) +bool GetWmNormalHints(x11::Window window, SizeHints* hints); + +COMPONENT_EXPORT(UI_BASE_X) +void SetWmNormalHints(x11::Window window, const SizeHints& hints); + +COMPONENT_EXPORT(UI_BASE_X) +bool GetWmHints(x11::Window window, WmHints* hints); + +COMPONENT_EXPORT(UI_BASE_X) +void SetWmHints(x11::Window window, const WmHints& hints); + +COMPONENT_EXPORT(UI_BASE_X) +void WithdrawWindow(x11::Window window); + +COMPONENT_EXPORT(UI_BASE_X) +void RaiseWindow(x11::Window window); + +COMPONENT_EXPORT(UI_BASE_X) +void LowerWindow(x11::Window window); + +COMPONENT_EXPORT(UI_BASE_X) +void DefineCursor(x11::Window window, x11::Cursor cursor); + +COMPONENT_EXPORT(UI_BASE_X) +x11::Window CreateDummyWindow(const std::string& name = ""); + +COMPONENT_EXPORT(UI_BASE_X) +x11::KeyCode KeysymToKeycode(x11::Connection* connection, x11::KeySym keysym); + // These functions cache their results --------------------------------- // Returns true if the system supports XINPUT2. @@ -73,11 +261,16 @@ COMPONENT_EXPORT(UI_BASE_X) XcursorImage* SkBitmapToXcursorImage(const SkBitmap& bitmap, const gfx::Point& hotspot); +// Loads and returns an X11 cursor, trying to find one that matches |type|. If +// unavailable, x11::None is returned. +COMPONENT_EXPORT(UI_BASE_X) +::Cursor LoadCursorFromType(mojom::CursorType type); + // Coalesce all pending motion events (touch or mouse) that are at the top of // the queue, and return the number eliminated, storing the last one in // |last_event|. COMPONENT_EXPORT(UI_BASE_X) -int CoalescePendingMotionEvents(const XEvent* xev, XEvent* last_event); +int CoalescePendingMotionEvents(const x11::Event* xev, x11::Event* last_event); // Hides the host cursor. COMPONENT_EXPORT(UI_BASE_X) void HideHostCursor(); @@ -87,7 +280,7 @@ COMPONENT_EXPORT(UI_BASE_X)::Cursor CreateInvisibleCursor(); // Sets whether |window| should use the OS window frame. COMPONENT_EXPORT(UI_BASE_X) -void SetUseOSWindowFrame(XID window, bool use_os_window_frame); +void SetUseOSWindowFrame(x11::Window window, bool use_os_window_frame); // These functions do not cache their results -------------------------- @@ -95,122 +288,123 @@ void SetUseOSWindowFrame(XID window, bool use_os_window_frame); COMPONENT_EXPORT(UI_BASE_X) bool IsShapeExtensionAvailable(); // Get the X window id for the default root window -COMPONENT_EXPORT(UI_BASE_X) XID GetX11RootWindow(); +COMPONENT_EXPORT(UI_BASE_X) x11::Window GetX11RootWindow(); // Returns the user's current desktop. COMPONENT_EXPORT(UI_BASE_X) bool GetCurrentDesktop(int* desktop); -enum HideTitlebarWhenMaximized { +enum HideTitlebarWhenMaximized : uint32_t { SHOW_TITLEBAR_WHEN_MAXIMIZED = 0, HIDE_TITLEBAR_WHEN_MAXIMIZED = 1, }; // Sets _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED on |window|. COMPONENT_EXPORT(UI_BASE_X) -void SetHideTitlebarWhenMaximizedProperty(XID window, +void SetHideTitlebarWhenMaximizedProperty(x11::Window window, HideTitlebarWhenMaximized property); // Clears all regions of X11's default root window by filling black pixels. COMPONENT_EXPORT(UI_BASE_X) void ClearX11DefaultRootWindow(); // Returns true if |window| is visible. -COMPONENT_EXPORT(UI_BASE_X) bool IsWindowVisible(XID window); +COMPONENT_EXPORT(UI_BASE_X) bool IsWindowVisible(x11::Window window); // Returns the inner bounds of |window| (excluding the non-client area). COMPONENT_EXPORT(UI_BASE_X) -bool GetInnerWindowBounds(XID window, gfx::Rect* rect); +bool GetInnerWindowBounds(x11::Window window, gfx::Rect* rect); // Returns the non-client area extents of |window|. This is a negative inset; it // represents the negative size of the window border on all sides. // InnerWindowBounds.Inset(WindowExtents) = OuterWindowBounds. // Returns false if the window manager does not provide extents information. COMPONENT_EXPORT(UI_BASE_X) -bool GetWindowExtents(XID window, gfx::Insets* extents); +bool GetWindowExtents(x11::Window window, gfx::Insets* extents); // Returns the outer bounds of |window| (including the non-client area). COMPONENT_EXPORT(UI_BASE_X) -bool GetOuterWindowBounds(XID window, gfx::Rect* rect); +bool GetOuterWindowBounds(x11::Window window, gfx::Rect* rect); // Returns true if |window| contains the point |screen_loc|. COMPONENT_EXPORT(UI_BASE_X) -bool WindowContainsPoint(XID window, gfx::Point screen_loc); +bool WindowContainsPoint(x11::Window window, gfx::Point screen_loc); // Return true if |window| has any property with |property_name|. COMPONENT_EXPORT(UI_BASE_X) -bool PropertyExists(XID window, const std::string& property_name); +bool PropertyExists(x11::Window window, const std::string& property_name); // Returns the raw bytes from a property with minimal // interpretation. |out_data| should be freed by XFree() after use. COMPONENT_EXPORT(UI_BASE_X) -bool GetRawBytesOfProperty(XID window, - XAtom property, - scoped_refptr<base::RefCountedMemory>* out_data, - size_t* out_data_items, - XAtom* out_type); +bool GetRawBytesOfProperty(x11::Window window, + x11::Atom property, + std::vector<uint8_t>* out_data, + x11::Atom* out_type); // Get the value of an int, int array, atom array or string property. On // success, true is returned and the value is stored in |value|. // -// TODO(erg): Once we remove the gtk port and are 100% aura, all of these -// should accept an XAtom instead of a string. -COMPONENT_EXPORT(UI_BASE_X) -bool GetIntProperty(XID window, const std::string& property_name, int* value); +// These functions should no longer be used. TODO(thomasanderson): migrate +// existing callers to {Set,Get}{,Array}Property<> instead. COMPONENT_EXPORT(UI_BASE_X) -bool GetXIDProperty(XID window, const std::string& property_name, XID* value); +bool GetIntProperty(x11::Window window, + const std::string& property_name, + int32_t* value); COMPONENT_EXPORT(UI_BASE_X) -bool GetIntArrayProperty(XID window, +bool GetIntArrayProperty(x11::Window window, const std::string& property_name, - std::vector<int>* value); + std::vector<int32_t>* value); COMPONENT_EXPORT(UI_BASE_X) -bool GetAtomArrayProperty(XID window, +bool GetAtomArrayProperty(x11::Window window, const std::string& property_name, - std::vector<XAtom>* value); + std::vector<x11::Atom>* value); COMPONENT_EXPORT(UI_BASE_X) -bool GetStringProperty(XID window, +bool GetStringProperty(x11::Window window, const std::string& property_name, std::string* value); -// These setters all make round trips. COMPONENT_EXPORT(UI_BASE_X) -bool SetIntProperty(XID window, +void SetIntProperty(x11::Window window, const std::string& name, const std::string& type, - int value); + int32_t value); COMPONENT_EXPORT(UI_BASE_X) -bool SetIntArrayProperty(XID window, +void SetIntArrayProperty(x11::Window window, const std::string& name, const std::string& type, - const std::vector<int>& value); + const std::vector<int32_t>& value); COMPONENT_EXPORT(UI_BASE_X) -bool SetAtomProperty(XID window, +void SetAtomProperty(x11::Window window, const std::string& name, const std::string& type, - XAtom value); + x11::Atom value); COMPONENT_EXPORT(UI_BASE_X) -bool SetAtomArrayProperty(XID window, +void SetAtomArrayProperty(x11::Window window, const std::string& name, const std::string& type, - const std::vector<XAtom>& value); + const std::vector<x11::Atom>& value); COMPONENT_EXPORT(UI_BASE_X) -bool SetStringProperty(XID window, - XAtom property, - XAtom type, +void SetStringProperty(x11::Window window, + x11::Atom property, + x11::Atom type, const std::string& value); // Sets the WM_CLASS attribute for a given X11 window. COMPONENT_EXPORT(UI_BASE_X) -void SetWindowClassHint(XDisplay* display, - XID window, +void SetWindowClassHint(x11::Connection* connection, + x11::Window window, const std::string& res_name, const std::string& res_class); // Sets the WM_WINDOW_ROLE attribute for a given X11 window. COMPONENT_EXPORT(UI_BASE_X) -void SetWindowRole(XDisplay* display, XID window, const std::string& role); +void SetWindowRole(x11::Window window, const std::string& role); // Sends a message to the x11 window manager, enabling or disabling the // states |state1| and |state2|. COMPONENT_EXPORT(UI_BASE_X) -void SetWMSpecState(XID window, bool enabled, XAtom state1, XAtom state2); +void SetWMSpecState(x11::Window window, + bool enabled, + x11::Atom state1, + x11::Atom state2); // Sends a NET_WM_MOVERESIZE message to the x11 window manager, enabling the // move/resize mode. As per NET_WM_MOVERESIZE spec, |location| is the position @@ -218,15 +412,16 @@ void SetWMSpecState(XID window, bool enabled, XAtom state1, XAtom state2); // |direction| indicates whether this is a move or resize event, and if it is a // resize event, which edges of the window the size grip applies to. COMPONENT_EXPORT(UI_BASE_X) -void DoWMMoveResize(XDisplay* display, - XID root_window, - XID window, +void DoWMMoveResize(x11::Connection* connection, + x11::Window root_window, + x11::Window window, const gfx::Point& location_px, int direction); // Checks if the window manager has set a specific state. COMPONENT_EXPORT(UI_BASE_X) -bool HasWMSpecProperty(const base::flat_set<XAtom>& properties, XAtom atom); +bool HasWMSpecProperty(const base::flat_set<x11::Atom>& properties, + x11::Atom atom); // Determine whether we should default to native decorations or the custom // frame based on the currently-running window manager. @@ -235,7 +430,8 @@ COMPONENT_EXPORT(UI_BASE_X) bool GetCustomFramePrefDefault(); static const int kAllDesktops = -1; // Queries the desktop |window| is on, kAllDesktops if sticky. Returns false if // property not found. -COMPONENT_EXPORT(UI_BASE_X) bool GetWindowDesktop(XID window, int* desktop); +COMPONENT_EXPORT(UI_BASE_X) +bool GetWindowDesktop(x11::Window window, int* desktop); // Translates an X11 error code into a printable string. COMPONENT_EXPORT(UI_BASE_X) @@ -245,12 +441,12 @@ std::string GetX11ErrorString(XDisplay* display, int err); // the main display. class EnumerateWindowsDelegate { public: - // |xid| is the X Window ID of the enumerated window. Return true to stop + // |window| is the X Window ID of the enumerated window. Return true to stop // further iteration. - virtual bool ShouldStopIterating(XID xid) = 0; + virtual bool ShouldStopIterating(x11::Window window) = 0; protected: - virtual ~EnumerateWindowsDelegate() {} + virtual ~EnumerateWindowsDelegate() = default; }; // Enumerates all windows in the current display. Will recurse into child @@ -265,7 +461,7 @@ void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate); // Returns all children windows of a given window in top-to-bottom stacking // order. COMPONENT_EXPORT(UI_BASE_X) -bool GetXWindowStack(XID window, std::vector<XID>* windows); +bool GetXWindowStack(x11::Window window, std::vector<x11::Window>* windows); enum WindowManagerName { WM_OTHER, // We were able to obtain the WM's name, but there is @@ -316,10 +512,10 @@ COMPONENT_EXPORT(UI_BASE_X) bool IsCompositingManagerPresent(); COMPONENT_EXPORT(UI_BASE_X) void SetDefaultX11ErrorHandlers(); // Returns true if a given window is in full-screen mode. -COMPONENT_EXPORT(UI_BASE_X) bool IsX11WindowFullScreen(XID window); +COMPONENT_EXPORT(UI_BASE_X) bool IsX11WindowFullScreen(x11::Window window); // Returns true if the window manager supports the given hint. -COMPONENT_EXPORT(UI_BASE_X) bool WmSupportsHint(XAtom atom); +COMPONENT_EXPORT(UI_BASE_X) bool WmSupportsHint(x11::Atom atom); // Returns the ICCProfile corresponding to |monitor| using XGetWindowProperty. COMPONENT_EXPORT(UI_BASE_X) @@ -333,6 +529,15 @@ 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( + x11::Window window, + x11::Window target, + x11::Atom type, + const std::array<uint32_t, 5> data, + x11::EventMask event_mask = x11::EventMask::SubstructureNotify | + x11::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. diff --git a/chromium/ui/base/x/x11_util_internal.h b/chromium/ui/base/x/x11_util_internal.h index cd97da64e02..705c606c7b5 100644 --- a/chromium/ui/base/x/x11_util_internal.h +++ b/chromium/ui/base/x/x11_util_internal.h @@ -55,18 +55,14 @@ class COMPONENT_EXPORT(UI_BASE_X) XVisualManager { public: static XVisualManager* GetInstance(); - // Picks the best argb or opaque visual given |want_argb_visual|. If the - // default visual is returned, |colormap| is set to CopyFromParent. + // Picks the best argb or opaque visual given |want_argb_visual|. void ChooseVisualForWindow(bool want_argb_visual, - Visual** visual, - int* depth, - Colormap* colormap, + x11::VisualId* visual_id, + uint8_t* depth, bool* visual_has_alpha); - bool GetVisualInfo(VisualID visual_id, - Visual** visual, - int* depth, - Colormap* colormap, + bool GetVisualInfo(x11::VisualId visual_id, + uint8_t* depth, bool* visual_has_alpha); // Called by GpuDataManagerImplPrivate when GPUInfo becomes available. It is @@ -74,8 +70,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XVisualManager { // because we don't want to load GL in the browser process. Returns false iff // |default_visual_id| or |transparent_visual_id| are invalid. bool OnGPUInfoChanged(bool software_rendering, - VisualID default_visual_id, - VisualID transparent_visual_id); + x11::VisualId default_visual_id, + x11::VisualId transparent_visual_id); // Are all of the system requirements met for using transparent visuals? bool ArgbVisualAvailable() const; @@ -87,41 +83,34 @@ class COMPONENT_EXPORT(UI_BASE_X) XVisualManager { class XVisualData { public: - explicit XVisualData(XVisualInfo visual_info); + XVisualData(uint8_t depth, const x11::VisualType* info); ~XVisualData(); - Colormap GetColormap(); - - const XVisualInfo visual_info; - - private: - Colormap colormap_; + uint8_t depth = 0; + const x11::VisualType* info = nullptr; }; XVisualManager(); - bool GetVisualInfoImpl(VisualID visual_id, - Visual** visual, - int* depth, - Colormap* colormap, + bool GetVisualInfoImpl(x11::VisualId visual_id, + uint8_t* depth, bool* visual_has_alpha); mutable base::Lock lock_; - std::unordered_map<VisualID, std::unique_ptr<XVisualData>> visuals_; + std::unordered_map<x11::VisualId, std::unique_ptr<XVisualData>> visuals_; - XDisplay* display_; + x11::Connection* const connection_; - VisualID default_visual_id_; + x11::VisualId default_visual_id_{}; // The system visual is usually the same as the default visual, but // may not be in general. - VisualID system_visual_id_; - VisualID transparent_visual_id_; + x11::VisualId system_visual_id_{}; + x11::VisualId transparent_visual_id_{}; - bool using_compositing_wm_; - bool using_software_rendering_; - bool have_gpu_argb_visual_; + bool using_software_rendering_ = false; + bool have_gpu_argb_visual_ = false; DISALLOW_COPY_AND_ASSIGN(XVisualManager); }; diff --git a/chromium/ui/base/x/x11_whole_screen_move_loop.cc b/chromium/ui/base/x/x11_whole_screen_move_loop.cc index 2f7aaf4037a..39f4d0c12aa 100644 --- a/chromium/ui/base/x/x11_whole_screen_move_loop.cc +++ b/chromium/ui/base/x/x11_whole_screen_move_loop.cc @@ -26,25 +26,34 @@ #include "ui/events/platform/x11/x11_event_source.h" #include "ui/events/x/events_x_utils.h" #include "ui/events/x/x11_window_event_manager.h" +#include "ui/gfx/x/connection.h" #include "ui/gfx/x/x11.h" namespace ui { +namespace { + +constexpr x11::KeySym kEscKeysym = static_cast<x11::KeySym>(0xff1b); + // XGrabKey requires the modifier mask to explicitly be specified. -const unsigned int kModifiersMasks[] = {0, // No additional modifier. - Mod2Mask, // Num lock - LockMask, // Caps lock - Mod5Mask, // Scroll lock - Mod2Mask | LockMask, - Mod2Mask | Mod5Mask, - LockMask | Mod5Mask, - Mod2Mask | LockMask | Mod5Mask}; +constexpr x11::ModMask kModifiersMasks[] = { + {}, // No additional modifier. + x11::ModMask::c_2, // Num lock + x11::ModMask::Lock, // Caps lock + x11::ModMask::c_5, // Scroll lock + x11::ModMask::c_2 | x11::ModMask::Lock, + x11::ModMask::c_2 | x11::ModMask::c_5, + x11::ModMask::Lock | x11::ModMask::c_5, + x11::ModMask::c_2 | x11::ModMask::Lock | x11::ModMask::c_5, +}; + +} // namespace X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(X11MoveLoopDelegate* delegate) : delegate_(delegate), in_move_loop_(false), initial_cursor_(x11::None), - grab_input_window_(x11::None), + grab_input_window_(x11::Window::None), grabbed_pointer_(false), canceled_(false) {} @@ -131,7 +140,7 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(bool can_grab_pointer, // restored when the move loop finishes. initial_cursor_ = old_cursor; - CreateDragInputWindow(gfx::GetXDisplay()); + CreateDragInputWindow(x11::Connection::Get()); // Only grab mouse capture of |grab_input_window_| if |can_grab_pointer| is // true aka the source that initiated the move loop doesn't have explicit @@ -145,7 +154,7 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(bool can_grab_pointer, if (can_grab_pointer) { grabbed_pointer_ = GrabPointer(new_cursor); if (!grabbed_pointer_) { - XDestroyWindow(gfx::GetXDisplay(), grab_input_window_); + x11::Connection::Get()->DestroyWindow({grab_input_window_}); return false; } } @@ -194,59 +203,65 @@ void X11WholeScreenMoveLoop::EndMoveLoop() { else UpdateCursor(initial_cursor_); - XDisplay* display = gfx::GetXDisplay(); - unsigned int esc_keycode = XKeysymToKeycode(display, XK_Escape); + auto* connection = x11::Connection::Get(); + auto esc_keycode = KeysymToKeycode(connection, kEscKeysym); for (auto mask : kModifiersMasks) - XUngrabKey(display, esc_keycode, mask, grab_input_window_); + connection->UngrabKey({esc_keycode, grab_input_window_, mask}); // Restore the previous dispatcher. nested_dispatcher_.reset(); delegate_->OnMoveLoopEnded(); grab_input_window_events_.reset(); - XDestroyWindow(display, grab_input_window_); - grab_input_window_ = x11::None; + connection->DestroyWindow({grab_input_window_}); + grab_input_window_ = x11::Window::None; in_move_loop_ = false; std::move(quit_closure_).Run(); } bool X11WholeScreenMoveLoop::GrabPointer(::Cursor cursor) { - XDisplay* display = gfx::GetXDisplay(); + auto* connection = x11::Connection::Get(); // Pass "owner_events" as false so that X sends all mouse events to // |grab_input_window_|. int ret = ui::GrabPointer(grab_input_window_, false, cursor); if (ret != GrabSuccess) { DLOG(ERROR) << "Grabbing pointer for dragging failed: " - << ui::GetX11ErrorString(display, ret); + << ui::GetX11ErrorString(connection->display(), ret); } - XFlush(display); + connection->Flush(); return ret == GrabSuccess; } void X11WholeScreenMoveLoop::GrabEscKey() { - XDisplay* display = gfx::GetXDisplay(); - unsigned int esc_keycode = XKeysymToKeycode(display, XK_Escape); + auto* connection = x11::Connection::Get(); + auto esc_keycode = KeysymToKeycode(connection, kEscKeysym); for (auto mask : kModifiersMasks) { - XGrabKey(display, esc_keycode, mask, grab_input_window_, x11::False, - GrabModeAsync, GrabModeAsync); + connection->GrabKey({false, grab_input_window_, mask, esc_keycode, + x11::GrabMode::Async, x11::GrabMode::Async}); } } -void X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) { - XSetWindowAttributes swa; - memset(&swa, 0, sizeof(swa)); - swa.override_redirect = x11::True; - grab_input_window_ = XCreateWindow(display, DefaultRootWindow(display), -100, - -100, 10, 10, 0, CopyFromParent, InputOnly, - CopyFromParent, CWOverrideRedirect, &swa); +void X11WholeScreenMoveLoop::CreateDragInputWindow( + x11::Connection* connection) { + grab_input_window_ = connection->GenerateId<x11::Window>(); + connection->CreateWindow({ + .wid = grab_input_window_, + .parent = connection->default_root(), + .x = -100, + .y = -100, + .width = 10, + .height = 10, + .c_class = x11::WindowClass::InputOnly, + .override_redirect = x11::Bool32(true), + }); uint32_t event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask; grab_input_window_events_ = std::make_unique<ui::XScopedEventSelector>( grab_input_window_, event_mask); - - XMapRaised(display, grab_input_window_); + connection->MapWindow({grab_input_window_}); + RaiseWindow(grab_input_window_); } } // namespace ui diff --git a/chromium/ui/base/x/x11_whole_screen_move_loop.h b/chromium/ui/base/x/x11_whole_screen_move_loop.h index 1132b905529..eae75d85f04 100644 --- a/chromium/ui/base/x/x11_whole_screen_move_loop.h +++ b/chromium/ui/base/x/x11_whole_screen_move_loop.h @@ -55,7 +55,7 @@ class COMPONENT_EXPORT(UI_BASE_X) X11WholeScreenMoveLoop void GrabEscKey(); // Creates an input-only window to be used during the drag. - void CreateDragInputWindow(XDisplay* display); + void CreateDragInputWindow(x11::Connection* connection); // Dispatch mouse movement event to |delegate_| in a posted task. void DispatchMouseMovement(); @@ -74,7 +74,7 @@ class COMPONENT_EXPORT(UI_BASE_X) X11WholeScreenMoveLoop // An invisible InputOnly window. Keyboard grab and sometimes mouse grab // are set on this window. - XID grab_input_window_; + x11::Window grab_input_window_; // Events selected on |grab_input_window_|. std::unique_ptr<ui::XScopedEventSelector> grab_input_window_events_; diff --git a/chromium/ui/base/x/x11_window.cc b/chromium/ui/base/x/x11_window.cc index 70f520bccd4..bc5f4fefa7a 100644 --- a/chromium/ui/base/x/x11_window.cc +++ b/chromium/ui/base/x/x11_window.cc @@ -13,6 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "net/base/network_interfaces.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/base/hit_test_x11.h" #include "ui/base/wm_role_names_linux.h" @@ -31,9 +32,13 @@ #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/skia_util.h" +#include "ui/gfx/x/connection.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_error_tracker.h" #include "ui/gfx/x/x11_path.h" +#include "ui/gfx/x/xfixes.h" +#include "ui/gfx/x/xinput.h" +#include "ui/gfx/x/xproto.h" #include "ui/platform_window/common/platform_window_defaults.h" namespace ui { @@ -46,7 +51,7 @@ const int kAllWorkspaces = 0xFFFFFFFF; constexpr char kX11WindowRolePopup[] = "popup"; constexpr char kX11WindowRoleBubble[] = "bubble"; -constexpr unsigned char kDarkGtkThemeVariant[] = "dark"; +constexpr char kDarkGtkThemeVariant[] = "dark"; constexpr long kSystemTrayRequestDock = 0; @@ -54,6 +59,11 @@ constexpr int kXembedInfoProtocolVersion = 0; constexpr int kXembedFlagMap = 1 << 0; constexpr int kXembedInfoFlags = kXembedFlagMap; +enum CrossingFlags : uint8_t { + CROSSING_FLAG_FOCUS = 1 << 0, + CROSSING_FLAG_SAME_SCREEN = 1 << 1, +}; + // In some situations, views tries to make a zero sized window, and that // makes us crash. Make sure we have valid sizes. gfx::Rect SanitizeBounds(const gfx::Rect& bounds) { @@ -64,59 +74,76 @@ gfx::Rect SanitizeBounds(const gfx::Rect& bounds) { } void SerializeImageRepresentation(const gfx::ImageSkiaRep& rep, - std::vector<unsigned long>* data) { - int width = rep.GetWidth(); + std::vector<uint32_t>* data) { + uint32_t width = rep.GetWidth(); data->push_back(width); - int height = rep.GetHeight(); + uint32_t height = rep.GetHeight(); data->push_back(height); const SkBitmap& bitmap = rep.GetBitmap(); - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) + for (uint32_t y = 0; y < height; ++y) + for (uint32_t x = 0; x < width; ++x) data->push_back(bitmap.getColor(x, y)); } -int XI2ModeToXMode(int xi2_mode) { +x11::NotifyMode XI2ModeToXMode(x11::Input::NotifyMode xi2_mode) { switch (xi2_mode) { - case XINotifyNormal: - return NotifyNormal; - case XINotifyGrab: - case XINotifyPassiveGrab: - return NotifyGrab; - case XINotifyUngrab: - case XINotifyPassiveUngrab: - return NotifyUngrab; - case XINotifyWhileGrabbed: - return NotifyWhileGrabbed; + case x11::Input::NotifyMode::Normal: + return x11::NotifyMode::Normal; + case x11::Input::NotifyMode::Grab: + case x11::Input::NotifyMode::PassiveGrab: + return x11::NotifyMode::Grab; + case x11::Input::NotifyMode::Ungrab: + case x11::Input::NotifyMode::PassiveUngrab: + return x11::NotifyMode::Ungrab; + case x11::Input::NotifyMode::WhileGrabbed: + return x11::NotifyMode::WhileGrabbed; default: NOTREACHED(); - return NotifyNormal; + return x11::NotifyMode::Normal; } } -bool SyncSetCounter(XDisplay* display, XID counter, int64_t value) { - XSyncValue sync_value; - XSyncIntsToValue(&sync_value, value & 0xFFFFFFFF, value >> 32); - return XSyncSetCounter(display, counter, sync_value) == x11::True; +x11::NotifyDetail XI2DetailToXDetail(x11::Input::NotifyDetail xi2_detail) { + switch (xi2_detail) { + case x11::Input::NotifyDetail::Ancestor: + return x11::NotifyDetail::Ancestor; + case x11::Input::NotifyDetail::Virtual: + return x11::NotifyDetail::Virtual; + case x11::Input::NotifyDetail::Inferior: + return x11::NotifyDetail::Inferior; + case x11::Input::NotifyDetail::Nonlinear: + return x11::NotifyDetail::Nonlinear; + case x11::Input::NotifyDetail::NonlinearVirtual: + return x11::NotifyDetail::NonlinearVirtual; + case x11::Input::NotifyDetail::Pointer: + return x11::NotifyDetail::Pointer; + case x11::Input::NotifyDetail::PointerRoot: + return x11::NotifyDetail::PointerRoot; + case x11::Input::NotifyDetail::None: + return x11::NotifyDetail::None; + } } -// Returns the whole path from |window| to the root. -std::vector<::Window> GetParentsList(XDisplay* xdisplay, ::Window window) { - ::Window parent_win, root_win; - Window* child_windows; - unsigned int num_child_windows; - std::vector<::Window> result; +void SyncSetCounter(x11::Connection* connection, + x11::Sync::Counter counter, + int64_t value) { + x11::Sync::Int64 sync_value{.hi = value >> 32, .lo = value & 0xFFFFFFFF}; + connection->sync().SetCounter({counter, sync_value}); +} - while (window) { +// Returns the whole path from |window| to the root. +std::vector<x11::Window> GetParentsList(x11::Connection* connection, + x11::Window window) { + std::vector<x11::Window> result; + while (window != x11::Window::None) { result.push_back(window); - if (!XQueryTree(xdisplay, window, &root_win, &parent_win, &child_windows, - &num_child_windows)) + if (auto reply = connection->QueryTree({window}).Sync()) + window = reply->parent; + else break; - if (child_windows) - XFree(child_windows); - window = parent_win; } return result; } @@ -139,15 +166,15 @@ XWindow::Configuration::Configuration(const Configuration&) = default; XWindow::Configuration::~Configuration() = default; XWindow::XWindow() - : xdisplay_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(xdisplay_)) { - DCHECK(xdisplay_); - DCHECK_NE(x_root_window_, x11::None); + : connection_(x11::Connection::Get()), x_root_window_(GetX11RootWindow()) { + DCHECK(connection_); + DCHECK_NE(x_root_window_, x11::Window::None); } XWindow::~XWindow() { - DCHECK_EQ(xwindow_, x11::None) << "XWindow destructed without calling " - "Close() to release allocated resources."; + DCHECK_EQ(xwindow_, x11::Window::None) + << "XWindow destructed without calling " + "Close() to release allocated resources."; } void XWindow::Init(const Configuration& config) { @@ -157,31 +184,28 @@ void XWindow::Init(const Configuration& config) { activatable_ = config.activatable; - unsigned long attribute_mask = CWBackPixel | CWBitGravity; - XSetWindowAttributes swa; - memset(&swa, 0, sizeof(swa)); - swa.background_pixmap = x11::None; - swa.bit_gravity = NorthWestGravity; - swa.background_pixel = config.background_color.has_value() + x11::CreateWindowRequest req; + req.bit_gravity = x11::Gravity::NorthWest; + req.background_pixel = config.background_color.has_value() ? config.background_color.value() - : WhitePixel(xdisplay_, DefaultScreen(xdisplay_)); + : connection_->default_screen().white_pixel; - XAtom window_type; + x11::Atom window_type; switch (config.type) { case WindowType::kMenu: - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_MENU"); break; case WindowType::kTooltip: - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP"); break; case WindowType::kPopup: - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION"); break; case WindowType::kDrag: - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_DND"); break; default: @@ -190,7 +214,7 @@ void XWindow::Init(const Configuration& config) { } // An in-activatable window should not interact with the system wm. if (!activatable_ || config.override_redirect) - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); #if !defined(USE_X11) // It seems like there is a difference how tests are instantiated in case of @@ -204,12 +228,10 @@ void XWindow::Init(const Configuration& config) { // here. Otherwise, tests for non-Ozone X11 fail. // TODO(msisov): figure out usage of this for non-Ozone X11. if (UseTestConfigForPlatformWindows()) - swa.override_redirect = true; + req.override_redirect = x11::Bool32(true); #endif - override_redirect_ = swa.override_redirect == x11::True; - if (override_redirect_) - attribute_mask |= CWOverrideRedirect; + override_redirect_ = req.override_redirect.has_value(); bool enable_transparent_visuals; switch (config.opacity) { @@ -223,44 +245,42 @@ void XWindow::Init(const Configuration& config) { enable_transparent_visuals = config.type == WindowType::kDrag; } - int visual_id; if (config.wm_role_name == kStatusIconWmRoleName) { std::string atom_name = - "_NET_SYSTEM_TRAY_S" + base::NumberToString(DefaultScreen(xdisplay_)); - XID manager = - XGetSelectionOwner(xdisplay_, gfx::GetAtom(atom_name.c_str())); - if (ui::GetIntProperty(manager, "_NET_SYSTEM_TRAY_VISUAL", &visual_id)) - visual_id_ = visual_id; - } - - Visual* visual = CopyFromParent; - int depth = CopyFromParent; - Colormap colormap = CopyFromParent; - ui::XVisualManager* visual_manager = ui::XVisualManager::GetInstance(); - if (!visual_id_ || - !visual_manager->GetVisualInfo(visual_id_, &visual, &depth, &colormap, - &visual_has_alpha_)) { - visual_manager->ChooseVisualForWindow(enable_transparent_visuals, &visual, - &depth, &colormap, - &visual_has_alpha_); + "_NET_SYSTEM_TRAY_S" + + base::NumberToString(connection_->DefaultScreenId()); + auto selection = connection_->GetSelectionOwner({gfx::GetAtom(atom_name)}); + if (auto reply = selection.Sync()) { + GetProperty(reply->owner, gfx::GetAtom("_NET_SYSTEM_TRAY_VISUAL"), + &visual_id_); + } } - if (colormap != CopyFromParent) { - attribute_mask |= CWColormap; - swa.colormap = colormap; + x11::VisualId visual_id = visual_id_; + uint8_t depth = 0; + XVisualManager* visual_manager = XVisualManager::GetInstance(); + if (visual_id_ == x11::VisualId{} || + !visual_manager->GetVisualInfo(visual_id_, &depth, &visual_has_alpha_)) { + visual_manager->ChooseVisualForWindow( + enable_transparent_visuals, &visual_id, &depth, &visual_has_alpha_); } // x.org will BadMatch if we don't set a border when the depth isn't the // same as the parent depth. - attribute_mask |= CWBorderPixel; - swa.border_pixel = 0; + req.border_pixel = 0; bounds_in_pixels_ = SanitizeBounds(config.bounds); - xwindow_ = XCreateWindow(xdisplay_, x_root_window_, bounds_in_pixels_.x(), - bounds_in_pixels_.y(), bounds_in_pixels_.width(), - bounds_in_pixels_.height(), - 0, // border width - depth, InputOutput, visual, attribute_mask, &swa); + req.parent = x_root_window_; + req.x = bounds_in_pixels_.x(); + req.y = bounds_in_pixels_.y(); + req.width = bounds_in_pixels_.width(); + req.height = bounds_in_pixels_.height(); + req.depth = depth; + req.c_class = x11::WindowClass::InputOutput; + req.visual = visual_id; + xwindow_ = connection_->GenerateId<x11::Window>(); + req.wid = xwindow_; + connection_->CreateWindow(req); // It can be a status icon window. If it fails to initialize, don't provide // him with a native window handle, close self and let the client destroy @@ -281,15 +301,12 @@ void XWindow::Init(const Configuration& config) { StructureNotifyMask | PropertyChangeMask | PointerMotionMask; xwindow_events_ = - std::make_unique<ui::XScopedEventSelector>(xwindow_, event_mask); - XFlush(xdisplay_); + std::make_unique<XScopedEventSelector>(xwindow_, event_mask); + connection_->Flush(); - if (ui::IsXInput2Available()) - ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); + if (IsXInput2Available()) + TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); - // TODO(erg): We currently only request window deletion events. We also - // should listen for activation events and anything else that GTK+ listens - // for, and do something useful. // Request the _NET_WM_SYNC_REQUEST protocol which is used for synchronizing // between chrome and desktop compositor (or WM) during resizing. // The resizing behavior with _NET_WM_SYNC_REQUEST is: @@ -305,31 +322,29 @@ void XWindow::Init(const Configuration& config) { // frame with new content from chrome. // 7. Desktop compositor responses user mouse move events, and starts a new // resize process, go to step 1. - XAtom protocols[] = { + std::vector<x11::Atom> protocols = { gfx::GetAtom("WM_DELETE_WINDOW"), gfx::GetAtom("_NET_WM_PING"), gfx::GetAtom("_NET_WM_SYNC_REQUEST"), }; - XSetWMProtocols(xdisplay_, xwindow_, protocols, base::size(protocols)); + SetArrayProperty(xwindow_, gfx::GetAtom("WM_PROTOCOLS"), x11::Atom::ATOM, + protocols); - // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with - // the desktop environment. - XSetWMProperties(xdisplay_, xwindow_, nullptr, nullptr, nullptr, 0, nullptr, - nullptr, nullptr); + // We need a WM_CLIENT_MACHINE value so we integrate with the desktop + // environment. + SetStringProperty(xwindow_, gfx::GetAtom("WM_CLIENT_MACHINE"), + gfx::GetAtom("STRING"), net::GetHostName()); // Likewise, the X server needs to know this window's pid so it knows which // program to kill if the window hangs. // XChangeProperty() expects "pid" to be long. - static_assert(sizeof(long) >= sizeof(pid_t), - "pid_t should not be larger than long"); - long pid = getpid(); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_PID"), XA_CARDINAL, - 32, PropModeReplace, reinterpret_cast<unsigned char*>(&pid), - 1); + static_assert(sizeof(uint32_t) >= sizeof(pid_t), + "pid_t should not be larger than uint32_t"); + uint32_t pid = getpid(); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_PID"), x11::Atom::CARDINAL, pid); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_WINDOW_TYPE"), - XA_ATOM, 32, PropModeReplace, - reinterpret_cast<unsigned char*>(&window_type), 1); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_TYPE"), x11::Atom::ATOM, + window_type); // The changes to |window_properties_| here will be sent to the X server just // before the window is mapped. @@ -350,16 +365,16 @@ void XWindow::Init(const Configuration& config) { workspace_ = base::nullopt; if (config.visible_on_all_workspaces) { window_properties_.insert(gfx::GetAtom("_NET_WM_STATE_STICKY")); - ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllWorkspaces); + SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllWorkspaces); } else if (!config.workspace.empty()) { int workspace; if (base::StringToInt(config.workspace, &workspace)) - ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", workspace); + SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", workspace); } if (!config.wm_class_name.empty() || !config.wm_class_class.empty()) { - ui::SetWindowClassHint(xdisplay_, xwindow_, config.wm_class_name, - config.wm_class_class); + SetWindowClassHint(connection_, xwindow_, config.wm_class_name, + config.wm_class_class); } const char* wm_role_name = nullptr; @@ -380,40 +395,40 @@ void XWindow::Init(const Configuration& config) { } } if (wm_role_name) - ui::SetWindowRole(xdisplay_, xwindow_, std::string(wm_role_name)); + SetWindowRole(xwindow_, std::string(wm_role_name)); if (config.remove_standard_frame) { // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force // fullscreen on the window when it matches the desktop size. - ui::SetHideTitlebarWhenMaximizedProperty(xwindow_, - ui::HIDE_TITLEBAR_WHEN_MAXIMIZED); + SetHideTitlebarWhenMaximizedProperty(xwindow_, + HIDE_TITLEBAR_WHEN_MAXIMIZED); } if (config.prefer_dark_theme) { - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_GTK_THEME_VARIANT"), - gfx::GetAtom("UTF8_STRING"), 8, PropModeReplace, - kDarkGtkThemeVariant, base::size(kDarkGtkThemeVariant) - 1); + SetStringProperty(xwindow_, gfx::GetAtom("_GTK_THEME_VARIANT"), + gfx::GetAtom("UTF8_STRING"), kDarkGtkThemeVariant); } - if (ui::IsSyncExtensionAvailable()) { - XSyncValue value; - XSyncIntToValue(&value, 0); - update_counter_ = XSyncCreateCounter(xdisplay_, value); - extended_update_counter_ = XSyncCreateCounter(xdisplay_, value); - XID counters[]{update_counter_, extended_update_counter_}; + if (IsSyncExtensionAvailable()) { + x11::Sync::Int64 value{}; + update_counter_ = connection_->GenerateId<x11::Sync::Counter>(); + connection_->sync().CreateCounter({update_counter_, value}); + extended_update_counter_ = connection_->GenerateId<x11::Sync::Counter>(); + connection_->sync().CreateCounter({extended_update_counter_, value}); + + std::vector<x11::Sync::Counter> counters{update_counter_, + extended_update_counter_}; // Set XSyncCounter as window property _NET_WM_SYNC_REQUEST_COUNTER. the // compositor will listen on them during resizing. - XChangeProperty( - xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_SYNC_REQUEST_COUNTER"), - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast<const unsigned char*>(counters), base::size(counters)); + SetArrayProperty(xwindow_, gfx::GetAtom("_NET_WM_SYNC_REQUEST_COUNTER"), + x11::Atom::CARDINAL, counters); } // Always composite Chromium windows if a compositing WM is used. Sometimes, // WMs will not composite fullscreen windows as an optimization, but this can // lead to tearing of fullscreen videos. - ui::SetIntProperty(xwindow_, "_NET_WM_BYPASS_COMPOSITOR", "CARDINAL", 2); + SetIntProperty(xwindow_, "_NET_WM_BYPASS_COMPOSITOR", "CARDINAL", 2); if (config.icon) SetXWindowIcons(gfx::ImageSkia(), *config.icon); @@ -422,58 +437,55 @@ void XWindow::Init(const Configuration& config) { void XWindow::Map(bool inactive) { // Before we map the window, set size hints. Otherwise, some window managers // will ignore toplevel XMoveWindow commands. - XSizeHints size_hints; - size_hints.flags = 0; - long supplied_return; - XGetWMNormalHints(xdisplay_, xwindow_, &size_hints, &supplied_return); - size_hints.flags |= PPosition; + SizeHints size_hints; + memset(&size_hints, 0, sizeof(size_hints)); + GetWmNormalHints(xwindow_, &size_hints); + size_hints.flags |= SIZE_HINT_P_POSITION; size_hints.x = bounds_in_pixels_.x(); size_hints.y = bounds_in_pixels_.y(); - XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); + SetWmNormalHints(xwindow_, size_hints); ignore_keyboard_input_ = inactive; - unsigned long wm_user_time_ms = + uint32_t wm_user_time_ms = ignore_keyboard_input_ ? 0 : X11EventSource::GetInstance()->GetTimestamp(); if (inactive || wm_user_time_ms != 0) { - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"), - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast<const unsigned char*>(&wm_user_time_ms), - 1); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"), + x11::Atom::CARDINAL, wm_user_time_ms); } UpdateMinAndMaxSize(); if (window_properties_.empty()) { - XDeleteProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_STATE")); + DeleteProperty(xwindow_, gfx::GetAtom("_NET_WM_STATE")); } else { - ui::SetAtomArrayProperty(xwindow_, "_NET_WM_STATE", "ATOM", - std::vector<XAtom>(std::begin(window_properties_), + SetAtomArrayProperty(xwindow_, "_NET_WM_STATE", "ATOM", + std::vector<x11::Atom>(std::begin(window_properties_), std::end(window_properties_))); } - XMapWindow(xdisplay_, xwindow_); + connection_->MapWindow({xwindow_}); window_mapped_in_client_ = true; // TODO(thomasanderson): Find out why this flush is necessary. - XFlush(xdisplay_); + connection_->Flush(); } void XWindow::Close() { - if (xwindow_ == x11::None) + if (xwindow_ == x11::Window::None) return; CancelResize(); UnconfineCursor(); - XDestroyWindow(xdisplay_, xwindow_); - xwindow_ = x11::None; + connection_->DestroyWindow({xwindow_}); + xwindow_ = x11::Window::None; - if (update_counter_ != x11::None) { - XSyncDestroyCounter(xdisplay_, update_counter_); - XSyncDestroyCounter(xdisplay_, extended_update_counter_); - update_counter_ = x11::None; - extended_update_counter_ = x11::None; + if (update_counter_ != x11::Sync::Counter{}) { + connection_->sync().DestroyCounter({update_counter_}); + connection_->sync().DestroyCounter({extended_update_counter_}); + update_counter_ = {}; + extended_update_counter_ = {}; } } @@ -487,10 +499,12 @@ void XWindow::Maximize() { } void XWindow::Minimize() { - if (window_mapped_in_client_) - XIconifyWindow(xdisplay_, xwindow_, 0); - else - SetWMSpecState(true, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::None); + if (window_mapped_in_client_) { + SendClientMessage(xwindow_, x_root_window_, gfx::GetAtom("WM_CHANGE_STATE"), + {WM_STATE_ICONIC, 0, 0, 0, 0}); + } else { + SetWMSpecState(true, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None); + } } void XWindow::Unmaximize() { @@ -506,18 +520,18 @@ bool XWindow::Hide() { // Make sure no resize task will run after the window is unmapped. CancelResize(); - XWithdrawWindow(xdisplay_, xwindow_, 0); + WithdrawWindow(xwindow_); window_mapped_in_client_ = false; return true; } void XWindow::Unhide() { - SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::None); + SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None); } void XWindow::SetFullscreen(bool fullscreen) { SetWMSpecState(fullscreen, gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"), - x11::None); + x11::Atom::None); } void XWindow::Activate() { @@ -531,45 +545,41 @@ void XWindow::Activate() { // wmii says that it supports _NET_ACTIVE_WINDOW but does not. // https://code.google.com/p/wmii/issues/detail?id=266 static bool wm_supports_active_window = - ui::GuessWindowManager() != ui::WM_WMII && - ui::WmSupportsHint(gfx::GetAtom("_NET_ACTIVE_WINDOW")); + GuessWindowManager() != WM_WMII && + WmSupportsHint(gfx::GetAtom("_NET_ACTIVE_WINDOW")); ::Time timestamp = X11EventSource::GetInstance()->GetTimestamp(); // override_redirect windows ignore _NET_ACTIVE_WINDOW. // https://crbug.com/940924 if (wm_supports_active_window && !override_redirect_) { - XEvent xclient; - memset(&xclient, 0, sizeof(xclient)); - xclient.type = ClientMessage; - xclient.xclient.window = xwindow_; - xclient.xclient.message_type = gfx::GetAtom("_NET_ACTIVE_WINDOW"); - xclient.xclient.format = 32; - xclient.xclient.data.l[0] = 1; // Specified we are an app. - xclient.xclient.data.l[1] = timestamp; - // TODO(thomasanderson): if another chrome window is active, specify that in - // data.l[2]. The EWMH spec claims this may make the WM more likely to - // service our _NET_ACTIVE_WINDOW request. - xclient.xclient.data.l[2] = x11::None; - xclient.xclient.data.l[3] = 0; - xclient.xclient.data.l[4] = 0; - - XSendEvent(xdisplay_, x_root_window_, x11::False, - SubstructureRedirectMask | SubstructureNotifyMask, &xclient); + std::array<uint32_t, 5> data = { + // We're an app. + 1, + timestamp, + // TODO(thomasanderson): if another chrome window is active, specify + // that here. The EWMH spec claims this may make the WM more likely to + // service our _NET_ACTIVE_WINDOW request. + 0, + 0, + 0, + }; + SendClientMessage(xwindow_, x_root_window_, + gfx::GetAtom("_NET_ACTIVE_WINDOW"), data); } else { - XRaiseWindow(xdisplay_, xwindow_); + RaiseWindow(xwindow_); // Directly ask the X server to give focus to the window. Note that the call // would have raised an X error if the window is not mapped. - auto ignore_errors = [](XDisplay*, XErrorEvent*) -> int { return 0; }; - auto old_error_handler = XSetErrorHandler(ignore_errors); - XSetInputFocus(xdisplay_, xwindow_, RevertToParent, timestamp); + connection_ + ->SetInputFocus({x11::InputFocus::Parent, xwindow_, + static_cast<x11::Time>(timestamp)}) + .IgnoreError(); // At this point, we know we will receive focus, and some // webdriver tests depend on a window being IsActive() immediately // after an Activate(), so just set this state now. has_pointer_focus_ = false; has_window_focus_ = true; window_mapped_in_server_ = true; - XSetErrorHandler(old_error_handler); } AfterActivationStateChanged(); @@ -581,7 +591,7 @@ void XWindow::Deactivate() { // Ignore future input events. ignore_keyboard_input_ = true; - XLowerWindow(xdisplay_, xwindow_); + ui::LowerWindow(xwindow_); AfterActivationStateChanged(); } @@ -594,8 +604,9 @@ bool XWindow::IsActive() const { return (has_window_focus_ || has_pointer_focus_) && !ignore_keyboard_input_; } void XWindow::SetSize(const gfx::Size& size_in_pixels) { - XResizeWindow(xdisplay_, xwindow_, size_in_pixels.width(), - size_in_pixels.height()); + connection_->ConfigureWindow({.window = xwindow_, + .width = size_in_pixels.width(), + .height = size_in_pixels.height()}); bounds_in_pixels_.set_size(size_in_pixels); } @@ -603,8 +614,8 @@ void XWindow::SetBounds(const gfx::Rect& requested_bounds_in_pixels) { gfx::Rect bounds_in_pixels(requested_bounds_in_pixels); bool origin_changed = bounds_in_pixels_.origin() != bounds_in_pixels.origin(); bool size_changed = bounds_in_pixels_.size() != bounds_in_pixels.size(); - XWindowChanges changes = {0}; - unsigned value_mask = 0; + + x11::ConfigureWindowRequest req{.window = xwindow_}; if (size_changed) { // Update the minimum and maximum sizes in case they have changed. @@ -622,19 +633,17 @@ void XWindow::SetBounds(const gfx::Rect& requested_bounds_in_pixels) { bounds_in_pixels.set_size(size_in_pixels); } - changes.width = bounds_in_pixels.width(); - changes.height = bounds_in_pixels.height(); - value_mask |= CWHeight | CWWidth; + req.width = bounds_in_pixels.width(); + req.height = bounds_in_pixels.height(); } if (origin_changed) { - changes.x = bounds_in_pixels.x(); - changes.y = bounds_in_pixels.y(); - value_mask |= CWX | CWY; + req.x = bounds_in_pixels.x(); + req.y = bounds_in_pixels.y(); } - if (value_mask) - XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes); + if (origin_changed || size_changed) + connection_->ConfigureWindow(req); // Assume that the resize will go through as requested, which should be the // case if we're running without a window manager. If there's a window @@ -658,23 +667,23 @@ bool XWindow::IsXWindowVisible() const { } bool XWindow::IsMinimized() const { - return ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_HIDDEN")); + return HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_HIDDEN")); } bool XWindow::IsMaximized() const { - return (ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) && - ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"))); + return (HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) && + HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"))); } bool XWindow::IsFullscreen() const { - return ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_FULLSCREEN")); + return HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_FULLSCREEN")); } -gfx::Rect XWindow::GetOutterBounds() const { +gfx::Rect XWindow::GetOuterBounds() const { gfx::Rect outer_bounds(bounds_in_pixels_); outer_bounds.Inset(-native_window_frame_borders_in_pixels_); return outer_bounds; @@ -687,18 +696,18 @@ void XWindow::GrabPointer() { } void XWindow::ReleasePointerGrab() { - ui::UngrabPointer(); + UngrabPointer(); has_pointer_grab_ = false; } -void XWindow::StackXWindowAbove(::Window window) { - DCHECK(window != x11::None); +void XWindow::StackXWindowAbove(x11::Window window) { + DCHECK(window != x11::Window::None); // Find all parent windows up to the root. - std::vector<::Window> window_below_parents = - GetParentsList(xdisplay_, window); - std::vector<::Window> window_above_parents = - GetParentsList(xdisplay_, xwindow_); + std::vector<x11::Window> window_below_parents = + GetParentsList(connection_, window); + std::vector<x11::Window> window_above_parents = + GetParentsList(connection_, xwindow_); // Find their common ancestor. auto it_below_window = window_below_parents.rbegin(); @@ -711,23 +720,21 @@ void XWindow::StackXWindowAbove(::Window window) { if (it_below_window != window_below_parents.rend() && it_above_window != window_above_parents.rend()) { - // First stack |xwindow| below so Z-order of |window| stays the same. - ::Window windows[] = {*it_below_window, *it_above_window}; - if (XRestackWindows(xdisplay_, windows, 2) == 0) { - // Now stack them properly. - std::swap(windows[0], windows[1]); - XRestackWindows(xdisplay_, windows, 2); - } + connection_->ConfigureWindow({ + .window = *it_above_window, + .sibling = *it_below_window, + .stack_mode = x11::StackMode::Above, + }); } } void XWindow::StackXWindowAtTop() { - XRaiseWindow(xdisplay_, xwindow_); + RaiseWindow(xwindow_); } void XWindow::SetCursor(::Cursor cursor) { last_cursor_ = cursor; - XDefineCursor(xdisplay_, xwindow_, cursor); + DefineCursor(xwindow_, static_cast<x11::Cursor>(cursor)); } bool XWindow::SetTitle(base::string16 title) { @@ -736,17 +743,10 @@ bool XWindow::SetTitle(base::string16 title) { window_title_ = title; std::string utf8str = base::UTF16ToUTF8(title); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_NAME"), - gfx::GetAtom("UTF8_STRING"), 8, PropModeReplace, - reinterpret_cast<const unsigned char*>(utf8str.c_str()), - utf8str.size()); - XTextProperty xtp; - char* c_utf8_str = const_cast<char*>(utf8str.c_str()); - if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1, XUTF8StringStyle, - &xtp) == x11::Success) { - XSetWMName(xdisplay_, xwindow_, &xtp); - XFree(xtp.value); - } + SetStringProperty(xwindow_, gfx::GetAtom("_NET_WM_NAME"), + gfx::GetAtom("UTF8_STRING"), utf8str); + SetStringProperty(xwindow_, x11::Atom::WM_NAME, gfx::GetAtom("UTF8_STRING"), + utf8str); return true; } @@ -756,35 +756,35 @@ void XWindow::SetXWindowOpacity(float opacity) { // XChangeProperty() expects "cardinality" to be long. // Scale opacity to [0 .. 255] range. - unsigned long opacity_8bit = - static_cast<unsigned long>(opacity * 255.0f) & 0xFF; + uint32_t opacity_8bit = static_cast<uint32_t>(opacity * 255.0f) & 0xFF; // Use opacity value for all channels. - const unsigned long channel_multiplier = 0x1010101; - unsigned long cardinality = opacity_8bit * channel_multiplier; + uint32_t channel_multiplier = 0x1010101; + uint32_t cardinality = opacity_8bit * channel_multiplier; if (cardinality == 0xffffffff) { - XDeleteProperty(xdisplay_, xwindow_, - gfx::GetAtom("_NET_WM_WINDOW_OPACITY")); + DeleteProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_OPACITY")); } else { - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_WINDOW_OPACITY"), - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast<unsigned char*>(&cardinality), 1); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_OPACITY"), + x11::Atom::CARDINAL, cardinality); } } void XWindow::SetXWindowAspectRatio(const gfx::SizeF& aspect_ratio) { - XSizeHints size_hints; - size_hints.flags = 0; - long supplied_return; + SizeHints size_hints; + memset(&size_hints, 0, sizeof(size_hints)); - XGetWMNormalHints(xdisplay_, xwindow_, &size_hints, &supplied_return); + GetWmNormalHints(xwindow_, &size_hints); // Unforce aspect ratio is parameter length is 0, otherwise set normally. - if (!aspect_ratio.IsEmpty()) { - size_hints.flags |= PAspect; - size_hints.min_aspect.x = size_hints.max_aspect.x = aspect_ratio.width(); - size_hints.min_aspect.y = size_hints.max_aspect.y = aspect_ratio.height(); + if (aspect_ratio.IsEmpty()) { + size_hints.flags &= ~SIZE_HINT_P_ASPECT; + } else { + size_hints.flags |= SIZE_HINT_P_ASPECT; + size_hints.min_aspect_num = size_hints.max_aspect_num = + aspect_ratio.width(); + size_hints.min_aspect_den = size_hints.max_aspect_den = + aspect_ratio.height(); } - XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); + SetWmNormalHints(xwindow_, size_hints); } void XWindow::SetXWindowIcons(const gfx::ImageSkia& window_icon, @@ -797,7 +797,7 @@ void XWindow::SetXWindowIcons(const gfx::ImageSkia& window_icon, // so that we can pass to the WM. // // All of this could be made much, much better. - std::vector<unsigned long> data; + std::vector<uint32_t> data; if (!window_icon.isNull()) SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data); @@ -805,35 +805,27 @@ void XWindow::SetXWindowIcons(const gfx::ImageSkia& window_icon, if (!app_icon.isNull()) SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data); - if (!data.empty()) - ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data); + if (!data.empty()) { + SetArrayProperty(xwindow_, gfx::GetAtom("_NET_WM_ICON"), + x11::Atom::CARDINAL, data); + } } void XWindow::SetXWindowVisibleOnAllWorkspaces(bool visible) { - SetWMSpecState(visible, gfx::GetAtom("_NET_WM_STATE_STICKY"), x11::None); + SetWMSpecState(visible, gfx::GetAtom("_NET_WM_STATE_STICKY"), + x11::Atom::None); int new_desktop = 0; if (visible) { new_desktop = kAllWorkspaces; } else { - if (!ui::GetCurrentDesktop(&new_desktop)) + if (!GetCurrentDesktop(&new_desktop)) return; } workspace_ = kAllWorkspaces; - XEvent xevent; - memset(&xevent, 0, sizeof(xevent)); - xevent.type = ClientMessage; - xevent.xclient.window = xwindow_; - xevent.xclient.message_type = gfx::GetAtom("_NET_WM_DESKTOP"); - xevent.xclient.format = 32; - xevent.xclient.data.l[0] = new_desktop; - xevent.xclient.data.l[1] = 0; - xevent.xclient.data.l[2] = 0; - xevent.xclient.data.l[3] = 0; - xevent.xclient.data.l[4] = 0; - XSendEvent(xdisplay_, x_root_window_, x11::False, - SubstructureRedirectMask | SubstructureNotifyMask, &xevent); + SendClientMessage(xwindow_, x_root_window_, gfx::GetAtom("_NET_WM_DESKTOP"), + {new_desktop, 0, 0, 0, 0}); } bool XWindow::IsXWindowVisibleOnAllWorkspaces() const { @@ -845,13 +837,15 @@ bool XWindow::IsXWindowVisibleOnAllWorkspaces() const { } void XWindow::MoveCursorTo(const gfx::Point& location_in_pixels) { - XWarpPointer(xdisplay_, x11::None, x_root_window_, 0, 0, 0, 0, - bounds_in_pixels_.x() + location_in_pixels.x(), - bounds_in_pixels_.y() + location_in_pixels.y()); + connection_->WarpPointer({ + .dst_window = x_root_window_, + .dst_x = bounds_in_pixels_.x() + location_in_pixels.x(), + .dst_y = bounds_in_pixels_.y() + location_in_pixels.y(), + }); } void XWindow::ResetWindowRegion() { - XRegion* xregion = nullptr; + std::unique_ptr<std::vector<x11::Rectangle>> xregion; if (!use_custom_shape() && !IsMaximized() && !IsFullscreen()) { SkPath window_mask; GetWindowMaskForXWindow(bounds().size(), &window_mask); @@ -860,13 +854,13 @@ void XWindow::ResetWindowRegion() { if (window_mask.countPoints() > 0) xregion = gfx::CreateRegionFromSkPath(window_mask); } - UpdateWindowRegion(xregion); + UpdateWindowRegion(std::move(xregion)); } void XWindow::OnWorkspaceUpdated() { auto old_workspace = workspace_; int workspace; - if (ui::GetWindowDesktop(xwindow_, &workspace)) + if (GetWindowDesktop(xwindow_, &workspace)) workspace_ = workspace; else workspace_ = base::nullopt; @@ -877,25 +871,24 @@ void XWindow::OnWorkspaceUpdated() { void XWindow::SetAlwaysOnTop(bool always_on_top) { is_always_on_top_ = always_on_top; - SetWMSpecState(always_on_top, gfx::GetAtom("_NET_WM_STATE_ABOVE"), x11::None); + SetWMSpecState(always_on_top, gfx::GetAtom("_NET_WM_STATE_ABOVE"), + x11::Atom::None); } void XWindow::SetFlashFrameHint(bool flash_frame) { if (urgency_hint_set_ == flash_frame) return; - gfx::XScopedPtr<XWMHints> hints(XGetWMHints(xdisplay_, xwindow_)); - if (!hints) { - // The window hasn't had its hints set yet. - hints.reset(XAllocWMHints()); - } + WmHints hints; + memset(&hints, 0, sizeof(hints)); + GetWmHints(xwindow_, &hints); if (flash_frame) - hints->flags |= XUrgencyHint; + hints.flags |= WM_HINT_X_URGENCY; else - hints->flags &= ~XUrgencyHint; + hints.flags &= ~WM_HINT_X_URGENCY; - XSetWMHints(xdisplay_, xwindow_, hints.get()); + SetWmHints(xwindow_, hints); urgency_hint_set_ = flash_frame; } @@ -911,28 +904,27 @@ void XWindow::UpdateMinAndMaxSize() { min_size_in_pixels_ = minimum_in_pixels.value(); max_size_in_pixels_ = maximum_in_pixels.value(); - XSizeHints hints; - hints.flags = 0; - long supplied_return; - XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return); + SizeHints hints; + memset(&hints, 0, sizeof(hints)); + GetWmNormalHints(xwindow_, &hints); if (min_size_in_pixels_.IsEmpty()) { - hints.flags &= ~PMinSize; + hints.flags &= ~SIZE_HINT_P_MIN_SIZE; } else { - hints.flags |= PMinSize; + hints.flags |= SIZE_HINT_P_MIN_SIZE; hints.min_width = min_size_in_pixels_.width(); hints.min_height = min_size_in_pixels_.height(); } if (max_size_in_pixels_.IsEmpty()) { - hints.flags &= ~PMaxSize; + hints.flags &= ~SIZE_HINT_P_MAX_SIZE; } else { - hints.flags |= PMaxSize; + hints.flags |= SIZE_HINT_P_MAX_SIZE; hints.max_width = max_size_in_pixels_.width(); hints.max_height = max_size_in_pixels_.height(); } - XSetWMNormalHints(xdisplay_, xwindow_, &hints); + SetWmNormalHints(xwindow_, hints); } void XWindow::BeforeActivationStateChanged() { @@ -961,24 +953,24 @@ void XWindow::AfterActivationStateChanged() { void XWindow::SetUseNativeFrame(bool use_native_frame) { use_native_frame_ = use_native_frame; - ui::SetUseOSWindowFrame(xwindow_, use_native_frame); + SetUseOSWindowFrame(xwindow_, use_native_frame); ResetWindowRegion(); } void XWindow::OnCrossingEvent(bool enter, bool focus_in_window_or_ancestor, - int mode, - int detail) { + x11::NotifyMode mode, + x11::NotifyDetail detail) { // NotifyInferior on a crossing event means the pointer moved into or out of a // child window, but the pointer is still within |xwindow_|. - if (detail == NotifyInferior) + if (detail == x11::NotifyDetail::Inferior) return; BeforeActivationStateChanged(); - if (mode == NotifyGrab) + if (mode == x11::NotifyMode::Grab) has_pointer_grab_ = enter; - else if (mode == NotifyUngrab) + else if (mode == x11::NotifyMode::Ungrab) has_pointer_grab_ = false; has_pointer_ = enter; @@ -994,13 +986,16 @@ void XWindow::OnCrossingEvent(bool enter, AfterActivationStateChanged(); } -void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { +void XWindow::OnFocusEvent(bool focus_in, + x11::NotifyMode mode, + x11::NotifyDetail detail) { // NotifyInferior on a focus event means the focus moved into or out of a // child window, but the focus is still within |xwindow_|. - if (detail == NotifyInferior) + if (detail == x11::NotifyDetail::Inferior) return; - bool notify_grab = mode == NotifyGrab || mode == NotifyUngrab; + bool notify_grab = + mode == x11::NotifyMode::Grab || mode == x11::NotifyMode::Ungrab; BeforeActivationStateChanged(); @@ -1010,13 +1005,13 @@ void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { // For |has_pointer_focus_| and |has_window_focus_|, we continue tracking // state during a grab, but ignore grab/ungrab events themselves. - if (!notify_grab && detail != NotifyPointer) + if (!notify_grab && detail != x11::NotifyDetail::Pointer) has_window_focus_ = focus_in; if (!notify_grab && has_pointer_) { switch (detail) { - case NotifyAncestor: - case NotifyVirtual: + case x11::NotifyDetail::Ancestor: + case x11::NotifyDetail::Virtual: // If we reach this point, we know |has_pointer_| was true before and // after this event. Since the definition of |has_pointer_focus_| is // (An ancestor window or the PointerRoot is focused) && |has_pointer_|, @@ -1033,7 +1028,7 @@ void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { // (FocusIn with NotifyVirtual) has_pointer_focus_ = !focus_in; break; - case NotifyPointer: + case x11::NotifyDetail::Pointer: // The remaining cases for |has_pointer_focus_| becoming true are: // 3. Focus moves from |xwindow_| to the PointerRoot // 4. Focus moves from a descendant of |xwindow_| to the PointerRoot @@ -1052,8 +1047,8 @@ void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { // In each case, we will get a FocusOut with a detail of NotifyPointer. has_pointer_focus_ = focus_in; break; - case NotifyNonlinear: - case NotifyNonlinearVirtual: + case x11::NotifyDetail::Nonlinear: + case x11::NotifyDetail::NonlinearVirtual: // We get Nonlinear(Virtual) events when // 1. Focus moves from Other to |xwindow_| // (FocusIn with NotifyNonlinear) @@ -1076,11 +1071,12 @@ void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { AfterActivationStateChanged(); } -bool XWindow::IsTargetedBy(const XEvent& xev) const { - ::Window target_window = - (xev.type == GenericEvent) +bool XWindow::IsTargetedBy(const x11::Event& x11_event) const { + const XEvent& xev = x11_event.xlib_event(); + auto target_window = static_cast<x11::Window>( + xev.type == x11::GeGenericEvent::opcode ? static_cast<XIDeviceEvent*>(xev.xcookie.data)->event - : xev.xany.window; + : xev.xany.window); return target_window == xwindow_; } @@ -1089,16 +1085,16 @@ void XWindow::WmMoveResize(int hittest, const gfx::Point& location) const { if (direction == -1) return; - DoWMMoveResize(xdisplay_, x_root_window_, xwindow_, location, direction); + DoWMMoveResize(connection_, x_root_window_, xwindow_, location, direction); } -// In Ozone, there are no ui::*Event constructors receiving XEvent* as input, -// in this case ui::PlatformEvent is expected. Furthermore, +// In Ozone, there are no *Event constructors receiving XEvent* as input, +// in this case PlatformEvent is expected. Furthermore, // X11EventSourceLibevent is used in that case, which already translates -// Mouse/Key/Touch/Scroll events into ui::Events so they should not be handled +// Mouse/Key/Touch/Scroll events into Events so they should not be handled // by PlatformWindow, which is supposed to use XWindow in Ozone builds. So // handling these events is disabled for Ozone. -void XWindow::ProcessEvent(XEvent* xev) { +void XWindow::ProcessEvent(x11::Event* xev) { // We can lose track of the window's position when the window is reparented. // When the parent window is moved, we won't get an event, so the window's // position relative to the root window will get out-of-sync. We can re-sync @@ -1106,8 +1102,8 @@ void XWindow::ProcessEvent(XEvent* xev) { // ButtonRelease, MotionNotify) which include the pointer location both // relative to this window and relative to the root window, so we can // calculate this window's position from that information. - gfx::Point window_point = ui::EventLocationFromXEvent(*xev); - gfx::Point root_point = ui::EventSystemLocationFromXEvent(*xev); + gfx::Point window_point = EventLocationFromXEvent(*xev); + gfx::Point root_point = EventSystemLocationFromXEvent(*xev); if (!window_point.IsOrigin() && !root_point.IsOrigin()) { gfx::Point window_origin = gfx::Point() + (root_point - window_point); if (bounds_in_pixels_.origin() != window_origin) { @@ -1118,135 +1114,115 @@ void XWindow::ProcessEvent(XEvent* xev) { // May want to factor CheckXEventForConsistency(xev); into a common location // since it is called here. - switch (xev->type) { - case EnterNotify: - case LeaveNotify: { - OnCrossingEvent(xev->type == EnterNotify, xev->xcrossing.focus, - xev->xcrossing.mode, xev->xcrossing.detail); - break; - } - case Expose: { - gfx::Rect damage_rect_in_pixels(xev->xexpose.x, xev->xexpose.y, - xev->xexpose.width, xev->xexpose.height); - OnXWindowDamageEvent(damage_rect_in_pixels); - break; - } - case x11::FocusIn: - case x11::FocusOut: - OnFocusEvent(xev->type == x11::FocusIn, xev->xfocus.mode, - xev->xfocus.detail); - break; - case ConfigureNotify: - OnConfigureEvent(xev); - break; - case GenericEvent: { - ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); - if (!factory->ShouldProcessXI2Event(xev)) - break; - - XIEnterEvent* enter_event = static_cast<XIEnterEvent*>(xev->xcookie.data); - switch (static_cast<XIEvent*>(xev->xcookie.data)->evtype) { - case XI_Enter: - case XI_Leave: { - OnCrossingEvent(enter_event->evtype == XI_Enter, enter_event->focus, - XI2ModeToXMode(enter_event->mode), - enter_event->detail); - return; - } - case XI_FocusIn: - case XI_FocusOut: { - OnFocusEvent(enter_event->evtype == XI_FocusIn, - XI2ModeToXMode(enter_event->mode), enter_event->detail); - return; - } - default: + if (auto* crossing = xev->As<x11::CrossingEvent>()) { + bool focus = crossing->same_screen_focus & CROSSING_FLAG_FOCUS; + OnCrossingEvent(crossing->opcode == x11::CrossingEvent::EnterNotify, focus, + crossing->mode, crossing->detail); + } else if (auto* expose = xev->As<x11::ExposeEvent>()) { + gfx::Rect damage_rect_in_pixels(expose->x, expose->y, expose->width, + expose->height); + OnXWindowDamageEvent(damage_rect_in_pixels); + } else if (auto* focus = xev->As<x11::FocusEvent>()) { + OnFocusEvent(focus->opcode == x11::FocusEvent::In, focus->mode, + focus->detail); + } else if (auto* configure = xev->As<x11::ConfigureNotifyEvent>()) { + OnConfigureEvent(*configure); + } else if (auto* crossing = xev->As<x11::Input::CrossingEvent>()) { + TouchFactory* factory = TouchFactory::GetInstance(); + if (factory->ShouldProcessXI2Event(&xev->xlib_event())) { + auto mode = XI2ModeToXMode(crossing->mode); + auto detail = XI2DetailToXDetail(crossing->detail); + switch (crossing->opcode) { + case x11::Input::CrossingEvent::Enter: + OnCrossingEvent(true, crossing->focus, mode, detail); break; - } - break; - } - case MapNotify: { - OnWindowMapped(); - break; - } - case UnmapNotify: { - window_mapped_in_server_ = false; - has_pointer_ = false; - has_pointer_grab_ = false; - has_pointer_focus_ = false; - has_window_focus_ = false; - break; - } - case ClientMessage: { - Atom message_type = xev->xclient.message_type; - if (message_type == gfx::GetAtom("WM_PROTOCOLS")) { - Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]); - if (protocol == gfx::GetAtom("WM_DELETE_WINDOW")) { - // We have received a close message from the window manager. - OnXWindowCloseRequested(); - } else if (protocol == gfx::GetAtom("_NET_WM_PING")) { - XEvent reply_event = *xev; - reply_event.xclient.window = x_root_window_; - - XSendEvent(xdisplay_, reply_event.xclient.window, x11::False, - SubstructureRedirectMask | SubstructureNotifyMask, - &reply_event); - } else if (protocol == gfx::GetAtom("_NET_WM_SYNC_REQUEST")) { - pending_counter_value_ = - xev->xclient.data.l[2] + - (static_cast<int64_t>(xev->xclient.data.l[3]) << 32); - pending_counter_value_is_extended_ = xev->xclient.data.l[4] != 0; - } - } else { - OnXWindowDragDropEvent(xev); - } - break; - } - case MappingNotify: { - switch (xev->xmapping.request) { - case MappingModifier: - case MappingKeyboard: - XRefreshKeyboardMapping(&xev->xmapping); + case x11::Input::CrossingEvent::Leave: + OnCrossingEvent(false, crossing->focus, mode, detail); break; - case MappingPointer: - ui::DeviceDataManagerX11::GetInstance()->UpdateButtonMap(); + case x11::Input::CrossingEvent::FocusIn: + OnFocusEvent(true, mode, detail); break; - default: - NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request; + case x11::Input::CrossingEvent::FocusOut: + OnFocusEvent(false, mode, detail); break; } - break; } - case PropertyNotify: { - XAtom changed_atom = xev->xproperty.atom; - if (changed_atom == gfx::GetAtom("_NET_WM_STATE")) { - OnWMStateUpdated(); - } else if (changed_atom == gfx::GetAtom("_NET_FRAME_EXTENTS")) { - OnFrameExtentsUpdated(); - } else if (changed_atom == gfx::GetAtom("_NET_WM_DESKTOP")) { - OnWorkspaceUpdated(); + } else if (xev->As<x11::MapNotifyEvent>()) { + OnWindowMapped(); + } else if (xev->As<x11::UnmapNotifyEvent>()) { + window_mapped_in_server_ = false; + has_pointer_ = false; + has_pointer_grab_ = false; + has_pointer_focus_ = false; + has_window_focus_ = false; + } else if (auto* client = xev->As<x11::ClientMessageEvent>()) { + x11::Atom message_type = client->type; + if (message_type == gfx::GetAtom("WM_PROTOCOLS")) { + x11::Atom protocol = static_cast<x11::Atom>(client->data.data32[0]); + if (protocol == gfx::GetAtom("WM_DELETE_WINDOW")) { + // We have received a close message from the window manager. + OnXWindowCloseRequested(); + } else if (protocol == gfx::GetAtom("_NET_WM_PING")) { + x11::ClientMessageEvent reply_event = *client; + reply_event.window = x_root_window_; + + auto event_bytes = x11::Write(reply_event); + DCHECK_EQ(event_bytes.size(), 32ul); + + x11::SendEventRequest request{false, x_root_window_, + x11::EventMask::SubstructureNotify | + x11::EventMask::SubstructureRedirect}; + std::copy(event_bytes.begin(), event_bytes.end(), + request.event.begin()); + connection_->SendEvent(request); + } else if (protocol == gfx::GetAtom("_NET_WM_SYNC_REQUEST")) { + pending_counter_value_ = + client->data.data32[2] + + (static_cast<int64_t>(client->data.data32[3]) << 32); + pending_counter_value_is_extended_ = client->data.data32[4] != 0; } - break; + } else { + OnXWindowDragDropEvent(xev); } - case SelectionNotify: { - OnXWindowSelectionEvent(xev); - break; + } else if (auto* mapping = xev->As<x11::MappingNotifyEvent>()) { + switch (mapping->request) { + case x11::Mapping::Modifier: + case x11::Mapping::Keyboard: + XRefreshKeyboardMapping(&xev->xlib_event().xmapping); + break; + case x11::Mapping::Pointer: + DeviceDataManagerX11::GetInstance()->UpdateButtonMap(); + break; + default: + NOTIMPLEMENTED() << " Unknown request: " + << static_cast<int>(mapping->request); + break; + } + } else if (auto* property = xev->As<x11::PropertyNotifyEvent>()) { + x11::Atom changed_atom = property->atom; + if (changed_atom == gfx::GetAtom("_NET_WM_STATE")) { + OnWMStateUpdated(); + } else if (changed_atom == gfx::GetAtom("_NET_FRAME_EXTENTS")) { + OnFrameExtentsUpdated(); + } else if (changed_atom == gfx::GetAtom("_NET_WM_DESKTOP")) { + OnWorkspaceUpdated(); } + } else if (auto* selection = xev->As<x11::SelectionNotifyEvent>()) { + OnXWindowSelectionEvent(xev); } } -void XWindow::UpdateWMUserTime(ui::Event* event) { +void XWindow::UpdateWMUserTime(Event* event) { if (!IsActive()) return; DCHECK(event); - ui::EventType type = event->type(); - if (type == ui::ET_MOUSE_PRESSED || type == ui::ET_KEY_PRESSED || - type == ui::ET_TOUCH_PRESSED) { - unsigned long wm_user_time_ms = + EventType type = event->type(); + if (type == ET_MOUSE_PRESSED || type == ET_KEY_PRESSED || + type == ET_TOUCH_PRESSED) { + uint32_t wm_user_time_ms = (event->time_stamp() - base::TimeTicks()).InMilliseconds(); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"), - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast<const unsigned char*>(&wm_user_time_ms), - 1); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"), + x11::Atom::CARDINAL, wm_user_time_ms); } } @@ -1260,31 +1236,33 @@ void XWindow::OnWindowMapped() { } } -void XWindow::OnConfigureEvent(XEvent* xev) { - DCHECK_EQ(xwindow_, xev->xconfigure.window); - DCHECK_EQ(xwindow_, xev->xconfigure.event); +void XWindow::OnConfigureEvent(const x11::ConfigureNotifyEvent& configure) { + DCHECK_EQ(xwindow_, configure.window); + DCHECK_EQ(xwindow_, configure.event); if (pending_counter_value_) { DCHECK(!configure_counter_value_); configure_counter_value_ = pending_counter_value_; configure_counter_value_is_extended_ = pending_counter_value_is_extended_; - pending_counter_value_is_extended_ = 0; + pending_counter_value_is_extended_ = false; pending_counter_value_ = 0; } // It's possible that the X window may be resized by some other means than // from within aura (e.g. the X window manager can change the size). Make // sure the root window size is maintained properly. - int translated_x_in_pixels = xev->xconfigure.x; - int translated_y_in_pixels = xev->xconfigure.y; - if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) { - Window unused; - XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_, 0, 0, - &translated_x_in_pixels, &translated_y_in_pixels, - &unused); + int translated_x_in_pixels = configure.x; + int translated_y_in_pixels = configure.y; + if (!configure.send_event && !configure.override_redirect) { + auto future = + connection_->TranslateCoordinates({xwindow_, x_root_window_, 0, 0}); + if (auto coords = future.Sync()) { + translated_x_in_pixels = coords->dst_x; + translated_y_in_pixels = coords->dst_y; + } } gfx::Rect bounds_in_pixels(translated_x_in_pixels, translated_y_in_pixels, - xev->xconfigure.width, xev->xconfigure.height); + configure.width, configure.height); bool size_changed = bounds_in_pixels_.size() != bounds_in_pixels.size(); bool origin_changed = bounds_in_pixels_.origin() != bounds_in_pixels.origin(); previous_bounds_in_pixels_ = bounds_in_pixels_; @@ -1296,13 +1274,13 @@ void XWindow::OnConfigureEvent(XEvent* xev) { NotifyBoundsChanged(bounds_in_pixels_); } -void XWindow::SetWMSpecState(bool enabled, XAtom state1, XAtom state2) { +void XWindow::SetWMSpecState(bool enabled, x11::Atom state1, x11::Atom state2) { if (window_mapped_in_client_) { ui::SetWMSpecState(xwindow_, enabled, state1, state2); } else { // The updated state will be set when the window is (re)mapped. - base::flat_set<XAtom> new_window_properties = window_properties_; - for (XAtom atom : {state1, state2}) { + base::flat_set<x11::Atom> new_window_properties = window_properties_; + for (x11::Atom atom : {state1, state2}) { if (enabled) new_window_properties.insert(atom); else @@ -1318,16 +1296,16 @@ void XWindow::OnWMStateUpdated() { // persist across a Hide() and Show(). So if the window is currently // unmapped, leave the state unchanged so it will be restored when the window // is remapped. - std::vector<XAtom> atom_list; - if (ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list) || + std::vector<x11::Atom> atom_list; + if (GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list) || window_mapped_in_client_) { UpdateWindowProperties( - base::flat_set<XAtom>(std::begin(atom_list), std::end(atom_list))); + base::flat_set<x11::Atom>(std::begin(atom_list), std::end(atom_list))); } } void XWindow::UpdateWindowProperties( - const base::flat_set<XAtom>& new_window_properties) { + const base::flat_set<x11::Atom>& new_window_properties) { was_minimized_ = IsMinimized(); window_properties_ = new_window_properties; @@ -1337,15 +1315,15 @@ void XWindow::UpdateWindowProperties( // handle window manager initiated fullscreen. In particular, Chrome needs to // do preprocessing before the x window's fullscreen state is toggled. - is_always_on_top_ = ui::HasWMSpecProperty( - window_properties_, gfx::GetAtom("_NET_WM_STATE_ABOVE")); + is_always_on_top_ = HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_ABOVE")); OnXWindowStateChanged(); ResetWindowRegion(); } void XWindow::OnFrameExtentsUpdated() { std::vector<int> insets; - if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) && + if (GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) && insets.size() == 4) { // |insets| are returned in the order: [left, right, top, bottom]. native_window_frame_borders_in_pixels_ = @@ -1363,14 +1341,14 @@ void XWindow::NotifySwapAfterResize() { // Setting an even number to |extended_update_counter_| will trigger a // new resize. current_counter_value_ += 3; - SyncSetCounter(xdisplay_, extended_update_counter_, + SyncSetCounter(connection_, extended_update_counter_, current_counter_value_); } return; } if (configure_counter_value_ != 0) { - SyncSetCounter(xdisplay_, update_counter_, configure_counter_value_); + SyncSetCounter(connection_, update_counter_, configure_counter_value_); configure_counter_value_ = 0; } } @@ -1378,7 +1356,8 @@ void XWindow::NotifySwapAfterResize() { // Removes |delayed_resize_task_| from the task queue (if it's in // the queue) and adds it back at the end of the queue. void XWindow::DispatchResize() { - if (update_counter_ == x11::None || configure_counter_value_ == 0) { + if (update_counter_ == x11::Sync::Counter{} || + configure_counter_value_ == 0) { // WM doesn't support _NET_WM_SYNC_REQUEST. // Or we are too slow, so _NET_WM_SYNC_REQUEST is disabled by the // compositor. @@ -1410,7 +1389,7 @@ void XWindow::DelayedResize(const gfx::Rect& bounds_in_pixels) { // are not frozen and re-enable _NET_WM_SYNC_REQUEST, if it was disabled. // Increase the |extended_update_counter_| to an odd number will not trigger // a new resize. - SyncSetCounter(xdisplay_, extended_update_counter_, + SyncSetCounter(connection_, extended_update_counter_, ++current_counter_value_); } @@ -1434,41 +1413,51 @@ void XWindow::ConfineCursorTo(const gfx::Rect& bounds) { gfx::Rect barrier = bounds + bounds_in_pixels_.OffsetFromOrigin(); + auto make_barrier = [&](uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, + x11::XFixes::BarrierDirections directions) { + x11::XFixes::Barrier barrier = + connection_->GenerateId<x11::XFixes::Barrier>(); + connection_->xfixes().CreatePointerBarrier( + {barrier, x_root_window_, x1, y1, x2, y2, directions}); + return barrier; + }; + // Top horizontal barrier. - pointer_barriers_[0] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, barrier.x(), barrier.y(), barrier.right(), - barrier.y(), BarrierPositiveY, 0, XIAllDevices); + pointer_barriers_[0] = + make_barrier(barrier.x(), barrier.y(), barrier.right(), barrier.y(), + x11::XFixes::BarrierDirections::PositiveY); // Bottom horizontal barrier. - pointer_barriers_[1] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, barrier.x(), barrier.bottom(), barrier.right(), - barrier.bottom(), BarrierNegativeY, 0, XIAllDevices); + pointer_barriers_[1] = + make_barrier(barrier.x(), barrier.bottom(), barrier.right(), + barrier.bottom(), x11::XFixes::BarrierDirections::NegativeY); // Left vertical barrier. - pointer_barriers_[2] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, barrier.x(), barrier.y(), barrier.x(), - barrier.bottom(), BarrierPositiveX, 0, XIAllDevices); + pointer_barriers_[2] = + make_barrier(barrier.x(), barrier.y(), barrier.x(), barrier.bottom(), + x11::XFixes::BarrierDirections::PositiveX); // Right vertical barrier. - pointer_barriers_[3] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, barrier.right(), barrier.y(), barrier.right(), - barrier.bottom(), BarrierNegativeX, 0, XIAllDevices); + pointer_barriers_[3] = + make_barrier(barrier.right(), barrier.y(), barrier.right(), + barrier.bottom(), x11::XFixes::BarrierDirections::NegativeX); has_pointer_barriers_ = true; } void XWindow::LowerWindow() { - XLowerWindow(xdisplay_, xwindow_); + ui::LowerWindow(xwindow_); } void XWindow::SetOverrideRedirect(bool override_redirect) { bool remap = window_mapped_in_client_; if (remap) Hide(); - XSetWindowAttributes swa; - swa.override_redirect = override_redirect; - XChangeWindowAttributes(xdisplay_, xwindow_, CWOverrideRedirect, &swa); + connection_->ChangeWindowAttributes({ + .window = xwindow_, + .override_redirect = x11::Bool32(override_redirect), + }); if (remap) { Map(); if (has_pointer_grab_) - ui::ChangeActivePointerGrabCursor(x11::None); + ChangeActivePointerGrabCursor(x11::None); } } @@ -1476,12 +1465,16 @@ bool XWindow::ContainsPointInRegion(const gfx::Point& point) const { if (!shape()) return true; - return XPointInRegion(shape(), point.x(), point.y()) == x11::True; + for (const auto& rect : *shape()) { + if (gfx::Rect(rect.x, rect.y, rect.width, rect.height).Contains(point)) + return true; + } + return false; } void XWindow::SetXWindowShape(std::unique_ptr<NativeShapeRects> native_shape, const gfx::Transform& transform) { - XRegion* xregion = nullptr; + std::unique_ptr<std::vector<x11::Rectangle>> xregion; if (native_shape) { SkRegion native_region; for (const gfx::Rect& rect : *native_shape) @@ -1493,7 +1486,7 @@ void XWindow::SetXWindowShape(std::unique_ptr<NativeShapeRects> native_shape, path_in_dip.transform(SkMatrix(transform.matrix()), &path_in_pixels); xregion = gfx::CreateRegionFromSkPath(path_in_pixels); } else { - xregion = XCreateRegion(); + xregion = std::make_unique<std::vector<x11::Rectangle>>(); } } else { xregion = gfx::CreateRegionFromSkRegion(native_region); @@ -1501,7 +1494,7 @@ void XWindow::SetXWindowShape(std::unique_ptr<NativeShapeRects> native_shape, } custom_window_shape_ = !!xregion; - window_shape_.reset(xregion); + window_shape_ = std::move(xregion); ResetWindowRegion(); } @@ -1509,25 +1502,35 @@ void XWindow::UnconfineCursor() { if (!has_pointer_barriers_) return; - for (XID pointer_barrier : pointer_barriers_) - XFixesDestroyPointerBarrier(xdisplay_, pointer_barrier); - pointer_barriers_.fill(x11::None); + for (auto pointer_barrier : pointer_barriers_) + connection_->xfixes().DeletePointerBarrier({pointer_barrier}); + + pointer_barriers_.fill({}); has_pointer_barriers_ = false; } -void XWindow::UpdateWindowRegion(XRegion* xregion) { +void XWindow::UpdateWindowRegion( + std::unique_ptr<std::vector<x11::Rectangle>> region) { + auto set_shape = [&](const std::vector<x11::Rectangle>& rectangles) { + connection_->shape().Rectangles({ + .operation = x11::Shape::So::Set, + .destination_kind = x11::Shape::Sk::Bounding, + .ordering = x11::ClipOrdering::YXBanded, + .destination_window = xwindow_, + .rectangles = rectangles, + }); + }; + // If a custom window shape was supplied then apply it. if (use_custom_shape()) { - XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 0, 0, - window_shape_.get(), false); + set_shape(*window_shape_); return; } - window_shape_.reset(xregion); + window_shape_ = std::move(region); if (window_shape_) { - XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 0, 0, - window_shape_.get(), false); + set_shape(*window_shape_); return; } @@ -1538,19 +1541,21 @@ void XWindow::UpdateWindowRegion(XRegion* xregion) { // If the window has system borders, the mask must be set to null (not a // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will // not put borders on a window with a custom shape. - XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, x11::None, - ShapeSet); + connection_->shape().Mask({ + .operation = x11::Shape::So::Set, + .destination_kind = x11::Shape::Sk::Bounding, + .destination_window = xwindow_, + .source_bitmap = x11::Pixmap::None, + }); } else { // Conversely, if the window does not have system borders, the mask must be // manually set to a rectangle that covers the whole window (not null). This // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null // shape causes the hint to disable system borders to be ignored (resulting // in a double border). - XRectangle r = {0, 0, - static_cast<unsigned short>(bounds_in_pixels_.width()), - static_cast<unsigned short>(bounds_in_pixels_.height())}; - XShapeCombineRectangles(xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, - ShapeSet, YXBanded); + x11::Rectangle r{0, 0, bounds_in_pixels_.width(), + bounds_in_pixels_.height()}; + set_shape({r}); } } @@ -1560,42 +1565,32 @@ void XWindow::NotifyBoundsChanged(const gfx::Rect& new_bounds_in_px) { } bool XWindow::InitializeAsStatusIcon() { - std::string atom_name = - "_NET_SYSTEM_TRAY_S" + base::NumberToString(DefaultScreen(xdisplay_)); - XID manager = XGetSelectionOwner(xdisplay_, gfx::GetAtom(atom_name.c_str())); - if (manager == x11::None) + std::string atom_name = "_NET_SYSTEM_TRAY_S" + + base::NumberToString(connection_->DefaultScreenId()); + auto reply = connection_->GetSelectionOwner({gfx::GetAtom(atom_name)}).Sync(); + if (!reply || reply->owner == x11::Window::None) return false; + auto manager = reply->owner; - ui::SetIntArrayProperty(xwindow_, "_XEMBED_INFO", "CARDINAL", - {kXembedInfoProtocolVersion, kXembedInfoFlags}); + SetIntArrayProperty(xwindow_, "_XEMBED_INFO", "CARDINAL", + {kXembedInfoProtocolVersion, kXembedInfoFlags}); - XSetWindowAttributes attrs; - unsigned long flags = 0; + x11::ChangeWindowAttributesRequest req{xwindow_}; if (has_alpha()) { - flags |= CWBackPixel; - attrs.background_pixel = 0; + req.background_pixel = 0; } else { - ui::SetIntProperty(xwindow_, "CHROMIUM_COMPOSITE_WINDOW", "CARDINAL", 1); - flags |= CWBackPixmap; - attrs.background_pixmap = 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 = 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(); + SetIntProperty(xwindow_, "CHROMIUM_COMPOSITE_WINDOW", "CARDINAL", 1); + req.background_pixmap = + static_cast<x11::Pixmap>(x11::BackPixmap::ParentRelative); } - return !error; + connection_->ChangeWindowAttributes(req); + + auto future = SendClientMessage( + manager, manager, gfx::GetAtom("_NET_SYSTEM_TRAY_OPCODE"), + {X11EventSource::GetInstance()->GetTimestamp(), kSystemTrayRequestDock, + static_cast<uint32_t>(xwindow_), 0, 0}, + x11::EventMask::NoEvent); + return !future.Sync().error; } } // namespace ui diff --git a/chromium/ui/base/x/x11_window.h b/chromium/ui/base/x/x11_window.h index feec9b62e6d..c5b0d7227a5 100644 --- a/chromium/ui/base/x/x11_window.h +++ b/chromium/ui/base/x/x11_window.h @@ -8,6 +8,7 @@ #include <array> #include <memory> #include <string> +#include <vector> #include "base/cancelable_callback.h" #include "base/component_export.h" @@ -19,8 +20,12 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_f.h" +#include "ui/gfx/x/event.h" +#include "ui/gfx/x/sync.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11_types.h" +#include "ui/gfx/x/xfixes.h" +#include "ui/gfx/x/xproto.h" class SkPath; @@ -107,11 +112,11 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { bool IsActive() const; void GrabPointer(); void ReleasePointerGrab(); - void StackXWindowAbove(::Window window); + void StackXWindowAbove(x11::Window window); void StackXWindowAtTop(); - bool IsTargetedBy(const XEvent& xev) const; + bool IsTargetedBy(const x11::Event& xev) const; void WmMoveResize(int hittest, const gfx::Point& location) const; - void ProcessEvent(XEvent* xev); + void ProcessEvent(x11::Event* xev); void SetSize(const gfx::Size& size_in_pixels); void SetBounds(const gfx::Rect& requested_bounds); @@ -119,7 +124,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { bool IsMinimized() const; bool IsMaximized() const; bool IsFullscreen() const; - gfx::Rect GetOutterBounds() const; + gfx::Rect GetOuterBounds() const; void SetCursor(::Cursor cursor); bool SetTitle(base::string16 title); @@ -163,12 +168,14 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { bool has_alpha() const { return visual_has_alpha_; } base::Optional<int> workspace() const { return workspace_; } - XDisplay* display() const { return xdisplay_; } - ::Window window() const { return xwindow_; } - ::Window root_window() const { return x_root_window_; } - ::Region shape() const { return window_shape_.get(); } - XID update_counter() const { return update_counter_; } - XID extended_update_counter() const { return extended_update_counter_; } + x11::Connection* connection() const { return connection_; } + x11::Window window() const { return xwindow_; } + x11::Window root_window() const { return x_root_window_; } + std::vector<x11::Rectangle>* shape() const { return window_shape_.get(); } + x11::Sync::Counter update_counter() const { return update_counter_; } + x11::Sync::Counter extended_update_counter() const { + return extended_update_counter_; + } ::Cursor last_cursor() const { return last_cursor_; } protected: @@ -178,14 +185,16 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { private: // Called on an XFocusInEvent, XFocusOutEvent, XIFocusInEvent, or an // XIFocusOutEvent. - void OnFocusEvent(bool focus_in, int mode, int detail); + void OnFocusEvent(bool focus_in, + x11::NotifyMode mode, + x11::NotifyDetail detail); // Called on an XEnterWindowEvent, XLeaveWindowEvent, XIEnterEvent, or an // XILeaveEvent. void OnCrossingEvent(bool enter, bool focus_in_window_or_ancestor, - int mode, - int detail); + x11::NotifyMode mode, + x11::NotifyDetail detail); // Called when |xwindow_|'s _NET_WM_STATE property is updated. void OnWMStateUpdated(); @@ -193,7 +202,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { // Called when |xwindow_|'s _NET_FRAME_EXTENTS property is updated. void OnFrameExtentsUpdated(); - void OnConfigureEvent(XEvent* xev); + void OnConfigureEvent(const x11::ConfigureNotifyEvent& event); void OnWorkspaceUpdated(); @@ -215,15 +224,15 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { // be invalid to unset the maximized state by making two calls like // (_NET_WM_STATE_MAXIMIZED_VERT, x11::None), (_NET_WM_STATE_MAXIMIZED_HORZ, // x11::None). - void SetWMSpecState(bool enabled, XAtom state1, XAtom state2); + void SetWMSpecState(bool enabled, x11::Atom state1, x11::Atom state2); // Updates |window_properties_| with |new_window_properties|. void UpdateWindowProperties( - const base::flat_set<XAtom>& new_window_properties); + const base::flat_set<x11::Atom>& new_window_properties); void UnconfineCursor(); - void UpdateWindowRegion(XRegion* xregion); + void UpdateWindowRegion(std::unique_ptr<std::vector<x11::Rectangle>> region); void NotifyBoundsChanged(const gfx::Rect& new_bounds_in_px); @@ -241,23 +250,23 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { virtual void OnXWindowWorkspaceChanged() = 0; virtual void OnXWindowLostPointerGrab() = 0; virtual void OnXWindowLostCapture() = 0; - virtual void OnXWindowSelectionEvent(XEvent* xev) = 0; - virtual void OnXWindowDragDropEvent(XEvent* xev) = 0; + virtual void OnXWindowSelectionEvent(x11::Event* xev) = 0; + virtual void OnXWindowDragDropEvent(x11::Event* xev) = 0; virtual base::Optional<gfx::Size> GetMinimumSizeForXWindow() = 0; virtual base::Optional<gfx::Size> GetMaximumSizeForXWindow() = 0; virtual void GetWindowMaskForXWindow(const gfx::Size& size, SkPath* window_mask) = 0; // The display and the native X window hosting the root window. - XDisplay* xdisplay_ = nullptr; - ::Window xwindow_ = x11::None; - ::Window x_root_window_ = x11::None; + x11::Connection* const connection_; + x11::Window xwindow_ = x11::Window::None; + x11::Window x_root_window_ = x11::Window::None; // Events selected on |xwindow_|. std::unique_ptr<ui::XScopedEventSelector> xwindow_events_; // The window manager state bits. - base::flat_set<XAtom> window_properties_; + base::flat_set<x11::Atom> window_properties_; // Is this window able to receive focus? bool activatable_ = true; @@ -276,7 +285,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { // The bounds of |xwindow_|. gfx::Rect bounds_in_pixels_; - VisualID visual_id_ = 0; + x11::VisualId visual_id_{}; // Whether we used an ARGB visual for our window. bool visual_has_alpha_ = false; @@ -325,8 +334,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { // Used for synchronizing between |xwindow_| and desktop compositor during // resizing. - XID update_counter_ = x11::None; - XID extended_update_counter_ = x11::None; + x11::Sync::Counter update_counter_{}; + x11::Sync::Counter extended_update_counter_{}; // Whenever the bounds are set, we keep the previous set of bounds around so // we can have a better chance of getting the real @@ -353,8 +362,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { gfx::Size max_size_in_pixels_; // The window shape if the window is non-rectangular. - gfx::XScopedPtr<XRegion, gfx::XObjectDeleter<XRegion, int, XDestroyRegion>> - window_shape_; + std::unique_ptr<std::vector<x11::Rectangle>> window_shape_; // Whether |window_shape_| was set via SetShape(). bool custom_window_shape_ = false; @@ -377,7 +385,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XWindow { // Keep track of barriers to confine cursor. bool has_pointer_barriers_ = false; - std::array<XID, 4> pointer_barriers_; + std::array<x11::XFixes::Barrier, 4> pointer_barriers_; ::Cursor last_cursor_ = x11::None; }; diff --git a/chromium/ui/base/x/x11_workspace_handler.cc b/chromium/ui/base/x/x11_workspace_handler.cc index 72ea0fb82d5..cb48d38fc4a 100644 --- a/chromium/ui/base/x/x11_workspace_handler.cc +++ b/chromium/ui/base/x/x11_workspace_handler.cc @@ -15,11 +15,10 @@ namespace ui { namespace { -x11::Future<x11::XProto::GetPropertyReply> GetWorkspace() { +x11::Future<x11::GetPropertyReply> GetWorkspace() { auto* connection = x11::Connection::Get(); return connection->GetProperty({ - .window = - static_cast<x11::Window>(XDefaultRootWindow(connection->display())), + .window = connection->default_screen().root, .property = static_cast<x11::Atom>(gfx::GetAtom("_NET_CURRENT_DESKTOP")), .type = static_cast<x11::Atom>(gfx::GetAtom("CARDINAL")), .long_length = 1, @@ -30,7 +29,7 @@ x11::Future<x11::XProto::GetPropertyReply> GetWorkspace() { X11WorkspaceHandler::X11WorkspaceHandler(Delegate* delegate) : xdisplay_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(xdisplay_)), + x_root_window_(ui::GetX11RootWindow()), delegate_(delegate) { DCHECK(delegate_); if (ui::X11EventSource::HasInstance()) @@ -51,14 +50,16 @@ std::string X11WorkspaceHandler::GetCurrentWorkspace() { return workspace_; } -bool X11WorkspaceHandler::DispatchXEvent(XEvent* event) { +bool X11WorkspaceHandler::DispatchXEvent(x11::Event* x11_event) { + XEvent* event = &x11_event->xlib_event(); if (event->type != PropertyNotify || - event->xproperty.window != x_root_window_) { + event->xproperty.window != static_cast<uint32_t>(x_root_window_)) { return false; } switch (event->type) { - case PropertyNotify: { - if (event->xproperty.atom == gfx::GetAtom("_NET_CURRENT_DESKTOP")) { + case x11::PropertyNotifyEvent::opcode: { + if (event->xproperty.atom == + static_cast<uint32_t>(gfx::GetAtom("_NET_CURRENT_DESKTOP"))) { GetWorkspace().OnResponse( base::BindOnce(&X11WorkspaceHandler::OnWorkspaceResponse, weak_factory_.GetWeakPtr())); @@ -72,7 +73,7 @@ bool X11WorkspaceHandler::DispatchXEvent(XEvent* event) { } void X11WorkspaceHandler::OnWorkspaceResponse( - x11::XProto::GetPropertyResponse response) { + x11::GetPropertyResponse response) { if (!response || response->format != 32 || response->value.size() < 4) return; DCHECK_EQ(response->bytes_after, 0U); diff --git a/chromium/ui/base/x/x11_workspace_handler.h b/chromium/ui/base/x/x11_workspace_handler.h index b60f91a9f56..2a9c1ab4ea6 100644 --- a/chromium/ui/base/x/x11_workspace_handler.h +++ b/chromium/ui/base/x/x11_workspace_handler.h @@ -10,6 +10,7 @@ #include "base/component_export.h" #include "base/memory/weak_ptr.h" #include "ui/events/platform/x11/x11_event_source.h" +#include "ui/gfx/x/event.h" #include "ui/gfx/x/x11.h" #include "ui/gfx/x/xproto.h" @@ -40,15 +41,15 @@ class COMPONENT_EXPORT(UI_BASE_X) X11WorkspaceHandler private: // ui::XEventDispatcher - bool DispatchXEvent(XEvent* event) override; + bool DispatchXEvent(x11::Event* event) override; - void OnWorkspaceResponse(x11::XProto::GetPropertyResponse response); + void OnWorkspaceResponse(x11::GetPropertyResponse response); // The display and the native X window hosting the root window. XDisplay* xdisplay_; // The native root window. - ::Window x_root_window_; + x11::Window x_root_window_; // Events selected on x_root_window_. std::unique_ptr<ui::XScopedEventSelector> x_root_window_events_; diff --git a/chromium/ui/base/x/xwmstartupcheck/BUILD.gn b/chromium/ui/base/x/xwmstartupcheck/BUILD.gn new file mode 100644 index 00000000000..debd8fac289 --- /dev/null +++ b/chromium/ui/base/x/xwmstartupcheck/BUILD.gn @@ -0,0 +1,13 @@ +# 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. + +executable("xwmstartupcheck") { + testonly = true + + sources = [ "xwmstartupcheck.cc" ] + + deps = [ "//base" ] + + configs += [ "//build/config/linux:x11" ] +} diff --git a/chromium/ui/base/x/xwmstartupcheck/xwmstartupcheck.cc b/chromium/ui/base/x/xwmstartupcheck/xwmstartupcheck.cc new file mode 100644 index 00000000000..09ef42f3e12 --- /dev/null +++ b/chromium/ui/base/x/xwmstartupcheck/xwmstartupcheck.cc @@ -0,0 +1,125 @@ +// 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. +// +// Checks for the reparent notify events that is a signal that a WM has been +// started. Returns 0 on success and 1 on failure. This program must be started +// BEFORE the Wm starts. +// + +#include <cerrno> +#include <cstdio> + +#include <time.h> + +#include <X11/Xlib.h> + +void CalculateTimeout(const timespec& now, + const timespec& deadline, + timeval* timeout) { + // 1s == 1e+6 us. + // 1nsec == 1e-3 us + timeout->tv_usec = (deadline.tv_sec - now.tv_sec) * 1000000 + + (deadline.tv_nsec - now.tv_nsec) / 1000; + timeout->tv_sec = 0; +} + +class XScopedDisplay { + public: + explicit XScopedDisplay(Display* display) : display_(display) {} + ~XScopedDisplay() { + if (display_) + XCloseDisplay(display_); + } + + Display* display() const { return display_; } + + private: + Display* const display_; +}; + +int main(int argc, char* argv[]) { + // Connects to a display specified in the current process' env value DISPLAY. + XScopedDisplay scoped_display(XOpenDisplay(nullptr)); + + // No display found - fail early. + if (!scoped_display.display()) { + fprintf(stderr, "Couldn't connect to a display.\n"); + return 1; + } + + auto* xdisplay = scoped_display.display(); + + auto root_window = DefaultRootWindow(xdisplay); + if (!root_window) { + fprintf(stderr, "Couldn't find root window.\n"); + return 1; + } + + auto dummmy_window = XCreateSimpleWindow( + xdisplay, root_window, 0 /*x*/, 0 /*y*/, 1 /*width*/, 1 /*height*/, + 0 /*border width*/, 0 /*border*/, 0 /*background*/); + if (!dummmy_window) { + fprintf(stderr, "Couldn't create a dummy window."); + return 1; + } + + XMapWindow(xdisplay, dummmy_window); + // We are only interested in the ReparentNotify events that are sent whenever + // our dummy window is reparented because of a wm start. + XSelectInput(xdisplay, dummmy_window, StructureNotifyMask); + XFlush(xdisplay); + + int display_fd = ConnectionNumber(xdisplay); + + // Set deadline as 30s. + struct timespec now, deadline; + clock_gettime(CLOCK_REALTIME, &now); + deadline = now; + deadline.tv_sec += 30; + + // Calculate first timeout. + struct timeval tv; + CalculateTimeout(now, deadline, &tv); + + XEvent ev; + do { + fd_set in_fds; + FD_ZERO(&in_fds); + FD_SET(display_fd, &in_fds); + + int ret = select(display_fd + 1, &in_fds, nullptr, nullptr, &tv); + if (ret == -1) { + if (errno != EINTR) { + perror("Error occured while polling the display fd"); + break; + } + } else if (ret > 0) { + while (XPending(xdisplay)) { + XNextEvent(xdisplay, &ev); + // If we got ReparentNotify, a wm has started up and we can stop + // execution. + if (ev.type == ReparentNotify) { + return 0; + } + } + } + // Calculate next timeout. If it's less or equal to 0, give up. + clock_gettime(CLOCK_REALTIME, &now); + CalculateTimeout(now, deadline, &tv); + } while (tv.tv_usec >= 0); + + return 1; +} + +#if defined(LEAK_SANITIZER) +// XOpenDisplay leaks memory if it takes more than one try to connect. This +// causes LSan bots to fail. We don't care about memory leaks in xdisplaycheck +// anyway, so just disable LSan completely. +// This function isn't referenced from the executable itself. Make sure it isn't +// stripped by the linker. +__attribute__((used)) __attribute__((visibility("default"))) extern "C" int +__lsan_is_turned_off() { + return 1; +} +#endif |