1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/x/wm_sync.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/event.h"
namespace x11 {
namespace {
Window GetWindowForEvent(const Event& event) {
if (auto* property = event.As<PropertyNotifyEvent>()) {
return property->window;
}
if (auto* reparent = event.As<ReparentNotifyEvent>()) {
return reparent->window;
}
if (auto* configure = event.As<ConfigureNotifyEvent>()) {
return configure->window;
}
return Window::None;
}
} // namespace
WmSync::WmSync(Connection* connection, base::OnceClosure on_synced)
: WmSync(connection, std::move(on_synced), connection->CanSyncWithWm()) {}
WmSync::WmSync(Connection* connection,
base::OnceClosure on_synced,
bool sync_with_wm)
: connection_(connection), on_synced_(std::move(on_synced)) {
if (!sync_with_wm) {
connection_->GetInputFocus().OnResponse(base::BindOnce(
&WmSync::OnGetInputFocusResponse, weak_ptr_factory_.GetWeakPtr()));
connection_->Flush();
return;
}
constexpr EventMask event_mask =
EventMask::StructureNotify | EventMask::PropertyChange;
scoped_observation_.Observe(connection_);
window_ = connection_->GenerateId<Window>();
connection_->CreateWindow({
.wid = window_,
.parent = connection_->default_root(),
// The window is never mapped, so the position doesn't matter. However,
// it's important that the following ConfigureWindow request has different
// coordinates.
.x = -10000,
.y = -10000,
.width = 10,
.height = 10,
.event_mask = event_mask,
});
window_events_ = connection_->ScopedSelectEvent(window_, event_mask);
// Send a ConfigureWindow request. If a WM is running, the request will be
// routed to the WM for it to service (or if a WM is not running, the X11
// server will handle it). Some time later, we'll observe the ConfigureNotify
// event that signals the sync is complete.
connection_->ConfigureWindow({
.window = window_,
.x = -200,
.y = -200,
.width = 20,
.height = 20,
});
connection_->Flush();
}
WmSync::~WmSync() {
Cleanup();
}
void WmSync::OnEvent(const Event& xevent) {
if (window_ != Window::None && GetWindowForEvent(xevent) == window_) {
Cleanup();
std::move(on_synced_).Run();
// `this` may be deleted.
}
}
void WmSync::OnGetInputFocusResponse(GetInputFocusResponse response) {
Cleanup();
std::move(on_synced_).Run();
// `this` may be deleted.
}
void WmSync::Cleanup() {
if (window_ == Window::None) {
return;
}
scoped_observation_.Reset();
window_events_.Reset();
connection_->DestroyWindow(window_);
window_ = Window::None;
}
} // namespace x11
|