summaryrefslogtreecommitdiff
path: root/chromium/ui/base/x/x11_util.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/ui/base/x/x11_util.cc
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-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.cc1011
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