#ifndef UI_GFX_X_WINDOW_CACHE_H_
#define UI_GFX_X_WINDOW_CACHE_H_
#include <memory>
#include <optional>
#include <unordered_map>
#include <vector>
#include "base/component_export.h"
#include "base/containers/circular_deque.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/future.h"
#include "ui/gfx/x/shape.h"
#include "ui/gfx/x/window_event_manager.h"
#include "ui/gfx/x/xproto.h"
namespace x11 {
COMPONENT_EXPORT(X11)
Window GetWindowAtPoint(const gfx::Point& point_px,
const base::flat_set<Window>* ignore = nullptr);
class Connection;
class ScopedShapeEventSelector {
public:
ScopedShapeEventSelector(Connection* connection, Window window);
~ScopedShapeEventSelector();
private:
const raw_ptr<Connection> connection_;
const Window window_;
};
class COMPONENT_EXPORT(X11) WindowCache : public EventObserver {
public:
struct WindowInfo {
WindowInfo();
~WindowInfo();
Window parent = Window::None;
bool mapped = false;
bool has_wm_name = false;
gfx::Insets gtk_frame_extents_px;
int16_t x_px = 0;
int16_t y_px = 0;
uint16_t width_px = 0;
uint16_t height_px = 0;
uint16_t border_width_px = 0;
std::vector<Window> children;
std::optional<std::vector<Rectangle>> bounding_rects_px;
std::optional<std::vector<Rectangle>> input_rects_px;
ScopedEventSelector events;
std::unique_ptr<ScopedShapeEventSelector> shape_events;
};
static WindowCache* instance() { return instance_; }
WindowCache(Connection* connection, Window root);
WindowCache(const WindowCache&) = delete;
WindowCache& operator=(const WindowCache&) = delete;
~WindowCache() override;
Window GetWindowAtPoint(gfx::Point point_px,
Window window,
const base::flat_set<Window>* ignore = nullptr);
void WaitUntilReady();
void BeginDestroyTimer(std::unique_ptr<WindowCache> self);
void SyncForTest();
const std::unordered_map<Window, WindowInfo>& windows() const {
return windows_;
}
private:
template <typename Future, typename Callback, typename... Args>
void AddRequest(Future&& future, Callback&& callback, Args&&... args) {
future.OnResponse(base::BindOnce(callback, weak_factory_.GetWeakPtr(),
std::forward<Args>(args)...));
pending_requests_.push_back(std::move(future));
}
void OnEvent(const Event& event) override;
void AddWindow(Window window, Window parent);
WindowInfo* GetInfo(Window window);
std::vector<Window>* GetChildren(Window window);
void GetProperty(Window window, Atom property, uint32_t length);
WindowInfo* OnResponse(Window window, bool has_reply);
void OnGetWindowAttributesResponse(Window window,
GetWindowAttributesResponse response);
void OnGetGeometryResponse(Window window, GetGeometryResponse response);
void OnQueryTreeResponse(Window window, QueryTreeResponse response);
void OnGetPropertyResponse(Window window,
Atom atom,
GetPropertyResponse response);
void OnGetRectanglesResponse(Window window,
Shape::Sk kind,
Shape::GetRectanglesResponse response);
void OnDestroyTimerExpired(std::unique_ptr<WindowCache> self);
static WindowCache* instance_;
const raw_ptr<Connection> connection_;
const Window root_;
const Atom gtk_frame_extents_;
ScopedEventSelector root_events_;
std::unordered_map<Window, WindowInfo> windows_;
base::circular_deque<FutureBase> pending_requests_;
std::optional<uint32_t> last_processed_event_;
bool delete_when_destroy_timer_fires_ = false;
base::WeakPtrFactory<WindowCache> weak_factory_{this};
};
}
#endif