diff options
Diffstat (limited to 'chromium/ui/base/x/x11_window.cc')
-rw-r--r-- | chromium/ui/base/x/x11_window.cc | 1043 |
1 files changed, 519 insertions, 524 deletions
diff --git a/chromium/ui/base/x/x11_window.cc b/chromium/ui/base/x/x11_window.cc index 70f520bccd4..bc5f4fefa7a 100644 --- a/chromium/ui/base/x/x11_window.cc +++ b/chromium/ui/base/x/x11_window.cc @@ -13,6 +13,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "net/base/network_interfaces.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/base/hit_test_x11.h" #include "ui/base/wm_role_names_linux.h" @@ -31,9 +32,13 @@ #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/skia_util.h" +#include "ui/gfx/x/connection.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_error_tracker.h" #include "ui/gfx/x/x11_path.h" +#include "ui/gfx/x/xfixes.h" +#include "ui/gfx/x/xinput.h" +#include "ui/gfx/x/xproto.h" #include "ui/platform_window/common/platform_window_defaults.h" namespace ui { @@ -46,7 +51,7 @@ const int kAllWorkspaces = 0xFFFFFFFF; constexpr char kX11WindowRolePopup[] = "popup"; constexpr char kX11WindowRoleBubble[] = "bubble"; -constexpr unsigned char kDarkGtkThemeVariant[] = "dark"; +constexpr char kDarkGtkThemeVariant[] = "dark"; constexpr long kSystemTrayRequestDock = 0; @@ -54,6 +59,11 @@ constexpr int kXembedInfoProtocolVersion = 0; constexpr int kXembedFlagMap = 1 << 0; constexpr int kXembedInfoFlags = kXembedFlagMap; +enum CrossingFlags : uint8_t { + CROSSING_FLAG_FOCUS = 1 << 0, + CROSSING_FLAG_SAME_SCREEN = 1 << 1, +}; + // In some situations, views tries to make a zero sized window, and that // makes us crash. Make sure we have valid sizes. gfx::Rect SanitizeBounds(const gfx::Rect& bounds) { @@ -64,59 +74,76 @@ gfx::Rect SanitizeBounds(const gfx::Rect& bounds) { } void SerializeImageRepresentation(const gfx::ImageSkiaRep& rep, - std::vector<unsigned long>* data) { - int width = rep.GetWidth(); + std::vector<uint32_t>* data) { + uint32_t width = rep.GetWidth(); data->push_back(width); - int height = rep.GetHeight(); + uint32_t height = rep.GetHeight(); data->push_back(height); const SkBitmap& bitmap = rep.GetBitmap(); - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) + for (uint32_t y = 0; y < height; ++y) + for (uint32_t x = 0; x < width; ++x) data->push_back(bitmap.getColor(x, y)); } -int XI2ModeToXMode(int xi2_mode) { +x11::NotifyMode XI2ModeToXMode(x11::Input::NotifyMode xi2_mode) { switch (xi2_mode) { - case XINotifyNormal: - return NotifyNormal; - case XINotifyGrab: - case XINotifyPassiveGrab: - return NotifyGrab; - case XINotifyUngrab: - case XINotifyPassiveUngrab: - return NotifyUngrab; - case XINotifyWhileGrabbed: - return NotifyWhileGrabbed; + case x11::Input::NotifyMode::Normal: + return x11::NotifyMode::Normal; + case x11::Input::NotifyMode::Grab: + case x11::Input::NotifyMode::PassiveGrab: + return x11::NotifyMode::Grab; + case x11::Input::NotifyMode::Ungrab: + case x11::Input::NotifyMode::PassiveUngrab: + return x11::NotifyMode::Ungrab; + case x11::Input::NotifyMode::WhileGrabbed: + return x11::NotifyMode::WhileGrabbed; default: NOTREACHED(); - return NotifyNormal; + return x11::NotifyMode::Normal; } } -bool SyncSetCounter(XDisplay* display, XID counter, int64_t value) { - XSyncValue sync_value; - XSyncIntsToValue(&sync_value, value & 0xFFFFFFFF, value >> 32); - return XSyncSetCounter(display, counter, sync_value) == x11::True; +x11::NotifyDetail XI2DetailToXDetail(x11::Input::NotifyDetail xi2_detail) { + switch (xi2_detail) { + case x11::Input::NotifyDetail::Ancestor: + return x11::NotifyDetail::Ancestor; + case x11::Input::NotifyDetail::Virtual: + return x11::NotifyDetail::Virtual; + case x11::Input::NotifyDetail::Inferior: + return x11::NotifyDetail::Inferior; + case x11::Input::NotifyDetail::Nonlinear: + return x11::NotifyDetail::Nonlinear; + case x11::Input::NotifyDetail::NonlinearVirtual: + return x11::NotifyDetail::NonlinearVirtual; + case x11::Input::NotifyDetail::Pointer: + return x11::NotifyDetail::Pointer; + case x11::Input::NotifyDetail::PointerRoot: + return x11::NotifyDetail::PointerRoot; + case x11::Input::NotifyDetail::None: + return x11::NotifyDetail::None; + } } -// Returns the whole path from |window| to the root. -std::vector<::Window> GetParentsList(XDisplay* xdisplay, ::Window window) { - ::Window parent_win, root_win; - Window* child_windows; - unsigned int num_child_windows; - std::vector<::Window> result; +void SyncSetCounter(x11::Connection* connection, + x11::Sync::Counter counter, + int64_t value) { + x11::Sync::Int64 sync_value{.hi = value >> 32, .lo = value & 0xFFFFFFFF}; + connection->sync().SetCounter({counter, sync_value}); +} - while (window) { +// Returns the whole path from |window| to the root. +std::vector<x11::Window> GetParentsList(x11::Connection* connection, + x11::Window window) { + std::vector<x11::Window> result; + while (window != x11::Window::None) { result.push_back(window); - if (!XQueryTree(xdisplay, window, &root_win, &parent_win, &child_windows, - &num_child_windows)) + if (auto reply = connection->QueryTree({window}).Sync()) + window = reply->parent; + else break; - if (child_windows) - XFree(child_windows); - window = parent_win; } return result; } @@ -139,15 +166,15 @@ XWindow::Configuration::Configuration(const Configuration&) = default; XWindow::Configuration::~Configuration() = default; XWindow::XWindow() - : xdisplay_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(xdisplay_)) { - DCHECK(xdisplay_); - DCHECK_NE(x_root_window_, x11::None); + : connection_(x11::Connection::Get()), x_root_window_(GetX11RootWindow()) { + DCHECK(connection_); + DCHECK_NE(x_root_window_, x11::Window::None); } XWindow::~XWindow() { - DCHECK_EQ(xwindow_, x11::None) << "XWindow destructed without calling " - "Close() to release allocated resources."; + DCHECK_EQ(xwindow_, x11::Window::None) + << "XWindow destructed without calling " + "Close() to release allocated resources."; } void XWindow::Init(const Configuration& config) { @@ -157,31 +184,28 @@ void XWindow::Init(const Configuration& config) { activatable_ = config.activatable; - unsigned long attribute_mask = CWBackPixel | CWBitGravity; - XSetWindowAttributes swa; - memset(&swa, 0, sizeof(swa)); - swa.background_pixmap = x11::None; - swa.bit_gravity = NorthWestGravity; - swa.background_pixel = config.background_color.has_value() + x11::CreateWindowRequest req; + req.bit_gravity = x11::Gravity::NorthWest; + req.background_pixel = config.background_color.has_value() ? config.background_color.value() - : WhitePixel(xdisplay_, DefaultScreen(xdisplay_)); + : connection_->default_screen().white_pixel; - XAtom window_type; + x11::Atom window_type; switch (config.type) { case WindowType::kMenu: - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_MENU"); break; case WindowType::kTooltip: - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP"); break; case WindowType::kPopup: - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION"); break; case WindowType::kDrag: - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); window_type = gfx::GetAtom("_NET_WM_WINDOW_TYPE_DND"); break; default: @@ -190,7 +214,7 @@ void XWindow::Init(const Configuration& config) { } // An in-activatable window should not interact with the system wm. if (!activatable_ || config.override_redirect) - swa.override_redirect = x11::True; + req.override_redirect = x11::Bool32(true); #if !defined(USE_X11) // It seems like there is a difference how tests are instantiated in case of @@ -204,12 +228,10 @@ void XWindow::Init(const Configuration& config) { // here. Otherwise, tests for non-Ozone X11 fail. // TODO(msisov): figure out usage of this for non-Ozone X11. if (UseTestConfigForPlatformWindows()) - swa.override_redirect = true; + req.override_redirect = x11::Bool32(true); #endif - override_redirect_ = swa.override_redirect == x11::True; - if (override_redirect_) - attribute_mask |= CWOverrideRedirect; + override_redirect_ = req.override_redirect.has_value(); bool enable_transparent_visuals; switch (config.opacity) { @@ -223,44 +245,42 @@ void XWindow::Init(const Configuration& config) { enable_transparent_visuals = config.type == WindowType::kDrag; } - int visual_id; if (config.wm_role_name == kStatusIconWmRoleName) { std::string atom_name = - "_NET_SYSTEM_TRAY_S" + base::NumberToString(DefaultScreen(xdisplay_)); - XID manager = - XGetSelectionOwner(xdisplay_, gfx::GetAtom(atom_name.c_str())); - if (ui::GetIntProperty(manager, "_NET_SYSTEM_TRAY_VISUAL", &visual_id)) - visual_id_ = visual_id; - } - - Visual* visual = CopyFromParent; - int depth = CopyFromParent; - Colormap colormap = CopyFromParent; - ui::XVisualManager* visual_manager = ui::XVisualManager::GetInstance(); - if (!visual_id_ || - !visual_manager->GetVisualInfo(visual_id_, &visual, &depth, &colormap, - &visual_has_alpha_)) { - visual_manager->ChooseVisualForWindow(enable_transparent_visuals, &visual, - &depth, &colormap, - &visual_has_alpha_); + "_NET_SYSTEM_TRAY_S" + + base::NumberToString(connection_->DefaultScreenId()); + auto selection = connection_->GetSelectionOwner({gfx::GetAtom(atom_name)}); + if (auto reply = selection.Sync()) { + GetProperty(reply->owner, gfx::GetAtom("_NET_SYSTEM_TRAY_VISUAL"), + &visual_id_); + } } - if (colormap != CopyFromParent) { - attribute_mask |= CWColormap; - swa.colormap = colormap; + x11::VisualId visual_id = visual_id_; + uint8_t depth = 0; + XVisualManager* visual_manager = XVisualManager::GetInstance(); + if (visual_id_ == x11::VisualId{} || + !visual_manager->GetVisualInfo(visual_id_, &depth, &visual_has_alpha_)) { + visual_manager->ChooseVisualForWindow( + enable_transparent_visuals, &visual_id, &depth, &visual_has_alpha_); } // x.org will BadMatch if we don't set a border when the depth isn't the // same as the parent depth. - attribute_mask |= CWBorderPixel; - swa.border_pixel = 0; + req.border_pixel = 0; bounds_in_pixels_ = SanitizeBounds(config.bounds); - xwindow_ = XCreateWindow(xdisplay_, x_root_window_, bounds_in_pixels_.x(), - bounds_in_pixels_.y(), bounds_in_pixels_.width(), - bounds_in_pixels_.height(), - 0, // border width - depth, InputOutput, visual, attribute_mask, &swa); + req.parent = x_root_window_; + req.x = bounds_in_pixels_.x(); + req.y = bounds_in_pixels_.y(); + req.width = bounds_in_pixels_.width(); + req.height = bounds_in_pixels_.height(); + req.depth = depth; + req.c_class = x11::WindowClass::InputOutput; + req.visual = visual_id; + xwindow_ = connection_->GenerateId<x11::Window>(); + req.wid = xwindow_; + connection_->CreateWindow(req); // It can be a status icon window. If it fails to initialize, don't provide // him with a native window handle, close self and let the client destroy @@ -281,15 +301,12 @@ void XWindow::Init(const Configuration& config) { StructureNotifyMask | PropertyChangeMask | PointerMotionMask; xwindow_events_ = - std::make_unique<ui::XScopedEventSelector>(xwindow_, event_mask); - XFlush(xdisplay_); + std::make_unique<XScopedEventSelector>(xwindow_, event_mask); + connection_->Flush(); - if (ui::IsXInput2Available()) - ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); + if (IsXInput2Available()) + TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); - // TODO(erg): We currently only request window deletion events. We also - // should listen for activation events and anything else that GTK+ listens - // for, and do something useful. // Request the _NET_WM_SYNC_REQUEST protocol which is used for synchronizing // between chrome and desktop compositor (or WM) during resizing. // The resizing behavior with _NET_WM_SYNC_REQUEST is: @@ -305,31 +322,29 @@ void XWindow::Init(const Configuration& config) { // frame with new content from chrome. // 7. Desktop compositor responses user mouse move events, and starts a new // resize process, go to step 1. - XAtom protocols[] = { + std::vector<x11::Atom> protocols = { gfx::GetAtom("WM_DELETE_WINDOW"), gfx::GetAtom("_NET_WM_PING"), gfx::GetAtom("_NET_WM_SYNC_REQUEST"), }; - XSetWMProtocols(xdisplay_, xwindow_, protocols, base::size(protocols)); + SetArrayProperty(xwindow_, gfx::GetAtom("WM_PROTOCOLS"), x11::Atom::ATOM, + protocols); - // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with - // the desktop environment. - XSetWMProperties(xdisplay_, xwindow_, nullptr, nullptr, nullptr, 0, nullptr, - nullptr, nullptr); + // We need a WM_CLIENT_MACHINE value so we integrate with the desktop + // environment. + SetStringProperty(xwindow_, gfx::GetAtom("WM_CLIENT_MACHINE"), + gfx::GetAtom("STRING"), net::GetHostName()); // Likewise, the X server needs to know this window's pid so it knows which // program to kill if the window hangs. // XChangeProperty() expects "pid" to be long. - static_assert(sizeof(long) >= sizeof(pid_t), - "pid_t should not be larger than long"); - long pid = getpid(); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_PID"), XA_CARDINAL, - 32, PropModeReplace, reinterpret_cast<unsigned char*>(&pid), - 1); + static_assert(sizeof(uint32_t) >= sizeof(pid_t), + "pid_t should not be larger than uint32_t"); + uint32_t pid = getpid(); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_PID"), x11::Atom::CARDINAL, pid); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_WINDOW_TYPE"), - XA_ATOM, 32, PropModeReplace, - reinterpret_cast<unsigned char*>(&window_type), 1); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_TYPE"), x11::Atom::ATOM, + window_type); // The changes to |window_properties_| here will be sent to the X server just // before the window is mapped. @@ -350,16 +365,16 @@ void XWindow::Init(const Configuration& config) { workspace_ = base::nullopt; if (config.visible_on_all_workspaces) { window_properties_.insert(gfx::GetAtom("_NET_WM_STATE_STICKY")); - ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllWorkspaces); + SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllWorkspaces); } else if (!config.workspace.empty()) { int workspace; if (base::StringToInt(config.workspace, &workspace)) - ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", workspace); + SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", workspace); } if (!config.wm_class_name.empty() || !config.wm_class_class.empty()) { - ui::SetWindowClassHint(xdisplay_, xwindow_, config.wm_class_name, - config.wm_class_class); + SetWindowClassHint(connection_, xwindow_, config.wm_class_name, + config.wm_class_class); } const char* wm_role_name = nullptr; @@ -380,40 +395,40 @@ void XWindow::Init(const Configuration& config) { } } if (wm_role_name) - ui::SetWindowRole(xdisplay_, xwindow_, std::string(wm_role_name)); + SetWindowRole(xwindow_, std::string(wm_role_name)); if (config.remove_standard_frame) { // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force // fullscreen on the window when it matches the desktop size. - ui::SetHideTitlebarWhenMaximizedProperty(xwindow_, - ui::HIDE_TITLEBAR_WHEN_MAXIMIZED); + SetHideTitlebarWhenMaximizedProperty(xwindow_, + HIDE_TITLEBAR_WHEN_MAXIMIZED); } if (config.prefer_dark_theme) { - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_GTK_THEME_VARIANT"), - gfx::GetAtom("UTF8_STRING"), 8, PropModeReplace, - kDarkGtkThemeVariant, base::size(kDarkGtkThemeVariant) - 1); + SetStringProperty(xwindow_, gfx::GetAtom("_GTK_THEME_VARIANT"), + gfx::GetAtom("UTF8_STRING"), kDarkGtkThemeVariant); } - if (ui::IsSyncExtensionAvailable()) { - XSyncValue value; - XSyncIntToValue(&value, 0); - update_counter_ = XSyncCreateCounter(xdisplay_, value); - extended_update_counter_ = XSyncCreateCounter(xdisplay_, value); - XID counters[]{update_counter_, extended_update_counter_}; + if (IsSyncExtensionAvailable()) { + x11::Sync::Int64 value{}; + update_counter_ = connection_->GenerateId<x11::Sync::Counter>(); + connection_->sync().CreateCounter({update_counter_, value}); + extended_update_counter_ = connection_->GenerateId<x11::Sync::Counter>(); + connection_->sync().CreateCounter({extended_update_counter_, value}); + + std::vector<x11::Sync::Counter> counters{update_counter_, + extended_update_counter_}; // Set XSyncCounter as window property _NET_WM_SYNC_REQUEST_COUNTER. the // compositor will listen on them during resizing. - XChangeProperty( - xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_SYNC_REQUEST_COUNTER"), - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast<const unsigned char*>(counters), base::size(counters)); + SetArrayProperty(xwindow_, gfx::GetAtom("_NET_WM_SYNC_REQUEST_COUNTER"), + x11::Atom::CARDINAL, counters); } // Always composite Chromium windows if a compositing WM is used. Sometimes, // WMs will not composite fullscreen windows as an optimization, but this can // lead to tearing of fullscreen videos. - ui::SetIntProperty(xwindow_, "_NET_WM_BYPASS_COMPOSITOR", "CARDINAL", 2); + SetIntProperty(xwindow_, "_NET_WM_BYPASS_COMPOSITOR", "CARDINAL", 2); if (config.icon) SetXWindowIcons(gfx::ImageSkia(), *config.icon); @@ -422,58 +437,55 @@ void XWindow::Init(const Configuration& config) { void XWindow::Map(bool inactive) { // Before we map the window, set size hints. Otherwise, some window managers // will ignore toplevel XMoveWindow commands. - XSizeHints size_hints; - size_hints.flags = 0; - long supplied_return; - XGetWMNormalHints(xdisplay_, xwindow_, &size_hints, &supplied_return); - size_hints.flags |= PPosition; + SizeHints size_hints; + memset(&size_hints, 0, sizeof(size_hints)); + GetWmNormalHints(xwindow_, &size_hints); + size_hints.flags |= SIZE_HINT_P_POSITION; size_hints.x = bounds_in_pixels_.x(); size_hints.y = bounds_in_pixels_.y(); - XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); + SetWmNormalHints(xwindow_, size_hints); ignore_keyboard_input_ = inactive; - unsigned long wm_user_time_ms = + uint32_t wm_user_time_ms = ignore_keyboard_input_ ? 0 : X11EventSource::GetInstance()->GetTimestamp(); if (inactive || wm_user_time_ms != 0) { - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"), - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast<const unsigned char*>(&wm_user_time_ms), - 1); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"), + x11::Atom::CARDINAL, wm_user_time_ms); } UpdateMinAndMaxSize(); if (window_properties_.empty()) { - XDeleteProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_STATE")); + DeleteProperty(xwindow_, gfx::GetAtom("_NET_WM_STATE")); } else { - ui::SetAtomArrayProperty(xwindow_, "_NET_WM_STATE", "ATOM", - std::vector<XAtom>(std::begin(window_properties_), + SetAtomArrayProperty(xwindow_, "_NET_WM_STATE", "ATOM", + std::vector<x11::Atom>(std::begin(window_properties_), std::end(window_properties_))); } - XMapWindow(xdisplay_, xwindow_); + connection_->MapWindow({xwindow_}); window_mapped_in_client_ = true; // TODO(thomasanderson): Find out why this flush is necessary. - XFlush(xdisplay_); + connection_->Flush(); } void XWindow::Close() { - if (xwindow_ == x11::None) + if (xwindow_ == x11::Window::None) return; CancelResize(); UnconfineCursor(); - XDestroyWindow(xdisplay_, xwindow_); - xwindow_ = x11::None; + connection_->DestroyWindow({xwindow_}); + xwindow_ = x11::Window::None; - if (update_counter_ != x11::None) { - XSyncDestroyCounter(xdisplay_, update_counter_); - XSyncDestroyCounter(xdisplay_, extended_update_counter_); - update_counter_ = x11::None; - extended_update_counter_ = x11::None; + if (update_counter_ != x11::Sync::Counter{}) { + connection_->sync().DestroyCounter({update_counter_}); + connection_->sync().DestroyCounter({extended_update_counter_}); + update_counter_ = {}; + extended_update_counter_ = {}; } } @@ -487,10 +499,12 @@ void XWindow::Maximize() { } void XWindow::Minimize() { - if (window_mapped_in_client_) - XIconifyWindow(xdisplay_, xwindow_, 0); - else - SetWMSpecState(true, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::None); + if (window_mapped_in_client_) { + SendClientMessage(xwindow_, x_root_window_, gfx::GetAtom("WM_CHANGE_STATE"), + {WM_STATE_ICONIC, 0, 0, 0, 0}); + } else { + SetWMSpecState(true, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None); + } } void XWindow::Unmaximize() { @@ -506,18 +520,18 @@ bool XWindow::Hide() { // Make sure no resize task will run after the window is unmapped. CancelResize(); - XWithdrawWindow(xdisplay_, xwindow_, 0); + WithdrawWindow(xwindow_); window_mapped_in_client_ = false; return true; } void XWindow::Unhide() { - SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::None); + SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None); } void XWindow::SetFullscreen(bool fullscreen) { SetWMSpecState(fullscreen, gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"), - x11::None); + x11::Atom::None); } void XWindow::Activate() { @@ -531,45 +545,41 @@ void XWindow::Activate() { // wmii says that it supports _NET_ACTIVE_WINDOW but does not. // https://code.google.com/p/wmii/issues/detail?id=266 static bool wm_supports_active_window = - ui::GuessWindowManager() != ui::WM_WMII && - ui::WmSupportsHint(gfx::GetAtom("_NET_ACTIVE_WINDOW")); + GuessWindowManager() != WM_WMII && + WmSupportsHint(gfx::GetAtom("_NET_ACTIVE_WINDOW")); ::Time timestamp = X11EventSource::GetInstance()->GetTimestamp(); // override_redirect windows ignore _NET_ACTIVE_WINDOW. // https://crbug.com/940924 if (wm_supports_active_window && !override_redirect_) { - XEvent xclient; - memset(&xclient, 0, sizeof(xclient)); - xclient.type = ClientMessage; - xclient.xclient.window = xwindow_; - xclient.xclient.message_type = gfx::GetAtom("_NET_ACTIVE_WINDOW"); - xclient.xclient.format = 32; - xclient.xclient.data.l[0] = 1; // Specified we are an app. - xclient.xclient.data.l[1] = timestamp; - // TODO(thomasanderson): if another chrome window is active, specify that in - // data.l[2]. The EWMH spec claims this may make the WM more likely to - // service our _NET_ACTIVE_WINDOW request. - xclient.xclient.data.l[2] = x11::None; - xclient.xclient.data.l[3] = 0; - xclient.xclient.data.l[4] = 0; - - XSendEvent(xdisplay_, x_root_window_, x11::False, - SubstructureRedirectMask | SubstructureNotifyMask, &xclient); + std::array<uint32_t, 5> data = { + // We're an app. + 1, + timestamp, + // TODO(thomasanderson): if another chrome window is active, specify + // that here. The EWMH spec claims this may make the WM more likely to + // service our _NET_ACTIVE_WINDOW request. + 0, + 0, + 0, + }; + SendClientMessage(xwindow_, x_root_window_, + gfx::GetAtom("_NET_ACTIVE_WINDOW"), data); } else { - XRaiseWindow(xdisplay_, xwindow_); + RaiseWindow(xwindow_); // Directly ask the X server to give focus to the window. Note that the call // would have raised an X error if the window is not mapped. - auto ignore_errors = [](XDisplay*, XErrorEvent*) -> int { return 0; }; - auto old_error_handler = XSetErrorHandler(ignore_errors); - XSetInputFocus(xdisplay_, xwindow_, RevertToParent, timestamp); + connection_ + ->SetInputFocus({x11::InputFocus::Parent, xwindow_, + static_cast<x11::Time>(timestamp)}) + .IgnoreError(); // At this point, we know we will receive focus, and some // webdriver tests depend on a window being IsActive() immediately // after an Activate(), so just set this state now. has_pointer_focus_ = false; has_window_focus_ = true; window_mapped_in_server_ = true; - XSetErrorHandler(old_error_handler); } AfterActivationStateChanged(); @@ -581,7 +591,7 @@ void XWindow::Deactivate() { // Ignore future input events. ignore_keyboard_input_ = true; - XLowerWindow(xdisplay_, xwindow_); + ui::LowerWindow(xwindow_); AfterActivationStateChanged(); } @@ -594,8 +604,9 @@ bool XWindow::IsActive() const { return (has_window_focus_ || has_pointer_focus_) && !ignore_keyboard_input_; } void XWindow::SetSize(const gfx::Size& size_in_pixels) { - XResizeWindow(xdisplay_, xwindow_, size_in_pixels.width(), - size_in_pixels.height()); + connection_->ConfigureWindow({.window = xwindow_, + .width = size_in_pixels.width(), + .height = size_in_pixels.height()}); bounds_in_pixels_.set_size(size_in_pixels); } @@ -603,8 +614,8 @@ void XWindow::SetBounds(const gfx::Rect& requested_bounds_in_pixels) { gfx::Rect bounds_in_pixels(requested_bounds_in_pixels); bool origin_changed = bounds_in_pixels_.origin() != bounds_in_pixels.origin(); bool size_changed = bounds_in_pixels_.size() != bounds_in_pixels.size(); - XWindowChanges changes = {0}; - unsigned value_mask = 0; + + x11::ConfigureWindowRequest req{.window = xwindow_}; if (size_changed) { // Update the minimum and maximum sizes in case they have changed. @@ -622,19 +633,17 @@ void XWindow::SetBounds(const gfx::Rect& requested_bounds_in_pixels) { bounds_in_pixels.set_size(size_in_pixels); } - changes.width = bounds_in_pixels.width(); - changes.height = bounds_in_pixels.height(); - value_mask |= CWHeight | CWWidth; + req.width = bounds_in_pixels.width(); + req.height = bounds_in_pixels.height(); } if (origin_changed) { - changes.x = bounds_in_pixels.x(); - changes.y = bounds_in_pixels.y(); - value_mask |= CWX | CWY; + req.x = bounds_in_pixels.x(); + req.y = bounds_in_pixels.y(); } - if (value_mask) - XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes); + if (origin_changed || size_changed) + connection_->ConfigureWindow(req); // Assume that the resize will go through as requested, which should be the // case if we're running without a window manager. If there's a window @@ -658,23 +667,23 @@ bool XWindow::IsXWindowVisible() const { } bool XWindow::IsMinimized() const { - return ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_HIDDEN")); + return HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_HIDDEN")); } bool XWindow::IsMaximized() const { - return (ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) && - ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"))); + return (HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) && + HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"))); } bool XWindow::IsFullscreen() const { - return ui::HasWMSpecProperty(window_properties_, - gfx::GetAtom("_NET_WM_STATE_FULLSCREEN")); + return HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_FULLSCREEN")); } -gfx::Rect XWindow::GetOutterBounds() const { +gfx::Rect XWindow::GetOuterBounds() const { gfx::Rect outer_bounds(bounds_in_pixels_); outer_bounds.Inset(-native_window_frame_borders_in_pixels_); return outer_bounds; @@ -687,18 +696,18 @@ void XWindow::GrabPointer() { } void XWindow::ReleasePointerGrab() { - ui::UngrabPointer(); + UngrabPointer(); has_pointer_grab_ = false; } -void XWindow::StackXWindowAbove(::Window window) { - DCHECK(window != x11::None); +void XWindow::StackXWindowAbove(x11::Window window) { + DCHECK(window != x11::Window::None); // Find all parent windows up to the root. - std::vector<::Window> window_below_parents = - GetParentsList(xdisplay_, window); - std::vector<::Window> window_above_parents = - GetParentsList(xdisplay_, xwindow_); + std::vector<x11::Window> window_below_parents = + GetParentsList(connection_, window); + std::vector<x11::Window> window_above_parents = + GetParentsList(connection_, xwindow_); // Find their common ancestor. auto it_below_window = window_below_parents.rbegin(); @@ -711,23 +720,21 @@ void XWindow::StackXWindowAbove(::Window window) { if (it_below_window != window_below_parents.rend() && it_above_window != window_above_parents.rend()) { - // First stack |xwindow| below so Z-order of |window| stays the same. - ::Window windows[] = {*it_below_window, *it_above_window}; - if (XRestackWindows(xdisplay_, windows, 2) == 0) { - // Now stack them properly. - std::swap(windows[0], windows[1]); - XRestackWindows(xdisplay_, windows, 2); - } + connection_->ConfigureWindow({ + .window = *it_above_window, + .sibling = *it_below_window, + .stack_mode = x11::StackMode::Above, + }); } } void XWindow::StackXWindowAtTop() { - XRaiseWindow(xdisplay_, xwindow_); + RaiseWindow(xwindow_); } void XWindow::SetCursor(::Cursor cursor) { last_cursor_ = cursor; - XDefineCursor(xdisplay_, xwindow_, cursor); + DefineCursor(xwindow_, static_cast<x11::Cursor>(cursor)); } bool XWindow::SetTitle(base::string16 title) { @@ -736,17 +743,10 @@ bool XWindow::SetTitle(base::string16 title) { window_title_ = title; std::string utf8str = base::UTF16ToUTF8(title); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_NAME"), - gfx::GetAtom("UTF8_STRING"), 8, PropModeReplace, - reinterpret_cast<const unsigned char*>(utf8str.c_str()), - utf8str.size()); - XTextProperty xtp; - char* c_utf8_str = const_cast<char*>(utf8str.c_str()); - if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1, XUTF8StringStyle, - &xtp) == x11::Success) { - XSetWMName(xdisplay_, xwindow_, &xtp); - XFree(xtp.value); - } + SetStringProperty(xwindow_, gfx::GetAtom("_NET_WM_NAME"), + gfx::GetAtom("UTF8_STRING"), utf8str); + SetStringProperty(xwindow_, x11::Atom::WM_NAME, gfx::GetAtom("UTF8_STRING"), + utf8str); return true; } @@ -756,35 +756,35 @@ void XWindow::SetXWindowOpacity(float opacity) { // XChangeProperty() expects "cardinality" to be long. // Scale opacity to [0 .. 255] range. - unsigned long opacity_8bit = - static_cast<unsigned long>(opacity * 255.0f) & 0xFF; + uint32_t opacity_8bit = static_cast<uint32_t>(opacity * 255.0f) & 0xFF; // Use opacity value for all channels. - const unsigned long channel_multiplier = 0x1010101; - unsigned long cardinality = opacity_8bit * channel_multiplier; + uint32_t channel_multiplier = 0x1010101; + uint32_t cardinality = opacity_8bit * channel_multiplier; if (cardinality == 0xffffffff) { - XDeleteProperty(xdisplay_, xwindow_, - gfx::GetAtom("_NET_WM_WINDOW_OPACITY")); + DeleteProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_OPACITY")); } else { - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_WINDOW_OPACITY"), - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast<unsigned char*>(&cardinality), 1); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_WINDOW_OPACITY"), + x11::Atom::CARDINAL, cardinality); } } void XWindow::SetXWindowAspectRatio(const gfx::SizeF& aspect_ratio) { - XSizeHints size_hints; - size_hints.flags = 0; - long supplied_return; + SizeHints size_hints; + memset(&size_hints, 0, sizeof(size_hints)); - XGetWMNormalHints(xdisplay_, xwindow_, &size_hints, &supplied_return); + GetWmNormalHints(xwindow_, &size_hints); // Unforce aspect ratio is parameter length is 0, otherwise set normally. - if (!aspect_ratio.IsEmpty()) { - size_hints.flags |= PAspect; - size_hints.min_aspect.x = size_hints.max_aspect.x = aspect_ratio.width(); - size_hints.min_aspect.y = size_hints.max_aspect.y = aspect_ratio.height(); + if (aspect_ratio.IsEmpty()) { + size_hints.flags &= ~SIZE_HINT_P_ASPECT; + } else { + size_hints.flags |= SIZE_HINT_P_ASPECT; + size_hints.min_aspect_num = size_hints.max_aspect_num = + aspect_ratio.width(); + size_hints.min_aspect_den = size_hints.max_aspect_den = + aspect_ratio.height(); } - XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); + SetWmNormalHints(xwindow_, size_hints); } void XWindow::SetXWindowIcons(const gfx::ImageSkia& window_icon, @@ -797,7 +797,7 @@ void XWindow::SetXWindowIcons(const gfx::ImageSkia& window_icon, // so that we can pass to the WM. // // All of this could be made much, much better. - std::vector<unsigned long> data; + std::vector<uint32_t> data; if (!window_icon.isNull()) SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data); @@ -805,35 +805,27 @@ void XWindow::SetXWindowIcons(const gfx::ImageSkia& window_icon, if (!app_icon.isNull()) SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data); - if (!data.empty()) - ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data); + if (!data.empty()) { + SetArrayProperty(xwindow_, gfx::GetAtom("_NET_WM_ICON"), + x11::Atom::CARDINAL, data); + } } void XWindow::SetXWindowVisibleOnAllWorkspaces(bool visible) { - SetWMSpecState(visible, gfx::GetAtom("_NET_WM_STATE_STICKY"), x11::None); + SetWMSpecState(visible, gfx::GetAtom("_NET_WM_STATE_STICKY"), + x11::Atom::None); int new_desktop = 0; if (visible) { new_desktop = kAllWorkspaces; } else { - if (!ui::GetCurrentDesktop(&new_desktop)) + if (!GetCurrentDesktop(&new_desktop)) return; } workspace_ = kAllWorkspaces; - XEvent xevent; - memset(&xevent, 0, sizeof(xevent)); - xevent.type = ClientMessage; - xevent.xclient.window = xwindow_; - xevent.xclient.message_type = gfx::GetAtom("_NET_WM_DESKTOP"); - xevent.xclient.format = 32; - xevent.xclient.data.l[0] = new_desktop; - xevent.xclient.data.l[1] = 0; - xevent.xclient.data.l[2] = 0; - xevent.xclient.data.l[3] = 0; - xevent.xclient.data.l[4] = 0; - XSendEvent(xdisplay_, x_root_window_, x11::False, - SubstructureRedirectMask | SubstructureNotifyMask, &xevent); + SendClientMessage(xwindow_, x_root_window_, gfx::GetAtom("_NET_WM_DESKTOP"), + {new_desktop, 0, 0, 0, 0}); } bool XWindow::IsXWindowVisibleOnAllWorkspaces() const { @@ -845,13 +837,15 @@ bool XWindow::IsXWindowVisibleOnAllWorkspaces() const { } void XWindow::MoveCursorTo(const gfx::Point& location_in_pixels) { - XWarpPointer(xdisplay_, x11::None, x_root_window_, 0, 0, 0, 0, - bounds_in_pixels_.x() + location_in_pixels.x(), - bounds_in_pixels_.y() + location_in_pixels.y()); + connection_->WarpPointer({ + .dst_window = x_root_window_, + .dst_x = bounds_in_pixels_.x() + location_in_pixels.x(), + .dst_y = bounds_in_pixels_.y() + location_in_pixels.y(), + }); } void XWindow::ResetWindowRegion() { - XRegion* xregion = nullptr; + std::unique_ptr<std::vector<x11::Rectangle>> xregion; if (!use_custom_shape() && !IsMaximized() && !IsFullscreen()) { SkPath window_mask; GetWindowMaskForXWindow(bounds().size(), &window_mask); @@ -860,13 +854,13 @@ void XWindow::ResetWindowRegion() { if (window_mask.countPoints() > 0) xregion = gfx::CreateRegionFromSkPath(window_mask); } - UpdateWindowRegion(xregion); + UpdateWindowRegion(std::move(xregion)); } void XWindow::OnWorkspaceUpdated() { auto old_workspace = workspace_; int workspace; - if (ui::GetWindowDesktop(xwindow_, &workspace)) + if (GetWindowDesktop(xwindow_, &workspace)) workspace_ = workspace; else workspace_ = base::nullopt; @@ -877,25 +871,24 @@ void XWindow::OnWorkspaceUpdated() { void XWindow::SetAlwaysOnTop(bool always_on_top) { is_always_on_top_ = always_on_top; - SetWMSpecState(always_on_top, gfx::GetAtom("_NET_WM_STATE_ABOVE"), x11::None); + SetWMSpecState(always_on_top, gfx::GetAtom("_NET_WM_STATE_ABOVE"), + x11::Atom::None); } void XWindow::SetFlashFrameHint(bool flash_frame) { if (urgency_hint_set_ == flash_frame) return; - gfx::XScopedPtr<XWMHints> hints(XGetWMHints(xdisplay_, xwindow_)); - if (!hints) { - // The window hasn't had its hints set yet. - hints.reset(XAllocWMHints()); - } + WmHints hints; + memset(&hints, 0, sizeof(hints)); + GetWmHints(xwindow_, &hints); if (flash_frame) - hints->flags |= XUrgencyHint; + hints.flags |= WM_HINT_X_URGENCY; else - hints->flags &= ~XUrgencyHint; + hints.flags &= ~WM_HINT_X_URGENCY; - XSetWMHints(xdisplay_, xwindow_, hints.get()); + SetWmHints(xwindow_, hints); urgency_hint_set_ = flash_frame; } @@ -911,28 +904,27 @@ void XWindow::UpdateMinAndMaxSize() { min_size_in_pixels_ = minimum_in_pixels.value(); max_size_in_pixels_ = maximum_in_pixels.value(); - XSizeHints hints; - hints.flags = 0; - long supplied_return; - XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return); + SizeHints hints; + memset(&hints, 0, sizeof(hints)); + GetWmNormalHints(xwindow_, &hints); if (min_size_in_pixels_.IsEmpty()) { - hints.flags &= ~PMinSize; + hints.flags &= ~SIZE_HINT_P_MIN_SIZE; } else { - hints.flags |= PMinSize; + hints.flags |= SIZE_HINT_P_MIN_SIZE; hints.min_width = min_size_in_pixels_.width(); hints.min_height = min_size_in_pixels_.height(); } if (max_size_in_pixels_.IsEmpty()) { - hints.flags &= ~PMaxSize; + hints.flags &= ~SIZE_HINT_P_MAX_SIZE; } else { - hints.flags |= PMaxSize; + hints.flags |= SIZE_HINT_P_MAX_SIZE; hints.max_width = max_size_in_pixels_.width(); hints.max_height = max_size_in_pixels_.height(); } - XSetWMNormalHints(xdisplay_, xwindow_, &hints); + SetWmNormalHints(xwindow_, hints); } void XWindow::BeforeActivationStateChanged() { @@ -961,24 +953,24 @@ void XWindow::AfterActivationStateChanged() { void XWindow::SetUseNativeFrame(bool use_native_frame) { use_native_frame_ = use_native_frame; - ui::SetUseOSWindowFrame(xwindow_, use_native_frame); + SetUseOSWindowFrame(xwindow_, use_native_frame); ResetWindowRegion(); } void XWindow::OnCrossingEvent(bool enter, bool focus_in_window_or_ancestor, - int mode, - int detail) { + x11::NotifyMode mode, + x11::NotifyDetail detail) { // NotifyInferior on a crossing event means the pointer moved into or out of a // child window, but the pointer is still within |xwindow_|. - if (detail == NotifyInferior) + if (detail == x11::NotifyDetail::Inferior) return; BeforeActivationStateChanged(); - if (mode == NotifyGrab) + if (mode == x11::NotifyMode::Grab) has_pointer_grab_ = enter; - else if (mode == NotifyUngrab) + else if (mode == x11::NotifyMode::Ungrab) has_pointer_grab_ = false; has_pointer_ = enter; @@ -994,13 +986,16 @@ void XWindow::OnCrossingEvent(bool enter, AfterActivationStateChanged(); } -void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { +void XWindow::OnFocusEvent(bool focus_in, + x11::NotifyMode mode, + x11::NotifyDetail detail) { // NotifyInferior on a focus event means the focus moved into or out of a // child window, but the focus is still within |xwindow_|. - if (detail == NotifyInferior) + if (detail == x11::NotifyDetail::Inferior) return; - bool notify_grab = mode == NotifyGrab || mode == NotifyUngrab; + bool notify_grab = + mode == x11::NotifyMode::Grab || mode == x11::NotifyMode::Ungrab; BeforeActivationStateChanged(); @@ -1010,13 +1005,13 @@ void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { // For |has_pointer_focus_| and |has_window_focus_|, we continue tracking // state during a grab, but ignore grab/ungrab events themselves. - if (!notify_grab && detail != NotifyPointer) + if (!notify_grab && detail != x11::NotifyDetail::Pointer) has_window_focus_ = focus_in; if (!notify_grab && has_pointer_) { switch (detail) { - case NotifyAncestor: - case NotifyVirtual: + case x11::NotifyDetail::Ancestor: + case x11::NotifyDetail::Virtual: // If we reach this point, we know |has_pointer_| was true before and // after this event. Since the definition of |has_pointer_focus_| is // (An ancestor window or the PointerRoot is focused) && |has_pointer_|, @@ -1033,7 +1028,7 @@ void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { // (FocusIn with NotifyVirtual) has_pointer_focus_ = !focus_in; break; - case NotifyPointer: + case x11::NotifyDetail::Pointer: // The remaining cases for |has_pointer_focus_| becoming true are: // 3. Focus moves from |xwindow_| to the PointerRoot // 4. Focus moves from a descendant of |xwindow_| to the PointerRoot @@ -1052,8 +1047,8 @@ void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { // In each case, we will get a FocusOut with a detail of NotifyPointer. has_pointer_focus_ = focus_in; break; - case NotifyNonlinear: - case NotifyNonlinearVirtual: + case x11::NotifyDetail::Nonlinear: + case x11::NotifyDetail::NonlinearVirtual: // We get Nonlinear(Virtual) events when // 1. Focus moves from Other to |xwindow_| // (FocusIn with NotifyNonlinear) @@ -1076,11 +1071,12 @@ void XWindow::OnFocusEvent(bool focus_in, int mode, int detail) { AfterActivationStateChanged(); } -bool XWindow::IsTargetedBy(const XEvent& xev) const { - ::Window target_window = - (xev.type == GenericEvent) +bool XWindow::IsTargetedBy(const x11::Event& x11_event) const { + const XEvent& xev = x11_event.xlib_event(); + auto target_window = static_cast<x11::Window>( + xev.type == x11::GeGenericEvent::opcode ? static_cast<XIDeviceEvent*>(xev.xcookie.data)->event - : xev.xany.window; + : xev.xany.window); return target_window == xwindow_; } @@ -1089,16 +1085,16 @@ void XWindow::WmMoveResize(int hittest, const gfx::Point& location) const { if (direction == -1) return; - DoWMMoveResize(xdisplay_, x_root_window_, xwindow_, location, direction); + DoWMMoveResize(connection_, x_root_window_, xwindow_, location, direction); } -// In Ozone, there are no ui::*Event constructors receiving XEvent* as input, -// in this case ui::PlatformEvent is expected. Furthermore, +// In Ozone, there are no *Event constructors receiving XEvent* as input, +// in this case PlatformEvent is expected. Furthermore, // X11EventSourceLibevent is used in that case, which already translates -// Mouse/Key/Touch/Scroll events into ui::Events so they should not be handled +// Mouse/Key/Touch/Scroll events into Events so they should not be handled // by PlatformWindow, which is supposed to use XWindow in Ozone builds. So // handling these events is disabled for Ozone. -void XWindow::ProcessEvent(XEvent* xev) { +void XWindow::ProcessEvent(x11::Event* xev) { // We can lose track of the window's position when the window is reparented. // When the parent window is moved, we won't get an event, so the window's // position relative to the root window will get out-of-sync. We can re-sync @@ -1106,8 +1102,8 @@ void XWindow::ProcessEvent(XEvent* xev) { // ButtonRelease, MotionNotify) which include the pointer location both // relative to this window and relative to the root window, so we can // calculate this window's position from that information. - gfx::Point window_point = ui::EventLocationFromXEvent(*xev); - gfx::Point root_point = ui::EventSystemLocationFromXEvent(*xev); + gfx::Point window_point = EventLocationFromXEvent(*xev); + gfx::Point root_point = EventSystemLocationFromXEvent(*xev); if (!window_point.IsOrigin() && !root_point.IsOrigin()) { gfx::Point window_origin = gfx::Point() + (root_point - window_point); if (bounds_in_pixels_.origin() != window_origin) { @@ -1118,135 +1114,115 @@ void XWindow::ProcessEvent(XEvent* xev) { // May want to factor CheckXEventForConsistency(xev); into a common location // since it is called here. - switch (xev->type) { - case EnterNotify: - case LeaveNotify: { - OnCrossingEvent(xev->type == EnterNotify, xev->xcrossing.focus, - xev->xcrossing.mode, xev->xcrossing.detail); - break; - } - case Expose: { - gfx::Rect damage_rect_in_pixels(xev->xexpose.x, xev->xexpose.y, - xev->xexpose.width, xev->xexpose.height); - OnXWindowDamageEvent(damage_rect_in_pixels); - break; - } - case x11::FocusIn: - case x11::FocusOut: - OnFocusEvent(xev->type == x11::FocusIn, xev->xfocus.mode, - xev->xfocus.detail); - break; - case ConfigureNotify: - OnConfigureEvent(xev); - break; - case GenericEvent: { - ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); - if (!factory->ShouldProcessXI2Event(xev)) - break; - - XIEnterEvent* enter_event = static_cast<XIEnterEvent*>(xev->xcookie.data); - switch (static_cast<XIEvent*>(xev->xcookie.data)->evtype) { - case XI_Enter: - case XI_Leave: { - OnCrossingEvent(enter_event->evtype == XI_Enter, enter_event->focus, - XI2ModeToXMode(enter_event->mode), - enter_event->detail); - return; - } - case XI_FocusIn: - case XI_FocusOut: { - OnFocusEvent(enter_event->evtype == XI_FocusIn, - XI2ModeToXMode(enter_event->mode), enter_event->detail); - return; - } - default: + if (auto* crossing = xev->As<x11::CrossingEvent>()) { + bool focus = crossing->same_screen_focus & CROSSING_FLAG_FOCUS; + OnCrossingEvent(crossing->opcode == x11::CrossingEvent::EnterNotify, focus, + crossing->mode, crossing->detail); + } else if (auto* expose = xev->As<x11::ExposeEvent>()) { + gfx::Rect damage_rect_in_pixels(expose->x, expose->y, expose->width, + expose->height); + OnXWindowDamageEvent(damage_rect_in_pixels); + } else if (auto* focus = xev->As<x11::FocusEvent>()) { + OnFocusEvent(focus->opcode == x11::FocusEvent::In, focus->mode, + focus->detail); + } else if (auto* configure = xev->As<x11::ConfigureNotifyEvent>()) { + OnConfigureEvent(*configure); + } else if (auto* crossing = xev->As<x11::Input::CrossingEvent>()) { + TouchFactory* factory = TouchFactory::GetInstance(); + if (factory->ShouldProcessXI2Event(&xev->xlib_event())) { + auto mode = XI2ModeToXMode(crossing->mode); + auto detail = XI2DetailToXDetail(crossing->detail); + switch (crossing->opcode) { + case x11::Input::CrossingEvent::Enter: + OnCrossingEvent(true, crossing->focus, mode, detail); break; - } - break; - } - case MapNotify: { - OnWindowMapped(); - break; - } - case UnmapNotify: { - window_mapped_in_server_ = false; - has_pointer_ = false; - has_pointer_grab_ = false; - has_pointer_focus_ = false; - has_window_focus_ = false; - break; - } - case ClientMessage: { - Atom message_type = xev->xclient.message_type; - if (message_type == gfx::GetAtom("WM_PROTOCOLS")) { - Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]); - if (protocol == gfx::GetAtom("WM_DELETE_WINDOW")) { - // We have received a close message from the window manager. - OnXWindowCloseRequested(); - } else if (protocol == gfx::GetAtom("_NET_WM_PING")) { - XEvent reply_event = *xev; - reply_event.xclient.window = x_root_window_; - - XSendEvent(xdisplay_, reply_event.xclient.window, x11::False, - SubstructureRedirectMask | SubstructureNotifyMask, - &reply_event); - } else if (protocol == gfx::GetAtom("_NET_WM_SYNC_REQUEST")) { - pending_counter_value_ = - xev->xclient.data.l[2] + - (static_cast<int64_t>(xev->xclient.data.l[3]) << 32); - pending_counter_value_is_extended_ = xev->xclient.data.l[4] != 0; - } - } else { - OnXWindowDragDropEvent(xev); - } - break; - } - case MappingNotify: { - switch (xev->xmapping.request) { - case MappingModifier: - case MappingKeyboard: - XRefreshKeyboardMapping(&xev->xmapping); + case x11::Input::CrossingEvent::Leave: + OnCrossingEvent(false, crossing->focus, mode, detail); break; - case MappingPointer: - ui::DeviceDataManagerX11::GetInstance()->UpdateButtonMap(); + case x11::Input::CrossingEvent::FocusIn: + OnFocusEvent(true, mode, detail); break; - default: - NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request; + case x11::Input::CrossingEvent::FocusOut: + OnFocusEvent(false, mode, detail); break; } - break; } - case PropertyNotify: { - XAtom changed_atom = xev->xproperty.atom; - if (changed_atom == gfx::GetAtom("_NET_WM_STATE")) { - OnWMStateUpdated(); - } else if (changed_atom == gfx::GetAtom("_NET_FRAME_EXTENTS")) { - OnFrameExtentsUpdated(); - } else if (changed_atom == gfx::GetAtom("_NET_WM_DESKTOP")) { - OnWorkspaceUpdated(); + } else if (xev->As<x11::MapNotifyEvent>()) { + OnWindowMapped(); + } else if (xev->As<x11::UnmapNotifyEvent>()) { + window_mapped_in_server_ = false; + has_pointer_ = false; + has_pointer_grab_ = false; + has_pointer_focus_ = false; + has_window_focus_ = false; + } else if (auto* client = xev->As<x11::ClientMessageEvent>()) { + x11::Atom message_type = client->type; + if (message_type == gfx::GetAtom("WM_PROTOCOLS")) { + x11::Atom protocol = static_cast<x11::Atom>(client->data.data32[0]); + if (protocol == gfx::GetAtom("WM_DELETE_WINDOW")) { + // We have received a close message from the window manager. + OnXWindowCloseRequested(); + } else if (protocol == gfx::GetAtom("_NET_WM_PING")) { + x11::ClientMessageEvent reply_event = *client; + reply_event.window = x_root_window_; + + auto event_bytes = x11::Write(reply_event); + DCHECK_EQ(event_bytes.size(), 32ul); + + x11::SendEventRequest request{false, x_root_window_, + x11::EventMask::SubstructureNotify | + x11::EventMask::SubstructureRedirect}; + std::copy(event_bytes.begin(), event_bytes.end(), + request.event.begin()); + connection_->SendEvent(request); + } else if (protocol == gfx::GetAtom("_NET_WM_SYNC_REQUEST")) { + pending_counter_value_ = + client->data.data32[2] + + (static_cast<int64_t>(client->data.data32[3]) << 32); + pending_counter_value_is_extended_ = client->data.data32[4] != 0; } - break; + } else { + OnXWindowDragDropEvent(xev); } - case SelectionNotify: { - OnXWindowSelectionEvent(xev); - break; + } else if (auto* mapping = xev->As<x11::MappingNotifyEvent>()) { + switch (mapping->request) { + case x11::Mapping::Modifier: + case x11::Mapping::Keyboard: + XRefreshKeyboardMapping(&xev->xlib_event().xmapping); + break; + case x11::Mapping::Pointer: + DeviceDataManagerX11::GetInstance()->UpdateButtonMap(); + break; + default: + NOTIMPLEMENTED() << " Unknown request: " + << static_cast<int>(mapping->request); + break; + } + } else if (auto* property = xev->As<x11::PropertyNotifyEvent>()) { + x11::Atom changed_atom = property->atom; + if (changed_atom == gfx::GetAtom("_NET_WM_STATE")) { + OnWMStateUpdated(); + } else if (changed_atom == gfx::GetAtom("_NET_FRAME_EXTENTS")) { + OnFrameExtentsUpdated(); + } else if (changed_atom == gfx::GetAtom("_NET_WM_DESKTOP")) { + OnWorkspaceUpdated(); } + } else if (auto* selection = xev->As<x11::SelectionNotifyEvent>()) { + OnXWindowSelectionEvent(xev); } } -void XWindow::UpdateWMUserTime(ui::Event* event) { +void XWindow::UpdateWMUserTime(Event* event) { if (!IsActive()) return; DCHECK(event); - ui::EventType type = event->type(); - if (type == ui::ET_MOUSE_PRESSED || type == ui::ET_KEY_PRESSED || - type == ui::ET_TOUCH_PRESSED) { - unsigned long wm_user_time_ms = + EventType type = event->type(); + if (type == ET_MOUSE_PRESSED || type == ET_KEY_PRESSED || + type == ET_TOUCH_PRESSED) { + uint32_t wm_user_time_ms = (event->time_stamp() - base::TimeTicks()).InMilliseconds(); - XChangeProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"), - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast<const unsigned char*>(&wm_user_time_ms), - 1); + SetProperty(xwindow_, gfx::GetAtom("_NET_WM_USER_TIME"), + x11::Atom::CARDINAL, wm_user_time_ms); } } @@ -1260,31 +1236,33 @@ void XWindow::OnWindowMapped() { } } -void XWindow::OnConfigureEvent(XEvent* xev) { - DCHECK_EQ(xwindow_, xev->xconfigure.window); - DCHECK_EQ(xwindow_, xev->xconfigure.event); +void XWindow::OnConfigureEvent(const x11::ConfigureNotifyEvent& configure) { + DCHECK_EQ(xwindow_, configure.window); + DCHECK_EQ(xwindow_, configure.event); if (pending_counter_value_) { DCHECK(!configure_counter_value_); configure_counter_value_ = pending_counter_value_; configure_counter_value_is_extended_ = pending_counter_value_is_extended_; - pending_counter_value_is_extended_ = 0; + pending_counter_value_is_extended_ = false; pending_counter_value_ = 0; } // It's possible that the X window may be resized by some other means than // from within aura (e.g. the X window manager can change the size). Make // sure the root window size is maintained properly. - int translated_x_in_pixels = xev->xconfigure.x; - int translated_y_in_pixels = xev->xconfigure.y; - if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) { - Window unused; - XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_, 0, 0, - &translated_x_in_pixels, &translated_y_in_pixels, - &unused); + int translated_x_in_pixels = configure.x; + int translated_y_in_pixels = configure.y; + if (!configure.send_event && !configure.override_redirect) { + auto future = + connection_->TranslateCoordinates({xwindow_, x_root_window_, 0, 0}); + if (auto coords = future.Sync()) { + translated_x_in_pixels = coords->dst_x; + translated_y_in_pixels = coords->dst_y; + } } gfx::Rect bounds_in_pixels(translated_x_in_pixels, translated_y_in_pixels, - xev->xconfigure.width, xev->xconfigure.height); + configure.width, configure.height); bool size_changed = bounds_in_pixels_.size() != bounds_in_pixels.size(); bool origin_changed = bounds_in_pixels_.origin() != bounds_in_pixels.origin(); previous_bounds_in_pixels_ = bounds_in_pixels_; @@ -1296,13 +1274,13 @@ void XWindow::OnConfigureEvent(XEvent* xev) { NotifyBoundsChanged(bounds_in_pixels_); } -void XWindow::SetWMSpecState(bool enabled, XAtom state1, XAtom state2) { +void XWindow::SetWMSpecState(bool enabled, x11::Atom state1, x11::Atom state2) { if (window_mapped_in_client_) { ui::SetWMSpecState(xwindow_, enabled, state1, state2); } else { // The updated state will be set when the window is (re)mapped. - base::flat_set<XAtom> new_window_properties = window_properties_; - for (XAtom atom : {state1, state2}) { + base::flat_set<x11::Atom> new_window_properties = window_properties_; + for (x11::Atom atom : {state1, state2}) { if (enabled) new_window_properties.insert(atom); else @@ -1318,16 +1296,16 @@ void XWindow::OnWMStateUpdated() { // persist across a Hide() and Show(). So if the window is currently // unmapped, leave the state unchanged so it will be restored when the window // is remapped. - std::vector<XAtom> atom_list; - if (ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list) || + std::vector<x11::Atom> atom_list; + if (GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list) || window_mapped_in_client_) { UpdateWindowProperties( - base::flat_set<XAtom>(std::begin(atom_list), std::end(atom_list))); + base::flat_set<x11::Atom>(std::begin(atom_list), std::end(atom_list))); } } void XWindow::UpdateWindowProperties( - const base::flat_set<XAtom>& new_window_properties) { + const base::flat_set<x11::Atom>& new_window_properties) { was_minimized_ = IsMinimized(); window_properties_ = new_window_properties; @@ -1337,15 +1315,15 @@ void XWindow::UpdateWindowProperties( // handle window manager initiated fullscreen. In particular, Chrome needs to // do preprocessing before the x window's fullscreen state is toggled. - is_always_on_top_ = ui::HasWMSpecProperty( - window_properties_, gfx::GetAtom("_NET_WM_STATE_ABOVE")); + is_always_on_top_ = HasWMSpecProperty(window_properties_, + gfx::GetAtom("_NET_WM_STATE_ABOVE")); OnXWindowStateChanged(); ResetWindowRegion(); } void XWindow::OnFrameExtentsUpdated() { std::vector<int> insets; - if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) && + if (GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) && insets.size() == 4) { // |insets| are returned in the order: [left, right, top, bottom]. native_window_frame_borders_in_pixels_ = @@ -1363,14 +1341,14 @@ void XWindow::NotifySwapAfterResize() { // Setting an even number to |extended_update_counter_| will trigger a // new resize. current_counter_value_ += 3; - SyncSetCounter(xdisplay_, extended_update_counter_, + SyncSetCounter(connection_, extended_update_counter_, current_counter_value_); } return; } if (configure_counter_value_ != 0) { - SyncSetCounter(xdisplay_, update_counter_, configure_counter_value_); + SyncSetCounter(connection_, update_counter_, configure_counter_value_); configure_counter_value_ = 0; } } @@ -1378,7 +1356,8 @@ void XWindow::NotifySwapAfterResize() { // Removes |delayed_resize_task_| from the task queue (if it's in // the queue) and adds it back at the end of the queue. void XWindow::DispatchResize() { - if (update_counter_ == x11::None || configure_counter_value_ == 0) { + if (update_counter_ == x11::Sync::Counter{} || + configure_counter_value_ == 0) { // WM doesn't support _NET_WM_SYNC_REQUEST. // Or we are too slow, so _NET_WM_SYNC_REQUEST is disabled by the // compositor. @@ -1410,7 +1389,7 @@ void XWindow::DelayedResize(const gfx::Rect& bounds_in_pixels) { // are not frozen and re-enable _NET_WM_SYNC_REQUEST, if it was disabled. // Increase the |extended_update_counter_| to an odd number will not trigger // a new resize. - SyncSetCounter(xdisplay_, extended_update_counter_, + SyncSetCounter(connection_, extended_update_counter_, ++current_counter_value_); } @@ -1434,41 +1413,51 @@ void XWindow::ConfineCursorTo(const gfx::Rect& bounds) { gfx::Rect barrier = bounds + bounds_in_pixels_.OffsetFromOrigin(); + auto make_barrier = [&](uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, + x11::XFixes::BarrierDirections directions) { + x11::XFixes::Barrier barrier = + connection_->GenerateId<x11::XFixes::Barrier>(); + connection_->xfixes().CreatePointerBarrier( + {barrier, x_root_window_, x1, y1, x2, y2, directions}); + return barrier; + }; + // Top horizontal barrier. - pointer_barriers_[0] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, barrier.x(), barrier.y(), barrier.right(), - barrier.y(), BarrierPositiveY, 0, XIAllDevices); + pointer_barriers_[0] = + make_barrier(barrier.x(), barrier.y(), barrier.right(), barrier.y(), + x11::XFixes::BarrierDirections::PositiveY); // Bottom horizontal barrier. - pointer_barriers_[1] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, barrier.x(), barrier.bottom(), barrier.right(), - barrier.bottom(), BarrierNegativeY, 0, XIAllDevices); + pointer_barriers_[1] = + make_barrier(barrier.x(), barrier.bottom(), barrier.right(), + barrier.bottom(), x11::XFixes::BarrierDirections::NegativeY); // Left vertical barrier. - pointer_barriers_[2] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, barrier.x(), barrier.y(), barrier.x(), - barrier.bottom(), BarrierPositiveX, 0, XIAllDevices); + pointer_barriers_[2] = + make_barrier(barrier.x(), barrier.y(), barrier.x(), barrier.bottom(), + x11::XFixes::BarrierDirections::PositiveX); // Right vertical barrier. - pointer_barriers_[3] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, barrier.right(), barrier.y(), barrier.right(), - barrier.bottom(), BarrierNegativeX, 0, XIAllDevices); + pointer_barriers_[3] = + make_barrier(barrier.right(), barrier.y(), barrier.right(), + barrier.bottom(), x11::XFixes::BarrierDirections::NegativeX); has_pointer_barriers_ = true; } void XWindow::LowerWindow() { - XLowerWindow(xdisplay_, xwindow_); + ui::LowerWindow(xwindow_); } void XWindow::SetOverrideRedirect(bool override_redirect) { bool remap = window_mapped_in_client_; if (remap) Hide(); - XSetWindowAttributes swa; - swa.override_redirect = override_redirect; - XChangeWindowAttributes(xdisplay_, xwindow_, CWOverrideRedirect, &swa); + connection_->ChangeWindowAttributes({ + .window = xwindow_, + .override_redirect = x11::Bool32(override_redirect), + }); if (remap) { Map(); if (has_pointer_grab_) - ui::ChangeActivePointerGrabCursor(x11::None); + ChangeActivePointerGrabCursor(x11::None); } } @@ -1476,12 +1465,16 @@ bool XWindow::ContainsPointInRegion(const gfx::Point& point) const { if (!shape()) return true; - return XPointInRegion(shape(), point.x(), point.y()) == x11::True; + for (const auto& rect : *shape()) { + if (gfx::Rect(rect.x, rect.y, rect.width, rect.height).Contains(point)) + return true; + } + return false; } void XWindow::SetXWindowShape(std::unique_ptr<NativeShapeRects> native_shape, const gfx::Transform& transform) { - XRegion* xregion = nullptr; + std::unique_ptr<std::vector<x11::Rectangle>> xregion; if (native_shape) { SkRegion native_region; for (const gfx::Rect& rect : *native_shape) @@ -1493,7 +1486,7 @@ void XWindow::SetXWindowShape(std::unique_ptr<NativeShapeRects> native_shape, path_in_dip.transform(SkMatrix(transform.matrix()), &path_in_pixels); xregion = gfx::CreateRegionFromSkPath(path_in_pixels); } else { - xregion = XCreateRegion(); + xregion = std::make_unique<std::vector<x11::Rectangle>>(); } } else { xregion = gfx::CreateRegionFromSkRegion(native_region); @@ -1501,7 +1494,7 @@ void XWindow::SetXWindowShape(std::unique_ptr<NativeShapeRects> native_shape, } custom_window_shape_ = !!xregion; - window_shape_.reset(xregion); + window_shape_ = std::move(xregion); ResetWindowRegion(); } @@ -1509,25 +1502,35 @@ void XWindow::UnconfineCursor() { if (!has_pointer_barriers_) return; - for (XID pointer_barrier : pointer_barriers_) - XFixesDestroyPointerBarrier(xdisplay_, pointer_barrier); - pointer_barriers_.fill(x11::None); + for (auto pointer_barrier : pointer_barriers_) + connection_->xfixes().DeletePointerBarrier({pointer_barrier}); + + pointer_barriers_.fill({}); has_pointer_barriers_ = false; } -void XWindow::UpdateWindowRegion(XRegion* xregion) { +void XWindow::UpdateWindowRegion( + std::unique_ptr<std::vector<x11::Rectangle>> region) { + auto set_shape = [&](const std::vector<x11::Rectangle>& rectangles) { + connection_->shape().Rectangles({ + .operation = x11::Shape::So::Set, + .destination_kind = x11::Shape::Sk::Bounding, + .ordering = x11::ClipOrdering::YXBanded, + .destination_window = xwindow_, + .rectangles = rectangles, + }); + }; + // If a custom window shape was supplied then apply it. if (use_custom_shape()) { - XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 0, 0, - window_shape_.get(), false); + set_shape(*window_shape_); return; } - window_shape_.reset(xregion); + window_shape_ = std::move(region); if (window_shape_) { - XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 0, 0, - window_shape_.get(), false); + set_shape(*window_shape_); return; } @@ -1538,19 +1541,21 @@ void XWindow::UpdateWindowRegion(XRegion* xregion) { // If the window has system borders, the mask must be set to null (not a // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will // not put borders on a window with a custom shape. - XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, x11::None, - ShapeSet); + connection_->shape().Mask({ + .operation = x11::Shape::So::Set, + .destination_kind = x11::Shape::Sk::Bounding, + .destination_window = xwindow_, + .source_bitmap = x11::Pixmap::None, + }); } else { // Conversely, if the window does not have system borders, the mask must be // manually set to a rectangle that covers the whole window (not null). This // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null // shape causes the hint to disable system borders to be ignored (resulting // in a double border). - XRectangle r = {0, 0, - static_cast<unsigned short>(bounds_in_pixels_.width()), - static_cast<unsigned short>(bounds_in_pixels_.height())}; - XShapeCombineRectangles(xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, - ShapeSet, YXBanded); + x11::Rectangle r{0, 0, bounds_in_pixels_.width(), + bounds_in_pixels_.height()}; + set_shape({r}); } } @@ -1560,42 +1565,32 @@ void XWindow::NotifyBoundsChanged(const gfx::Rect& new_bounds_in_px) { } bool XWindow::InitializeAsStatusIcon() { - std::string atom_name = - "_NET_SYSTEM_TRAY_S" + base::NumberToString(DefaultScreen(xdisplay_)); - XID manager = XGetSelectionOwner(xdisplay_, gfx::GetAtom(atom_name.c_str())); - if (manager == x11::None) + std::string atom_name = "_NET_SYSTEM_TRAY_S" + + base::NumberToString(connection_->DefaultScreenId()); + auto reply = connection_->GetSelectionOwner({gfx::GetAtom(atom_name)}).Sync(); + if (!reply || reply->owner == x11::Window::None) return false; + auto manager = reply->owner; - ui::SetIntArrayProperty(xwindow_, "_XEMBED_INFO", "CARDINAL", - {kXembedInfoProtocolVersion, kXembedInfoFlags}); + SetIntArrayProperty(xwindow_, "_XEMBED_INFO", "CARDINAL", + {kXembedInfoProtocolVersion, kXembedInfoFlags}); - XSetWindowAttributes attrs; - unsigned long flags = 0; + x11::ChangeWindowAttributesRequest req{xwindow_}; if (has_alpha()) { - flags |= CWBackPixel; - attrs.background_pixel = 0; + req.background_pixel = 0; } else { - ui::SetIntProperty(xwindow_, "CHROMIUM_COMPOSITE_WINDOW", "CARDINAL", 1); - flags |= CWBackPixmap; - attrs.background_pixmap = ParentRelative; - } - XChangeWindowAttributes(xdisplay_, xwindow_, flags, &attrs); - XEvent ev; - memset(&ev, 0, sizeof(ev)); - ev.xclient.type = ClientMessage; - ev.xclient.window = manager; - ev.xclient.message_type = gfx::GetAtom("_NET_SYSTEM_TRAY_OPCODE"); - ev.xclient.format = 32; - ev.xclient.data.l[0] = ui::X11EventSource::GetInstance()->GetTimestamp(); - ev.xclient.data.l[1] = kSystemTrayRequestDock; - ev.xclient.data.l[2] = xwindow_; - bool error; - { - gfx::X11ErrorTracker error_tracker; - XSendEvent(xdisplay_, manager, false, NoEventMask, &ev); - error = error_tracker.FoundNewError(); + SetIntProperty(xwindow_, "CHROMIUM_COMPOSITE_WINDOW", "CARDINAL", 1); + req.background_pixmap = + static_cast<x11::Pixmap>(x11::BackPixmap::ParentRelative); } - return !error; + connection_->ChangeWindowAttributes(req); + + auto future = SendClientMessage( + manager, manager, gfx::GetAtom("_NET_SYSTEM_TRAY_OPCODE"), + {X11EventSource::GetInstance()->GetTimestamp(), kSystemTrayRequestDock, + static_cast<uint32_t>(xwindow_), 0, 0}, + x11::EventMask::NoEvent); + return !future.Sync().error; } } // namespace ui |