[X11] Refactor bounds handling to use WM synchronization
* Replace the direct use of the bounds_in_pixels_ with a new sync-based mechanism that tracks the last set bounds (stored in last_set_bounds_px_) and relies on a WmSync object plus a GeometryCache to obtain current geometry via GetBoundsInPixels(). * Update SetBoundsInPixels() and fullscreen logic to call SetBoundsWithWmSync(), so that window bounds are only updated once the WM has synchronized the change. This replaces ad-hoc direct assignments with a coordinated update via OnWmSynced() and OnBoundsChanged(). * Modify OnConfigureEvent() to initialize and later use the new sync tracking (via last_configure_size_ and last_swapped_size_), and add a helper MaybeUpdateSyncCounter() to flush pending counter updates when the configured size matches the swapped size. * Update the X11Extension interface (and its usage in DesktopWindowTreeHostLinux) so that OnCompleteSwapAfterResize() now accepts a new size parameter. Bug: 40528928, 381224161 Change-Id: I1a25874fc47c6573ec77427b38532f53e9802684 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6289229 Reviewed-by: Maksim Sisov <msisov@igalia.com> Reviewed-by: Elly FJ <ellyjones@chromium.org> Commit-Queue: Thomas Anderson <thomasanderson@chromium.org> Reviewed-by: Nick Yamane <nickdiego@igalia.com> Cr-Commit-Position: refs/heads/main@{#1429329}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
41ae968453
commit
d13172e652
chrome/browser/ui/views/tabs/dragging
ui
gfx
ozone
platform
platform_window
extensions
views
@@ -487,7 +487,7 @@ Browser* TabDragControllerTest::CreateAnotherBrowserAndResize() {
|
|||||||
gfx::Rect browser_rect(work_area.origin() + gfx::Vector2d(50, 50), size);
|
gfx::Rect browser_rect(work_area.origin() + gfx::Vector2d(50, 50), size);
|
||||||
|
|
||||||
if (test::PlatformSupportsScreenCoordinates()) {
|
if (test::PlatformSupportsScreenCoordinates()) {
|
||||||
browser()->window()->SetBounds(browser_rect);
|
ui_test_utils::SetAndWaitForBounds(*browser(), browser_rect);
|
||||||
browser_rect.set_x(browser_rect.right());
|
browser_rect.set_x(browser_rect.right());
|
||||||
} else {
|
} else {
|
||||||
test::ResizeUsingMouseEmulation(browser(), browser_rect);
|
test::ResizeUsingMouseEmulation(browser(), browser_rect);
|
||||||
@@ -509,7 +509,7 @@ Browser* TabDragControllerTest::CreateAnotherBrowserAndResize() {
|
|||||||
Browser* browser2 = CreateBrowser(browser()->profile());
|
Browser* browser2 = CreateBrowser(browser()->profile());
|
||||||
ResetIDs(browser2->tab_strip_model(), 100);
|
ResetIDs(browser2->tab_strip_model(), 100);
|
||||||
if (test::PlatformSupportsScreenCoordinates()) {
|
if (test::PlatformSupportsScreenCoordinates()) {
|
||||||
browser2->window()->SetBounds(browser_rect);
|
ui_test_utils::SetAndWaitForBounds(*browser2, browser_rect);
|
||||||
} else {
|
} else {
|
||||||
test::ResizeUsingMouseEmulation(browser2, browser_rect);
|
test::ResizeUsingMouseEmulation(browser2, browser_rect);
|
||||||
}
|
}
|
||||||
|
@@ -412,6 +412,17 @@ int Connection::GetFd() {
|
|||||||
return Ready() ? xcb_get_file_descriptor(XcbConnection()) : -1;
|
return Ready() ? xcb_get_file_descriptor(XcbConnection()) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Connection::CanSyncWithWm() const {
|
||||||
|
// For some WMs, we don't need to experimentally sync with them to determine
|
||||||
|
// sync support, so we can use WmSync right away. For now, only check for
|
||||||
|
// Openbox since that's what is used in tests. The list may be expanded as
|
||||||
|
// nearly all WMs should work with WmSync.
|
||||||
|
if (GetWmName() == "Openbox") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return synced_with_wm_;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& Connection::DisplayString() const {
|
const std::string& Connection::DisplayString() const {
|
||||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||||
return display_string_;
|
return display_string_;
|
||||||
|
@@ -255,9 +255,10 @@ class COMPONENT_EXPORT(X11) Connection final : public XProto,
|
|||||||
|
|
||||||
WindowEventManager& window_event_manager() { return window_event_manager_; }
|
WindowEventManager& window_event_manager() { return window_event_manager_; }
|
||||||
|
|
||||||
// Indicates if the connection was able to successfully sync with the
|
// Indicates if the connection is able to sync with the WM, either because the
|
||||||
// window manager.
|
// WM is on an allowlist or the connection successfully synced with the WM to
|
||||||
bool synced_with_wm() const { return synced_with_wm_; }
|
// test support experimentally.
|
||||||
|
bool CanSyncWithWm() const;
|
||||||
|
|
||||||
// Returns the underlying socket's FD if the connection is valid, or -1
|
// Returns the underlying socket's FD if the connection is valid, or -1
|
||||||
// otherwise.
|
// otherwise.
|
||||||
|
@@ -52,11 +52,17 @@ gfx::Rect GeometryCache::GetBoundsPx() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GeometryCache::OnQueryTreeResponse(QueryTreeResponse response) {
|
void GeometryCache::OnQueryTreeResponse(QueryTreeResponse response) {
|
||||||
|
if (have_parent_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
OnParentChanged(response ? response->parent : Window::None,
|
OnParentChanged(response ? response->parent : Window::None,
|
||||||
geometry_.origin());
|
geometry_.origin());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryCache::OnGetGeometryResponse(GetGeometryResponse response) {
|
void GeometryCache::OnGetGeometryResponse(GetGeometryResponse response) {
|
||||||
|
if (have_geometry_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
OnGeometryChanged(response ? gfx::Rect(response->x, response->y,
|
OnGeometryChanged(response ? gfx::Rect(response->x, response->y,
|
||||||
response->width, response->height)
|
response->width, response->height)
|
||||||
: gfx::Rect());
|
: gfx::Rect());
|
||||||
|
@@ -27,7 +27,7 @@ Window GetWindowForEvent(const Event& event) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
WmSync::WmSync(Connection* connection, base::OnceClosure on_synced)
|
WmSync::WmSync(Connection* connection, base::OnceClosure on_synced)
|
||||||
: WmSync(connection, std::move(on_synced), connection->synced_with_wm()) {}
|
: WmSync(connection, std::move(on_synced), connection->CanSyncWithWm()) {}
|
||||||
|
|
||||||
WmSync::WmSync(Connection* connection,
|
WmSync::WmSync(Connection* connection,
|
||||||
base::OnceClosure on_synced,
|
base::OnceClosure on_synced,
|
||||||
|
@@ -45,8 +45,10 @@
|
|||||||
#include "ui/gfx/geometry/transform.h"
|
#include "ui/gfx/geometry/transform.h"
|
||||||
#include "ui/gfx/image/image_skia_rep.h"
|
#include "ui/gfx/image/image_skia_rep.h"
|
||||||
#include "ui/gfx/x/atom_cache.h"
|
#include "ui/gfx/x/atom_cache.h"
|
||||||
|
#include "ui/gfx/x/geometry_cache.h"
|
||||||
#include "ui/gfx/x/visual_manager.h"
|
#include "ui/gfx/x/visual_manager.h"
|
||||||
#include "ui/gfx/x/window_event_manager.h"
|
#include "ui/gfx/x/window_event_manager.h"
|
||||||
|
#include "ui/gfx/x/wm_sync.h"
|
||||||
#include "ui/gfx/x/x11_path.h"
|
#include "ui/gfx/x/x11_path.h"
|
||||||
#include "ui/gfx/x/xproto.h"
|
#include "ui/gfx/x/xproto.h"
|
||||||
#include "ui/ozone/platform/x11/hit_test_x11.h"
|
#include "ui/ozone/platform/x11/hit_test_x11.h"
|
||||||
@@ -494,9 +496,9 @@ void X11Window::SetBoundsInPixels(const gfx::Rect& bounds) {
|
|||||||
AdjustSizeForDisplay(bounds.size()));
|
AdjustSizeForDisplay(bounds.size()));
|
||||||
|
|
||||||
const bool size_changed =
|
const bool size_changed =
|
||||||
bounds_in_pixels_.size() != new_bounds_in_pixels.size();
|
GetBoundsInPixels().size() != new_bounds_in_pixels.size();
|
||||||
const bool origin_changed =
|
const bool origin_changed =
|
||||||
bounds_in_pixels_.origin() != new_bounds_in_pixels.origin();
|
GetBoundsInPixels().origin() != new_bounds_in_pixels.origin();
|
||||||
|
|
||||||
// Assume that the resize will go through as requested, which should be the
|
// 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
|
// case if we're running without a window manager. If there's a window
|
||||||
@@ -537,7 +539,6 @@ void X11Window::SetBoundsInPixels(const gfx::Rect& bounds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (origin_changed || size_changed) {
|
if (origin_changed || size_changed) {
|
||||||
bounds_change_in_flight_ = true;
|
|
||||||
connection_->ConfigureWindow(req);
|
connection_->ConfigureWindow(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +547,7 @@ void X11Window::SetBoundsInPixels(const gfx::Rect& bounds) {
|
|||||||
// manager, it can modify or ignore the request, but (per ICCCM) we'll get a
|
// manager, it can modify or ignore the request, but (per ICCCM) we'll get a
|
||||||
// (possibly synthetic) ConfigureNotify about the actual size and correct
|
// (possibly synthetic) ConfigureNotify about the actual size and correct
|
||||||
// |bounds_in_pixels_| later.
|
// |bounds_in_pixels_| later.
|
||||||
bounds_in_pixels_ = new_bounds_in_pixels;
|
SetBoundsWithWmSync(new_bounds_in_pixels);
|
||||||
ResetWindowRegion();
|
ResetWindowRegion();
|
||||||
|
|
||||||
// Even if the pixel bounds didn't change this call to the delegate should
|
// Even if the pixel bounds didn't change this call to the delegate should
|
||||||
@@ -556,7 +557,8 @@ void X11Window::SetBoundsInPixels(const gfx::Rect& bounds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect X11Window::GetBoundsInPixels() const {
|
gfx::Rect X11Window::GetBoundsInPixels() const {
|
||||||
return bounds_in_pixels_;
|
return bounds_wm_sync_ || !geometry_cache_ ? last_set_bounds_px_
|
||||||
|
: geometry_cache_->GetBoundsPx();
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11Window::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) {
|
void X11Window::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) {
|
||||||
@@ -565,7 +567,7 @@ void X11Window::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect X11Window::GetBoundsInDIP() const {
|
gfx::Rect X11Window::GetBoundsInDIP() const {
|
||||||
return platform_window_delegate_->ConvertRectToDIP(bounds_in_pixels_);
|
return platform_window_delegate_->ConvertRectToDIP(GetBoundsInPixels());
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11Window::SetTitle(const std::u16string& title) {
|
void X11Window::SetTitle(const std::u16string& title) {
|
||||||
@@ -673,23 +675,11 @@ void X11Window::SetFullscreen(bool fullscreen, int64_t target_display_id) {
|
|||||||
|
|
||||||
UpdateDecorationInsets();
|
UpdateDecorationInsets();
|
||||||
|
|
||||||
// Do not go through SetBounds as long as it adjusts bounds and sets them to X
|
// Pretend the bounds changed immediately, and wait for a WM sync to use the
|
||||||
// Server. Instead, we just store the bounds and notify the client that the
|
// server's bounds.
|
||||||
// window occupies the entire screen.
|
bool origin_changed = GetBoundsInPixels().origin() != new_bounds_px.origin();
|
||||||
bool origin_changed = bounds_in_pixels_.origin() != new_bounds_px.origin();
|
SetBoundsWithWmSync(new_bounds_px);
|
||||||
bounds_in_pixels_ = new_bounds_px;
|
|
||||||
|
|
||||||
// If there is a restore and/or bounds change in flight, then set a flag to
|
|
||||||
// ignore the next one or two configure events (hopefully) coming from those
|
|
||||||
// requests. This prevents any in-flight restore requests from changing the
|
|
||||||
// bounds in a way that conflicts with the `bounds_in_pixels_` setting above.
|
|
||||||
// This is not perfect, and if there is some other in-flight bounds change for
|
|
||||||
// some reason, or if the ordering of events from the WM behaves differently,
|
|
||||||
// this will not prevent the issue. See: http://crbug.com/1227451
|
|
||||||
ignore_next_configures_ = restore_in_flight_ ? 1 : 0;
|
|
||||||
if (bounds_change_in_flight_) {
|
|
||||||
ignore_next_configures_++;
|
|
||||||
}
|
|
||||||
// This must be the final call in this function, as `this` may be deleted
|
// This must be the final call in this function, as `this` may be deleted
|
||||||
// during the observation of this event.
|
// during the observation of this event.
|
||||||
platform_window_delegate_->OnBoundsChanged({origin_changed});
|
platform_window_delegate_->OnBoundsChanged({origin_changed});
|
||||||
@@ -736,11 +726,9 @@ void X11Window::Minimize() {
|
|||||||
|
|
||||||
void X11Window::Restore() {
|
void X11Window::Restore() {
|
||||||
if (IsMinimized()) {
|
if (IsMinimized()) {
|
||||||
restore_in_flight_ = true;
|
|
||||||
SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_HIDDEN"),
|
SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_HIDDEN"),
|
||||||
x11::Atom::None);
|
x11::Atom::None);
|
||||||
} else if (IsMaximized()) {
|
} else if (IsMaximized()) {
|
||||||
restore_in_flight_ = true;
|
|
||||||
should_maximize_after_map_ = false;
|
should_maximize_after_map_ = false;
|
||||||
SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
|
SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
|
||||||
x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
|
x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
|
||||||
@@ -852,8 +840,8 @@ void X11Window::SetCursor(scoped_refptr<PlatformCursor> cursor) {
|
|||||||
void X11Window::MoveCursorTo(const gfx::Point& location_px) {
|
void X11Window::MoveCursorTo(const gfx::Point& location_px) {
|
||||||
connection_->WarpPointer(x11::WarpPointerRequest{
|
connection_->WarpPointer(x11::WarpPointerRequest{
|
||||||
.dst_window = x_root_window_,
|
.dst_window = x_root_window_,
|
||||||
.dst_x = static_cast<int16_t>(bounds_in_pixels_.x() + location_px.x()),
|
.dst_x = static_cast<int16_t>(GetBoundsInPixels().x() + location_px.x()),
|
||||||
.dst_y = static_cast<int16_t>(bounds_in_pixels_.y() + location_px.y()),
|
.dst_y = static_cast<int16_t>(GetBoundsInPixels().y() + location_px.y()),
|
||||||
});
|
});
|
||||||
// The cached cursor location is no longer valid.
|
// The cached cursor location is no longer valid.
|
||||||
X11EventSource::GetInstance()->ClearLastCursorLocation();
|
X11EventSource::GetInstance()->ClearLastCursorLocation();
|
||||||
@@ -866,7 +854,7 @@ void X11Window::ConfineCursorToBounds(const gfx::Rect& bounds) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect barrier = bounds + bounds_in_pixels_.OffsetFromOrigin();
|
gfx::Rect barrier = bounds + GetBoundsInPixels().OffsetFromOrigin();
|
||||||
|
|
||||||
auto make_barrier = [&](uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,
|
auto make_barrier = [&](uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,
|
||||||
x11::XFixes::BarrierDirections directions) {
|
x11::XFixes::BarrierDirections directions) {
|
||||||
@@ -1165,6 +1153,7 @@ void X11Window::NotifyStartupComplete(const std::string& startup_id) {
|
|||||||
event.type = net_startup_info;
|
event.type = net_startup_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry_cache_.reset();
|
||||||
connection_->DestroyWindow(window);
|
connection_->DestroyWindow(window);
|
||||||
connection_->Flush();
|
connection_->Flush();
|
||||||
}
|
}
|
||||||
@@ -1214,11 +1203,10 @@ bool X11Window::IsWmTiling() const {
|
|||||||
return ui::IsWmTiling(ui::GuessWindowManager());
|
return ui::IsWmTiling(ui::GuessWindowManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11Window::OnCompleteSwapAfterResize() {
|
void X11Window::OnCompleteSwapAfterResize(const gfx::Size& new_size) {
|
||||||
if (configure_counter_value_ && have_configure_) {
|
last_swapped_size_ = new_size;
|
||||||
connection_->sync().SetCounter(update_counter_, *configure_counter_value_);
|
if (configure_counter_value_) {
|
||||||
configure_counter_value_.reset();
|
MaybeUpdateSyncCounter();
|
||||||
have_configure_ = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1260,6 +1248,10 @@ void X11Window::SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) {
|
|||||||
x11_extension_delegate_ = delegate;
|
x11_extension_delegate_ = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool X11Window::IsWmSyncActiveForTest() {
|
||||||
|
return bounds_wm_sync_.get();
|
||||||
|
}
|
||||||
|
|
||||||
bool X11Window::HandleAsAtkEvent(const x11::KeyEvent& key_event,
|
bool X11Window::HandleAsAtkEvent(const x11::KeyEvent& key_event,
|
||||||
bool send_event,
|
bool send_event,
|
||||||
bool transient) {
|
bool transient) {
|
||||||
@@ -1414,10 +1406,6 @@ void X11Window::OnXWindowStateChanged() {
|
|||||||
new_state = PlatformWindowState::kMaximized;
|
new_state = PlatformWindowState::kMaximized;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restore_in_flight_ && !IsMaximized()) {
|
|
||||||
restore_in_flight_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fullscreen state is set syschronously at ToggleFullscreen() and must be
|
// fullscreen state is set syschronously at ToggleFullscreen() and must be
|
||||||
// kept and propagated to the client only when explicitly requested by upper
|
// kept and propagated to the client only when explicitly requested by upper
|
||||||
// layers, as it means we are in "browser fullscreen mode" (where
|
// layers, as it means we are in "browser fullscreen mode" (where
|
||||||
@@ -1445,16 +1433,8 @@ void X11Window::OnXWindowStateChanged() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restored_bounds_in_pixels_.IsEmpty()) {
|
if (!restored_bounds_in_pixels_.IsEmpty() && !IsMaximized() &&
|
||||||
if (IsMaximized()) {
|
!IsFullscreen()) {
|
||||||
// The request that we become maximized originated from a different
|
|
||||||
// process. |bounds_in_pixels_| already contains our maximized bounds. Do
|
|
||||||
// a best effort attempt to get restored bounds by setting it to our
|
|
||||||
// previously set bounds (and if we get this wrong, we aren't any worse
|
|
||||||
// off since we'd otherwise be returning our maximized bounds).
|
|
||||||
restored_bounds_in_pixels_ = previous_bounds_in_pixels_;
|
|
||||||
}
|
|
||||||
} else if (!IsMaximized() && !IsFullscreen()) {
|
|
||||||
// If we have restored bounds, but WM_STATE no longer claims to be
|
// If we have restored bounds, but WM_STATE no longer claims to be
|
||||||
// maximized or fullscreen, we should clear our restored bounds.
|
// maximized or fullscreen, we should clear our restored bounds.
|
||||||
restored_bounds_in_pixels_ = gfx::Rect();
|
restored_bounds_in_pixels_ = gfx::Rect();
|
||||||
@@ -1719,7 +1699,7 @@ scoped_refptr<X11Cursor> X11Window::GetLastCursor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gfx::Size X11Window::GetSize() {
|
gfx::Size X11Window::GetSize() {
|
||||||
return bounds_in_pixels_.size();
|
return GetBoundsInPixels().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11Window::QuitDragLoop() {
|
void X11Window::QuitDragLoop() {
|
||||||
@@ -1846,12 +1826,12 @@ void X11Window::CreateXWindow(const PlatformWindowInitProperties& properties) {
|
|||||||
// same as the parent depth.
|
// same as the parent depth.
|
||||||
req.border_pixel = 0;
|
req.border_pixel = 0;
|
||||||
|
|
||||||
bounds_in_pixels_ = SanitizeBounds(bounds);
|
last_set_bounds_px_ = SanitizeBounds(bounds);
|
||||||
req.parent = x_root_window_;
|
req.parent = x_root_window_;
|
||||||
req.x = bounds_in_pixels_.x();
|
req.x = last_set_bounds_px_.x();
|
||||||
req.y = bounds_in_pixels_.y();
|
req.y = last_set_bounds_px_.y();
|
||||||
req.width = bounds_in_pixels_.width();
|
req.width = last_set_bounds_px_.width();
|
||||||
req.height = bounds_in_pixels_.height();
|
req.height = last_set_bounds_px_.height();
|
||||||
req.depth = depth;
|
req.depth = depth;
|
||||||
req.c_class = x11::WindowClass::InputOutput;
|
req.c_class = x11::WindowClass::InputOutput;
|
||||||
req.visual = visual_id;
|
req.visual = visual_id;
|
||||||
@@ -1859,6 +1839,10 @@ void X11Window::CreateXWindow(const PlatformWindowInitProperties& properties) {
|
|||||||
xwindow_ = connection_->GenerateId<x11::Window>();
|
xwindow_ = connection_->GenerateId<x11::Window>();
|
||||||
req.wid = xwindow_;
|
req.wid = xwindow_;
|
||||||
connection_->CreateWindow(req);
|
connection_->CreateWindow(req);
|
||||||
|
// Unretained is safe since we own `geometry_cache_`.
|
||||||
|
geometry_cache_ = std::make_unique<x11::GeometryCache>(
|
||||||
|
&*connection_, xwindow_,
|
||||||
|
base::BindRepeating(&X11Window::OnBoundsChanged, base::Unretained(this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11Window::CloseXWindow() {
|
void X11Window::CloseXWindow() {
|
||||||
@@ -1875,6 +1859,7 @@ void X11Window::CloseXWindow() {
|
|||||||
security_surfaces.end());
|
security_surfaces.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry_cache_.reset();
|
||||||
connection_->DestroyWindow({xwindow_});
|
connection_->DestroyWindow({xwindow_});
|
||||||
xwindow_ = x11::Window::None;
|
xwindow_ = x11::Window::None;
|
||||||
|
|
||||||
@@ -1891,8 +1876,8 @@ void X11Window::Map(bool inactive) {
|
|||||||
memset(&size_hints, 0, sizeof(size_hints));
|
memset(&size_hints, 0, sizeof(size_hints));
|
||||||
connection_->GetWmNormalHints(xwindow_, &size_hints);
|
connection_->GetWmNormalHints(xwindow_, &size_hints);
|
||||||
size_hints.flags |= x11::SIZE_HINT_P_POSITION;
|
size_hints.flags |= x11::SIZE_HINT_P_POSITION;
|
||||||
size_hints.x = bounds_in_pixels_.x();
|
size_hints.x = GetBoundsInPixels().x();
|
||||||
size_hints.y = bounds_in_pixels_.y();
|
size_hints.y = GetBoundsInPixels().y();
|
||||||
// Set STATIC_GRAVITY so that the window position is not affected by the
|
// Set STATIC_GRAVITY so that the window position is not affected by the
|
||||||
// frame width when running with window manager.
|
// frame width when running with window manager.
|
||||||
size_hints.flags |= x11::SIZE_HINT_P_WIN_GRAVITY;
|
size_hints.flags |= x11::SIZE_HINT_P_WIN_GRAVITY;
|
||||||
@@ -1964,7 +1949,7 @@ bool X11Window::IsFullscreen() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect X11Window::GetOuterBounds() const {
|
gfx::Rect X11Window::GetOuterBounds() const {
|
||||||
gfx::Rect outer_bounds(bounds_in_pixels_);
|
gfx::Rect outer_bounds(GetBoundsInPixels());
|
||||||
outer_bounds.Inset(-native_window_frame_borders_in_pixels_);
|
outer_bounds.Inset(-native_window_frame_borders_in_pixels_);
|
||||||
return outer_bounds;
|
return outer_bounds;
|
||||||
}
|
}
|
||||||
@@ -2272,23 +2257,6 @@ void X11Window::HandleEvent(const x11::Event& xev) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|
||||||
// when getting pointer events (EnterNotify, LeaveNotify, ButtonPress,
|
|
||||||
// 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 = 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) {
|
|
||||||
bounds_in_pixels_.set_origin(window_origin);
|
|
||||||
NotifyBoundsChanged(/*origin changed=*/true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// May want to factor CheckXEventForConsistency(xev); into a common location
|
// May want to factor CheckXEventForConsistency(xev); into a common location
|
||||||
// since it is called here.
|
// since it is called here.
|
||||||
if (auto* crossing = xev.As<x11::CrossingEvent>()) {
|
if (auto* crossing = xev.As<x11::CrossingEvent>()) {
|
||||||
@@ -2303,7 +2271,7 @@ void X11Window::HandleEvent(const x11::Event& xev) {
|
|||||||
OnFocusEvent(focus->opcode == x11::FocusEvent::In, focus->mode,
|
OnFocusEvent(focus->opcode == x11::FocusEvent::In, focus->mode,
|
||||||
focus->detail);
|
focus->detail);
|
||||||
} else if (auto* configure = xev.As<x11::ConfigureNotifyEvent>()) {
|
} else if (auto* configure = xev.As<x11::ConfigureNotifyEvent>()) {
|
||||||
OnConfigureEvent(*configure, xev.send_event());
|
OnConfigureEvent(*configure);
|
||||||
} else if (auto* crossing_input = xev.As<x11::Input::CrossingEvent>()) {
|
} else if (auto* crossing_input = xev.As<x11::Input::CrossingEvent>()) {
|
||||||
TouchFactory* factory = TouchFactory::GetInstance();
|
TouchFactory* factory = TouchFactory::GetInstance();
|
||||||
if (factory->ShouldProcessCrossingEvent(*crossing_input)) {
|
if (factory->ShouldProcessCrossingEvent(*crossing_input)) {
|
||||||
@@ -2347,7 +2315,6 @@ void X11Window::HandleEvent(const x11::Event& xev) {
|
|||||||
x11::EventMask::SubstructureRedirect);
|
x11::EventMask::SubstructureRedirect);
|
||||||
} else if (protocol == x11::GetAtom("_NET_WM_SYNC_REQUEST")) {
|
} else if (protocol == x11::GetAtom("_NET_WM_SYNC_REQUEST")) {
|
||||||
configure_counter_value_.reset();
|
configure_counter_value_.reset();
|
||||||
have_configure_ = false;
|
|
||||||
const int32_t hi = static_cast<int32_t>(client->data.data32[3]);
|
const int32_t hi = static_cast<int32_t>(client->data.data32[3]);
|
||||||
const uint32_t lo = client->data.data32[2];
|
const uint32_t lo = client->data.data32[2];
|
||||||
// The spec says the WM should never send a counter value of 0, so
|
// The spec says the WM should never send a counter value of 0, so
|
||||||
@@ -2405,57 +2372,12 @@ void X11Window::OnWindowMapped() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11Window::OnConfigureEvent(const x11::ConfigureNotifyEvent& configure,
|
void X11Window::OnConfigureEvent(const x11::ConfigureNotifyEvent& configure) {
|
||||||
bool send_event) {
|
|
||||||
DCHECK_EQ(xwindow_, configure.window);
|
DCHECK_EQ(xwindow_, configure.window);
|
||||||
|
|
||||||
if (configure_counter_value_) {
|
if (configure_counter_value_ && !last_configure_size_) {
|
||||||
have_configure_ = true;
|
last_configure_size_ = gfx::Size(configure.width, configure.height);
|
||||||
}
|
MaybeUpdateSyncCounter();
|
||||||
|
|
||||||
// During a Restore() -> ToggleFullscreen() or Restore() -> SetBounds() ->
|
|
||||||
// ToggleFullscreen() sequence, ignore the configure events from the Restore
|
|
||||||
// and SetBounds requests, if we're waiting on fullscreen. After
|
|
||||||
// OnXWindowStateChanged unsets this flag, there will be a configuration event
|
|
||||||
// that will set the bounds to the final fullscreen bounds.
|
|
||||||
if (ignore_next_configures_ > 0) {
|
|
||||||
ignore_next_configures_--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: This OnConfigureEvent might not necessarily correspond to a previous
|
|
||||||
// SetBounds request. Due to limitations in X11 there isn't a way to
|
|
||||||
// match events to its original request. For now, we assume that the next
|
|
||||||
// OnConfigureEvent event after a SetBounds (ConfigureWindow) request is from
|
|
||||||
// that request. This would break in some scenarios (for example calling
|
|
||||||
// SetBounds more than once quickly). See crbug.com/1227451.
|
|
||||||
bounds_change_in_flight_ = false;
|
|
||||||
|
|
||||||
// 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 = configure.x;
|
|
||||||
int translated_y_in_pixels = configure.y;
|
|
||||||
if (!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 new_bounds_px(translated_x_in_pixels, translated_y_in_pixels,
|
|
||||||
configure.width, configure.height);
|
|
||||||
const bool size_changed = bounds_in_pixels_.size() != new_bounds_px.size();
|
|
||||||
const bool origin_changed =
|
|
||||||
bounds_in_pixels_.origin() != new_bounds_px.origin();
|
|
||||||
previous_bounds_in_pixels_ = bounds_in_pixels_;
|
|
||||||
bounds_in_pixels_ = new_bounds_px;
|
|
||||||
|
|
||||||
if (size_changed) {
|
|
||||||
DispatchResize(origin_changed);
|
|
||||||
} else if (origin_changed) {
|
|
||||||
NotifyBoundsChanged(/*origin changed=*/true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2537,6 +2459,7 @@ void X11Window::OnFrameExtentsUpdated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void X11Window::DispatchResize(bool origin_changed) {
|
void X11Window::DispatchResize(bool origin_changed) {
|
||||||
|
last_swapped_size_.reset();
|
||||||
if (configure_counter_value_) {
|
if (configure_counter_value_) {
|
||||||
// WM handles resize throttling. No need to delay resize events.
|
// WM handles resize throttling. No need to delay resize events.
|
||||||
DelayedResize(origin_changed);
|
DelayedResize(origin_changed);
|
||||||
@@ -2656,4 +2579,39 @@ bool X11Window::InitializeAsStatusIcon() {
|
|||||||
return !future.Sync().error;
|
return !future.Sync().error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void X11Window::SetBoundsWithWmSync(const gfx::Rect& bounds_px) {
|
||||||
|
last_set_bounds_px_ = bounds_px;
|
||||||
|
// Unretained is safe since we own `bounds_wm_sync_`.
|
||||||
|
bounds_wm_sync_ = std::make_unique<x11::WmSync>(
|
||||||
|
&*connection_,
|
||||||
|
base::BindOnce(&X11Window::OnWmSynced, base::Unretained(this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::OnWmSynced() {
|
||||||
|
bounds_wm_sync_.reset();
|
||||||
|
OnBoundsChanged(last_set_bounds_px_, GetBoundsInPixels());
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::OnBoundsChanged(const std::optional<gfx::Rect>& old_bounds_px,
|
||||||
|
const gfx::Rect& new_bounds_px) {
|
||||||
|
const bool size_changed = !old_bounds_px.has_value() ||
|
||||||
|
old_bounds_px->size() != new_bounds_px.size();
|
||||||
|
const bool origin_changed = !old_bounds_px.has_value() ||
|
||||||
|
old_bounds_px->origin() != new_bounds_px.origin();
|
||||||
|
|
||||||
|
if (size_changed) {
|
||||||
|
DispatchResize(origin_changed);
|
||||||
|
} else if (origin_changed) {
|
||||||
|
NotifyBoundsChanged(/*origin changed=*/true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::MaybeUpdateSyncCounter() {
|
||||||
|
if (last_configure_size_ == last_swapped_size_) {
|
||||||
|
connection_->sync().SetCounter(update_counter_, *configure_counter_value_);
|
||||||
|
configure_counter_value_.reset();
|
||||||
|
last_configure_size_.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
@@ -36,6 +36,11 @@
|
|||||||
|
|
||||||
class SkPath;
|
class SkPath;
|
||||||
|
|
||||||
|
namespace x11 {
|
||||||
|
class GeometryCache;
|
||||||
|
class WmSync;
|
||||||
|
} // namespace x11
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
class PlatformWindowDelegate;
|
class PlatformWindowDelegate;
|
||||||
@@ -134,12 +139,13 @@ class X11Window : public PlatformWindow,
|
|||||||
// X11Extension:
|
// X11Extension:
|
||||||
bool IsSyncExtensionAvailable() const override;
|
bool IsSyncExtensionAvailable() const override;
|
||||||
bool IsWmTiling() const override;
|
bool IsWmTiling() const override;
|
||||||
void OnCompleteSwapAfterResize() override;
|
void OnCompleteSwapAfterResize(const gfx::Size& new_size) override;
|
||||||
gfx::Rect GetXRootWindowOuterBounds() const override;
|
gfx::Rect GetXRootWindowOuterBounds() const override;
|
||||||
void LowerXWindow() override;
|
void LowerXWindow() override;
|
||||||
void SetOverrideRedirect(bool override_redirect) override;
|
void SetOverrideRedirect(bool override_redirect) override;
|
||||||
bool CanResetOverrideRedirect() const override;
|
bool CanResetOverrideRedirect() const override;
|
||||||
void SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) override;
|
void SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) override;
|
||||||
|
bool IsWmSyncActiveForTest() override;
|
||||||
|
|
||||||
// x11::EventObserver:
|
// x11::EventObserver:
|
||||||
void OnEvent(const x11::Event& event) override;
|
void OnEvent(const x11::Event& event) override;
|
||||||
@@ -283,8 +289,7 @@ class X11Window : public PlatformWindow,
|
|||||||
// Called when |xwindow_|'s _NET_FRAME_EXTENTS property is updated.
|
// Called when |xwindow_|'s _NET_FRAME_EXTENTS property is updated.
|
||||||
void OnFrameExtentsUpdated();
|
void OnFrameExtentsUpdated();
|
||||||
|
|
||||||
void OnConfigureEvent(const x11::ConfigureNotifyEvent& event,
|
void OnConfigureEvent(const x11::ConfigureNotifyEvent& event);
|
||||||
bool send_event);
|
|
||||||
|
|
||||||
void OnWorkspaceUpdated();
|
void OnWorkspaceUpdated();
|
||||||
|
|
||||||
@@ -323,6 +328,15 @@ class X11Window : public PlatformWindow,
|
|||||||
// Initializes as a status icon window.
|
// Initializes as a status icon window.
|
||||||
bool InitializeAsStatusIcon();
|
bool InitializeAsStatusIcon();
|
||||||
|
|
||||||
|
void SetBoundsWithWmSync(const gfx::Rect& bounds_px);
|
||||||
|
|
||||||
|
void OnWmSynced();
|
||||||
|
|
||||||
|
void OnBoundsChanged(const std::optional<gfx::Rect>& old_bounds_px,
|
||||||
|
const gfx::Rect& new_bounds_px);
|
||||||
|
|
||||||
|
void MaybeUpdateSyncCounter();
|
||||||
|
|
||||||
// Stores current state of this window.
|
// Stores current state of this window.
|
||||||
PlatformWindowState state_ = PlatformWindowState::kUnknown;
|
PlatformWindowState state_ = PlatformWindowState::kUnknown;
|
||||||
|
|
||||||
@@ -393,8 +407,12 @@ class X11Window : public PlatformWindow,
|
|||||||
// Whether the window is mapped with respect to the X server.
|
// Whether the window is mapped with respect to the X server.
|
||||||
bool window_mapped_in_server_ = false;
|
bool window_mapped_in_server_ = false;
|
||||||
|
|
||||||
// The bounds of |xwindow_|.
|
// The bounds of `xwindow_`. If `bounds_wm_sync_` is active, then
|
||||||
gfx::Rect bounds_in_pixels_;
|
// `last_set_bounds_px_` should be treated as the current bounds. Otherwise,
|
||||||
|
// the bounds from `geometry_cache_` should be used.
|
||||||
|
gfx::Rect last_set_bounds_px_;
|
||||||
|
std::unique_ptr<x11::WmSync> bounds_wm_sync_;
|
||||||
|
std::unique_ptr<x11::GeometryCache> geometry_cache_;
|
||||||
|
|
||||||
x11::VisualId visual_id_{};
|
x11::VisualId visual_id_{};
|
||||||
|
|
||||||
@@ -450,15 +468,6 @@ class X11Window : public PlatformWindow,
|
|||||||
bool had_pointer_grab_ = false;
|
bool had_pointer_grab_ = false;
|
||||||
bool had_window_focus_ = false;
|
bool had_window_focus_ = false;
|
||||||
|
|
||||||
// Whenever the bounds are set, we keep the previous set of bounds around so
|
|
||||||
// we can have a better chance of getting the real
|
|
||||||
// |restored_bounds_in_pixels_|. Window managers tend to send a Configure
|
|
||||||
// message with the maximized bounds, and then set the window maximized
|
|
||||||
// property. (We don't rely on this for when we request that the window be
|
|
||||||
// maximized, only when we detect that some other process has requested that
|
|
||||||
// we become the maximized window.)
|
|
||||||
gfx::Rect previous_bounds_in_pixels_;
|
|
||||||
|
|
||||||
// True if a Maximize() call should be done after mapping the window.
|
// True if a Maximize() call should be done after mapping the window.
|
||||||
bool should_maximize_after_map_ = false;
|
bool should_maximize_after_map_ = false;
|
||||||
|
|
||||||
@@ -490,22 +499,10 @@ class X11Window : public PlatformWindow,
|
|||||||
gfx::Insets native_window_frame_borders_in_pixels_;
|
gfx::Insets native_window_frame_borders_in_pixels_;
|
||||||
|
|
||||||
// Used for synchronizing between `xwindow_` and the WM during resizing.
|
// Used for synchronizing between `xwindow_` and the WM during resizing.
|
||||||
std::optional<x11::Sync::Int64> configure_counter_value_;
|
|
||||||
bool have_configure_ = false;
|
|
||||||
x11::Sync::Counter update_counter_{};
|
x11::Sync::Counter update_counter_{};
|
||||||
|
std::optional<x11::Sync::Int64> configure_counter_value_;
|
||||||
// Used for ignoring bounds changes during the fullscreening process. For
|
std::optional<gfx::Size> last_configure_size_;
|
||||||
// cross-display fullscreening, there is a Restore() (called by BrowserView)
|
std::optional<gfx::Size> last_swapped_size_;
|
||||||
// that may cause configuration bounds updates that make this window appear to
|
|
||||||
// temporarily be on a different screen than its destination screen. This
|
|
||||||
// restore only happens if the window is maximized. The integer represents how
|
|
||||||
// many events to ignore.
|
|
||||||
int ignore_next_configures_ = 0;
|
|
||||||
// True between Restore() and the next OnXWindowStateChanged().
|
|
||||||
bool restore_in_flight_ = false;
|
|
||||||
// True between SetBoundsInPixels (when the bounds actually change) and the
|
|
||||||
// next OnConfigureEvent.
|
|
||||||
bool bounds_change_in_flight_ = false;
|
|
||||||
|
|
||||||
base::CancelableOnceClosure delayed_resize_task_;
|
base::CancelableOnceClosure delayed_resize_task_;
|
||||||
|
|
||||||
|
@@ -27,7 +27,7 @@ class COMPONENT_EXPORT(PLATFORM_WINDOW) X11Extension {
|
|||||||
virtual bool IsWmTiling() const = 0;
|
virtual bool IsWmTiling() const = 0;
|
||||||
|
|
||||||
// Handles CompleteSwapAfterResize event coming from the compositor observer.
|
// Handles CompleteSwapAfterResize event coming from the compositor observer.
|
||||||
virtual void OnCompleteSwapAfterResize() = 0;
|
virtual void OnCompleteSwapAfterResize(const gfx::Size& new_size) = 0;
|
||||||
|
|
||||||
// Returns the current bounds in terms of the X11 Root Window including the
|
// Returns the current bounds in terms of the X11 Root Window including the
|
||||||
// borders provided by the window manager (if any).
|
// borders provided by the window manager (if any).
|
||||||
@@ -46,6 +46,9 @@ class COMPONENT_EXPORT(PLATFORM_WINDOW) X11Extension {
|
|||||||
|
|
||||||
virtual void SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) = 0;
|
virtual void SetX11ExtensionDelegate(X11ExtensionDelegate* delegate) = 0;
|
||||||
|
|
||||||
|
// Indicates whether a WmSync is pending. Should only be used for testing.
|
||||||
|
virtual bool IsWmSyncActiveForTest() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~X11Extension();
|
virtual ~X11Extension();
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#include "ui/aura/window_tree_host_platform.h"
|
#include "ui/aura/window_tree_host_platform.h"
|
||||||
#include "ui/ozone/public/ozone_platform.h"
|
#include "ui/ozone/public/ozone_platform.h"
|
||||||
#include "ui/platform_window/extensions/wayland_extension.h"
|
#include "ui/platform_window/extensions/wayland_extension.h"
|
||||||
|
#include "ui/platform_window/extensions/x11_extension.h"
|
||||||
|
|
||||||
#endif // BUILDFLAG(IS_LINUX)
|
#endif // BUILDFLAG(IS_LINUX)
|
||||||
|
|
||||||
@@ -48,11 +49,11 @@ AsyncWidgetRequestWaiter::~AsyncWidgetRequestWaiter() {
|
|||||||
void AsyncWidgetRequestWaiter::Wait() {
|
void AsyncWidgetRequestWaiter::Wait() {
|
||||||
CHECK(!waited_) << "`Wait` may only be called once.";
|
CHECK(!waited_) << "`Wait` may only be called once.";
|
||||||
#if BUILDFLAG(IS_LINUX)
|
#if BUILDFLAG(IS_LINUX)
|
||||||
|
auto* host = aura::WindowTreeHostPlatform::GetHostForWindow(
|
||||||
|
widget_->GetNativeWindow());
|
||||||
if (ui::OzonePlatform::GetPlatformNameForTest() == "wayland") {
|
if (ui::OzonePlatform::GetPlatformNameForTest() == "wayland") {
|
||||||
// Wait for a Wayland roundtrip to ensure all side effects have been
|
// Wait for a Wayland roundtrip to ensure all side effects have been
|
||||||
// processed.
|
// processed.
|
||||||
auto* host = aura::WindowTreeHostPlatform::GetHostForWindow(
|
|
||||||
widget_->GetNativeWindow());
|
|
||||||
auto* wayland_extension = ui::GetWaylandExtension(*host->platform_window());
|
auto* wayland_extension = ui::GetWaylandExtension(*host->platform_window());
|
||||||
wayland_extension->RoundTripQueue();
|
wayland_extension->RoundTripQueue();
|
||||||
|
|
||||||
@@ -72,6 +73,15 @@ void AsyncWidgetRequestWaiter::Wait() {
|
|||||||
// to be processed on the server side.
|
// to be processed on the server side.
|
||||||
wayland_extension->RoundTripQueue();
|
wayland_extension->RoundTripQueue();
|
||||||
wayland_extension->SetLatchImmediately(true);
|
wayland_extension->SetLatchImmediately(true);
|
||||||
|
} else if (ui::OzonePlatform::GetPlatformNameForTest() == "x11") {
|
||||||
|
// Setting the window bounds on X11 is asynchronous, so the platform window
|
||||||
|
// pretends the bounds change completed successfully until it can sync with
|
||||||
|
// the WM. This may cause inconsistent state with respect to other caches
|
||||||
|
// such as x11::WindowCache. Wait for the WM sync to complete to ensure
|
||||||
|
// consistency.
|
||||||
|
auto* x11_extension = ui::GetX11Extension(*host->platform_window());
|
||||||
|
CHECK(base::test::RunUntil(
|
||||||
|
[&]() { return !x11_extension->IsWmSyncActiveForTest(); }));
|
||||||
} else {
|
} else {
|
||||||
NOTIMPLEMENTED_LOG_ONCE();
|
NOTIMPLEMENTED_LOG_ONCE();
|
||||||
}
|
}
|
||||||
|
@@ -348,7 +348,7 @@ DesktopWindowTreeHostLinux::GetKeyboardLayoutMap() {
|
|||||||
void DesktopWindowTreeHostLinux::OnCompleteSwapWithNewSize(
|
void DesktopWindowTreeHostLinux::OnCompleteSwapWithNewSize(
|
||||||
const gfx::Size& size) {
|
const gfx::Size& size) {
|
||||||
if (GetX11Extension()) {
|
if (GetX11Extension()) {
|
||||||
GetX11Extension()->OnCompleteSwapAfterResize();
|
GetX11Extension()->OnCompleteSwapAfterResize(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user