diff options
author | Yuqian Yang <crupest@crupest.life> | 2025-09-22 14:58:02 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2025-09-22 16:39:33 +0800 |
commit | 444e628d22db67742181ae14ae2ed0a9c2b6cd67 (patch) | |
tree | fa2f6249ba90d1e7e618e59c7eb3cdf00fbe9971 /src/platform/gui/xcb | |
parent | 8bde78e1a008ba5ba95ea54ff03717baf53d4170 (diff) | |
download | cru-444e628d22db67742181ae14ae2ed0a9c2b6cd67.tar.gz cru-444e628d22db67742181ae14ae2ed0a9c2b6cd67.tar.bz2 cru-444e628d22db67742181ae14ae2ed0a9c2b6cd67.zip |
Impl window rect of xcb window.
Diffstat (limited to 'src/platform/gui/xcb')
-rw-r--r-- | src/platform/gui/xcb/Window.cpp | 89 |
1 files changed, 81 insertions, 8 deletions
diff --git a/src/platform/gui/xcb/Window.cpp b/src/platform/gui/xcb/Window.cpp index 1dbef489..9f2448d1 100644 --- a/src/platform/gui/xcb/Window.cpp +++ b/src/platform/gui/xcb/Window.cpp @@ -1,6 +1,7 @@ #include "cru/platform/gui/xcb/Window.h" #include "cru/base/Base.h" #include "cru/platform/Check.h" +#include "cru/platform/GraphicsBase.h" #include "cru/platform/graphics/Painter.h" #include "cru/platform/graphics/cairo/CairoPainter.h" #include "cru/platform/gui/Base.h" @@ -188,12 +189,15 @@ Rect XcbWindow::GetClientRect() { if (!xcb_window_) { return Rect{}; } - auto cookie = - xcb_get_geometry(application_->GetXcbConnection(), *xcb_window_); + + auto window = *xcb_window_; + + auto cookie = xcb_get_geometry(application_->GetXcbConnection(), window); auto reply = xcb_get_geometry_reply(application_->GetXcbConnection(), cookie, nullptr); - return Rect(reply->x + reply->border_width, reply->y + reply->border_width, - reply->width, reply->height); + auto position = GetXcbWindowPosition(window); + + return Rect(position.x, position.y, reply->width, reply->height); } void XcbWindow::SetClientRect(const Rect &rect) { @@ -201,6 +205,32 @@ void XcbWindow::SetClientRect(const Rect &rect) { DoSetClientRect(*xcb_window_, rect); } +Rect XcbWindow::GetWindowRect() { + if (!xcb_window_) return {}; + + auto client_rect = GetClientRect(); + auto frame_properties = Get_NET_FRAME_EXTENTS(*xcb_window_); + + if (frame_properties.has_value()) { + return client_rect.Expand(*frame_properties); + } + + return client_rect; +} + +void XcbWindow::SetWindowRect(const Rect &rect) { + if (!xcb_window_) return; + + auto real_rect = rect; + auto frame_properties = Get_NET_FRAME_EXTENTS(*xcb_window_); + + if (frame_properties.has_value()) { + real_rect = real_rect.Shrink(*frame_properties, true); + } + + SetClientRect(real_rect); +} + std::unique_ptr<graphics::IPainter> XcbWindow::BeginPaint() { assert(cairo_surface_); @@ -518,10 +548,16 @@ void XcbWindow::DoSetTitle(xcb_window_t window) { } void XcbWindow::DoSetClientRect(xcb_window_t window, const Rect &rect) { - std::uint32_t values[4]{static_cast<std::uint32_t>(rect.left), - static_cast<std::uint32_t>(rect.top), - static_cast<std::uint32_t>(rect.width), - static_cast<std::uint32_t>(rect.height)}; + auto tree_cookie = xcb_query_tree(application_->GetXcbConnection(), window); + auto tree_reply = xcb_query_tree_reply(application_->GetXcbConnection(), + tree_cookie, nullptr); + auto parent_position = GetXcbWindowPosition(tree_reply->parent); + + std::uint32_t values[4]{ + static_cast<std::uint32_t>(rect.left - parent_position.x), + static_cast<std::uint32_t>(rect.top - parent_position.y), + static_cast<std::uint32_t>(rect.width), + static_cast<std::uint32_t>(rect.height)}; xcb_configure_window(application_->GetXcbConnection(), window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, @@ -544,4 +580,41 @@ void *XcbWindow::XcbGetProperty(xcb_window_t window, xcb_atom_t property, } return xcb_get_property_value(reply); } + +std::optional<Thickness> XcbWindow::Get_NET_FRAME_EXTENTS(xcb_window_t window) { + auto frame_properties = static_cast<std::uint32_t *>( + XcbGetProperty(window, application_->GetXcbAtom_NET_FRAME_EXTENTS(), + XCB_ATOM_CARDINAL, 0, 4)); + + if (frame_properties == nullptr) { + return std::nullopt; + } + + return Thickness(frame_properties[0], frame_properties[2], + frame_properties[1], frame_properties[3]); +} + +Point XcbWindow::GetXcbWindowPosition(xcb_window_t window) { + Point result; + + while (true) { + auto cookie = xcb_get_geometry(application_->GetXcbConnection(), window); + auto reply = xcb_get_geometry_reply(application_->GetXcbConnection(), + cookie, nullptr); + result.x += reply->x; + result.y += reply->y; + + auto tree_cookie = xcb_query_tree(application_->GetXcbConnection(), window); + auto tree_reply = xcb_query_tree_reply(application_->GetXcbConnection(), + tree_cookie, nullptr); + window = tree_reply->parent; + // TODO: Multi-screen offset? + if (tree_reply->root == window || window == XCB_WINDOW_NONE) { + break; + } + } + + return result; +} + } // namespace cru::platform::gui::xcb |