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/x11_util.cc | |
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/x11_util.cc')
-rw-r--r-- | chromium/ui/base/x/x11_util.cc | 1011 |
1 files changed, 526 insertions, 485 deletions
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 |