#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;
}
}
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(),
.x = -10000,
.y = -10000,
.width = 10,
.height = 10,
.event_mask = event_mask,
});
window_events_ = connection_->ScopedSelectEvent(window_, event_mask);
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();
}
}
void WmSync::OnGetInputFocusResponse(GetInputFocusResponse response) {
Cleanup();
std::move(on_synced_).Run();
}
void WmSync::Cleanup() {
if (window_ == Window::None) {
return;
}
scoped_observation_.Reset();
window_events_.Reset();
connection_->DestroyWindow(window_);
window_ = Window::None;
}
}