utils/xcbutils: Use window geometry in device pixels

If the logical geometry changes, the X11Window still needs to verify
whether the currently applied native geometry differs from it. In order
to do that, the X11Window needs to map the logical geometry to the device
pixels. Given that X11Window already maps the logical pixels to the
device pixels, the Xcb::Window doesn't need to map the geometry again.

Also, the way different coordinate spaces are handled now is inconsistent.
Some things (Xcb::Window) work only with the logical pixels, while other
(e.g. client messages) require the user manually mapping the geometry
between the different coordinate spaces. With this change, it would be
more consistent.

Regarding the porting process, it was performed in a single step because
all the code that changes or reads Xcb::Window geometry is neatly
encapsulated in the X11Window class in a couple of functions.
This commit is contained in:
Vlad Zahorodnii 2024-06-13 22:29:36 +03:00
parent eb7b04e320
commit 4c86653cd5
3 changed files with 78 additions and 73 deletions

View file

@ -624,6 +624,16 @@ uint32_t toXNative(qreal value)
return static_cast<int32_t>(std::round(kwinApp()->xwaylandScale() * value));
}
QPoint toXNative(const QPointF &p)
{
return QPoint(toXNative(p.x()), toXNative(p.y()));
}
QSize toXNative(const QSizeF &s)
{
return QSize(toXNative(s.width()), toXNative(s.height()));
}
QRect toXNative(const QRectF &r)
{
return QRect(toXNative(r.x()), toXNative(r.y()), toXNative(r.width()), toXNative(r.height()));

View file

@ -41,6 +41,8 @@ namespace Xcb
typedef xcb_window_t WindowId;
uint32_t KWIN_EXPORT toXNative(qreal value);
QPoint KWIN_EXPORT toXNative(const QPointF &value);
QSize KWIN_EXPORT toXNative(const QSizeF &value);
QRect KWIN_EXPORT toXNative(const QRectF &value);
qreal KWIN_EXPORT fromXNative(int value);
QRectF KWIN_EXPORT fromXNative(const QRect &value);
@ -1590,7 +1592,7 @@ public:
* @param values The values to be passed to xcb_create_window
* @param parent The parent window
*/
Window(const QRectF &geometry, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
Window(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
/**
* Creates an xcb_window_t and manages it. It's a convenient method to create a window with
* depth and visual being copied from parent and border being @c 0.
@ -1600,7 +1602,7 @@ public:
* @param values The values to be passed to xcb_create_window
* @param parent The parent window
*/
Window(const QRectF &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
Window(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
Window(const Window &other) = delete;
~Window();
@ -1614,7 +1616,7 @@ public:
* @param values The values to be passed to xcb_create_window
* @param parent The parent window
*/
void create(const QRectF &geometry, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
void create(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
/**
* Creates a new window for which the responsibility is taken over. If a window had been managed
* before it is freed.
@ -1626,7 +1628,7 @@ public:
* @param values The values to be passed to xcb_create_window
* @param parent The parent window
*/
void create(const QRectF &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
void create(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
/**
* Frees the existing window and starts to manage the new @p window.
* If @p destroy is @c true the new managed window will be destroyed together with this
@ -1638,29 +1640,25 @@ public:
* @returns @c true if a window is managed, @c false otherwise.
*/
bool isValid() const;
inline const QRectF &geometry() const
inline const QRect &geometry() const
{
return m_logicGeometry;
}
QRect deviceGeometry() const
{
return m_deviceGeometry;
return m_geometry;
}
/**
* Configures the window with a new geometry.
* @param geometry The new window geometry to be used
*/
void setGeometry(const QRectF &geometry);
void setGeometry(qreal x, qreal y, qreal width, qreal height);
void move(const QPointF &pos);
void move(qreal x, qreal y);
void resize(const QSizeF &size);
void resize(qreal width, qreal height);
void setGeometry(const QRect &geometry);
void setGeometry(int x, int y, int width, int height);
void move(const QPoint &pos);
void move(int x, int y);
void resize(const QSize &size);
void resize(int width, int height);
void raise();
void lower();
void map();
void unmap();
void reparent(xcb_window_t parent, qreal x = 0, qreal y = 0);
void reparent(xcb_window_t parent, int x = 0, int y = 0);
void changeProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length,
const void *data, uint8_t mode = XCB_PROP_MODE_REPLACE);
void deleteProperty(xcb_atom_t property);
@ -1685,12 +1683,11 @@ public:
operator xcb_window_t() const;
private:
xcb_window_t doCreate(const QRectF &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
xcb_window_t doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
void destroy();
xcb_window_t m_window;
bool m_destroy;
QRectF m_logicGeometry;
QRect m_deviceGeometry;
QRect m_geometry;
};
inline Window::Window(xcb_window_t window, bool destroy)
@ -1699,13 +1696,13 @@ inline Window::Window(xcb_window_t window, bool destroy)
{
}
inline Window::Window(const QRectF &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
inline Window::Window(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
: m_window(doCreate(geometry, XCB_COPY_FROM_PARENT, mask, values, parent))
, m_destroy(true)
{
}
inline Window::Window(const QRectF &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
inline Window::Window(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
: m_window(doCreate(geometry, windowClass, mask, values, parent))
, m_destroy(true)
{
@ -1735,27 +1732,26 @@ inline Window::operator xcb_window_t() const
return m_window;
}
inline void Window::create(const QRectF &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
inline void Window::create(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
{
destroy();
m_window = doCreate(geometry, windowClass, mask, values, parent);
}
inline void Window::create(const QRectF &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
inline void Window::create(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
{
create(geometry, XCB_COPY_FROM_PARENT, mask, values, parent);
}
inline xcb_window_t Window::doCreate(const QRectF &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
inline xcb_window_t Window::doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
{
m_logicGeometry = geometry;
m_deviceGeometry = Xcb::toXNative(geometry);
m_geometry = geometry;
xcb_window_t w = xcb_generate_id(connection());
xcb_create_window(connection(), XCB_COPY_FROM_PARENT, w, parent,
m_deviceGeometry.x(),
m_deviceGeometry.y(),
m_deviceGeometry.width(),
m_deviceGeometry.height(),
m_geometry.x(),
m_geometry.y(),
m_geometry.width(),
m_geometry.height(),
0, windowClass, XCB_COPY_FROM_PARENT, mask, values);
return w;
}
@ -1767,54 +1763,51 @@ inline void Window::reset(xcb_window_t window, bool shouldDestroy)
m_destroy = shouldDestroy;
}
inline void Window::setGeometry(const QRectF &geometry)
inline void Window::setGeometry(const QRect &geometry)
{
setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height());
}
inline void Window::setGeometry(qreal x, qreal y, qreal width, qreal height)
inline void Window::setGeometry(int x, int y, int width, int height)
{
m_logicGeometry.setRect(x, y, width, height);
m_deviceGeometry = Xcb::toXNative(m_logicGeometry);
m_geometry.setRect(x, y, width, height);
if (!isValid()) {
return;
}
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const uint32_t values[] = {uint32_t(m_deviceGeometry.x()), uint32_t(m_deviceGeometry.y()), uint32_t(m_deviceGeometry.width()), uint32_t(m_deviceGeometry.height())};
const uint32_t values[] = {uint32_t(m_geometry.x()), uint32_t(m_geometry.y()), uint32_t(m_geometry.width()), uint32_t(m_geometry.height())};
xcb_configure_window(connection(), m_window, mask, values);
}
inline void Window::move(const QPointF &pos)
inline void Window::move(const QPoint &pos)
{
move(pos.x(), pos.y());
}
inline void Window::move(qreal x, qreal y)
inline void Window::move(int x, int y)
{
m_logicGeometry.moveTo(x, y);
m_deviceGeometry.moveTo(Xcb::toXNative(x), Xcb::toXNative(y));
m_geometry.moveTo(x, y);
if (!isValid()) {
return;
}
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
const uint32_t values[] = {uint32_t(m_deviceGeometry.x()), uint32_t(m_deviceGeometry.y())};
const uint32_t values[] = {uint32_t(m_geometry.x()), uint32_t(m_geometry.y())};
xcb_configure_window(connection(), m_window, mask, values);
}
inline void Window::resize(const QSizeF &size)
inline void Window::resize(const QSize &size)
{
resize(size.width(), size.height());
}
inline void Window::resize(qreal width, qreal height)
inline void Window::resize(int width, int height)
{
m_logicGeometry.setSize(QSizeF(width, height));
m_deviceGeometry.setSize(QSize(Xcb::toXNative(width), Xcb::toXNative(height)));
m_geometry.setSize(QSize(width, height));
if (!isValid()) {
return;
}
const uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const uint32_t values[] = {uint32_t(m_deviceGeometry.width()), uint32_t(m_deviceGeometry.height())};
const uint32_t values[] = {uint32_t(m_geometry.width()), uint32_t(m_geometry.height())};
xcb_configure_window(connection(), m_window, mask, values);
}
@ -1845,12 +1838,12 @@ inline void Window::unmap()
xcb_unmap_window(connection(), m_window);
}
inline void Window::reparent(xcb_window_t parent, qreal x, qreal y)
inline void Window::reparent(xcb_window_t parent, int x, int y)
{
if (!isValid()) {
return;
}
xcb_reparent_window(connection(), m_window, parent, Xcb::toXNative(x), Xcb::toXNative(y));
xcb_reparent_window(connection(), m_window, parent, x, y);
}
inline void Window::changeProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void *data, uint8_t mode)
@ -1874,7 +1867,7 @@ inline void Window::setBorderWidth(int32_t width)
if (!isValid()) {
return;
}
uint32_t _width = Xcb::toXNative(width);
uint32_t _width = width;
xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_BORDER_WIDTH, &_width);
}
@ -1939,7 +1932,7 @@ static inline void moveResizeWindow(WindowId window, const QRect &geometry)
{
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const uint32_t values[] = {Xcb::toXNative(geometry.x()), Xcb::toXNative(geometry.y()), Xcb::toXNative(geometry.width()), Xcb::toXNative(geometry.height())};
const uint32_t values[] = {uint32_t(geometry.x()), uint32_t(geometry.y()), uint32_t(geometry.width()), uint32_t(geometry.height())};
xcb_configure_window(connection(), window, mask, values);
}
@ -1951,7 +1944,7 @@ static inline void moveWindow(xcb_window_t window, const QPoint &pos)
static inline void moveWindow(xcb_window_t window, int32_t x, int32_t y)
{
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
const uint32_t values[] = {Xcb::toXNative(x), Xcb::toXNative(y)};
const uint32_t values[] = {uint32_t(x), uint32_t(y)};
xcb_configure_window(connection(), window, mask, values);
}
@ -2008,12 +2001,11 @@ static inline int defaultDepth()
static inline xcb_rectangle_t fromQt(const QRect &rect)
{
const QRect nativeRect = toXNative(rect);
xcb_rectangle_t rectangle;
rectangle.x = nativeRect.x();
rectangle.y = nativeRect.y();
rectangle.width = nativeRect.width();
rectangle.height = nativeRect.height();
rectangle.x = rect.x();
rectangle.y = rect.y();
rectangle.width = rect.width();
rectangle.height = rect.height();
return rectangle;
}

View file

@ -443,7 +443,7 @@ void X11Window::releaseWindow(bool on_shutdown)
m_client.deleteProperty(atoms->net_frame_extents);
m_client.deleteProperty(atoms->kde_net_wm_frame_strut);
const QPointF grav = calculateGravitation(true);
m_client.reparent(kwinApp()->x11RootWindow(), grav.x(), grav.y());
m_client.reparent(kwinApp()->x11RootWindow(), Xcb::toXNative(grav.x()), Xcb::toXNative(grav.y()));
xcb_change_save_set(c, XCB_SET_MODE_DELETE, m_client);
m_client.selectInput(XCB_EVENT_MASK_NO_EVENT);
if (on_shutdown) {
@ -1280,11 +1280,11 @@ void X11Window::updateInputWindow()
return;
}
QRectF bounds = region.boundingRect();
QRect bounds = region.boundingRect();
input_offset = bounds.topLeft();
// Move the bounding rect to screen coordinates
bounds.translate(frameGeometry().topLeft());
bounds.translate(frameGeometry().topLeft().toPoint());
// Move the region to input window coordinates
region.translate(-input_offset.toPoint());
@ -1586,7 +1586,7 @@ void X11Window::updateInputShape()
if (!shape_helper_window.isValid()) {
shape_helper_window.create(QRect(0, 0, 1, 1));
}
const QSizeF bufferSize = m_bufferGeometry.size();
const QSize bufferSize = Xcb::toXNative(m_bufferGeometry.size());
shape_helper_window.resize(bufferSize);
xcb_connection_t *c = kwinApp()->x11Connection();
xcb_shape_combine(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_SHAPE_SK_BOUNDING,
@ -2927,7 +2927,7 @@ QPointF X11Window::wrapperPos() const
*/
QSizeF X11Window::implicitSize() const
{
return clientSizeToFrameSize(m_client.geometry().size());
return clientSizeToFrameSize(Xcb::fromXNative(m_client.geometry().size()));
}
pid_t X11Window::pid() const
@ -4424,15 +4424,18 @@ void X11Window::updateServerGeometry()
// If the client is being interactively resized, then the frame window, the wrapper window,
// and the client window have correct geometry at this point, so we don't have to configure
// them again.
if (m_frame.geometry() != m_bufferGeometry) {
m_frame.setGeometry(m_bufferGeometry);
const QRect xFrameGeometry = Xcb::toXNative(m_bufferGeometry);
if (m_frame.geometry() != xFrameGeometry) {
m_frame.setGeometry(xFrameGeometry);
}
if (!isShade()) {
if (m_wrapper.geometry() != clientRect) {
m_wrapper.setGeometry(clientRect);
const QRect xWrapperGeometry = Xcb::toXNative(clientRect);
if (m_wrapper.geometry() != xWrapperGeometry) {
m_wrapper.setGeometry(xWrapperGeometry);
}
if (m_client.geometry() != QRectF(QPointF(0, 0), clientRect.size())) {
m_client.setGeometry(QRectF(QPointF(0, 0), clientRect.size()));
const QRect xClientGeometry = Xcb::toXNative(QRectF(QPointF(0, 0), clientRect.size()));
if (m_client.geometry() != xClientGeometry) {
m_client.setGeometry(xClientGeometry);
}
// SELI - won't this be too expensive?
// THOMAS - yes, but gtk+ clients will not resize without ...
@ -4441,10 +4444,10 @@ void X11Window::updateServerGeometry()
updateShape();
updateInputWindow();
} else {
m_frame.move(m_bufferGeometry.topLeft());
m_frame.move(Xcb::toXNative(m_bufferGeometry.topLeft()));
sendSyntheticConfigureNotify();
// Unconditionally move the input window: it won't affect rendering
m_decoInputExtent.move(pos().toPoint() + inputPos());
m_decoInputExtent.move(Xcb::toXNative(pos() + inputPos()));
}
m_lastBufferGeometry = m_bufferGeometry;
@ -4812,11 +4815,11 @@ void X11Window::doInteractiveResizeSync(const QRectF &rect)
const QRectF moveResizeClientGeometry = frameRectToClientRect(moveResizeFrameGeometry);
const QRectF moveResizeBufferGeometry = frameRectToBufferRect(moveResizeFrameGeometry);
const QRectF xFrameGeometry = moveResizeBufferGeometry;
const QRectF xWrapperGeometry = moveResizeClientGeometry.translated(-moveResizeBufferGeometry.topLeft());
const QRectF xClientGeometry = QRectF(QPointF(0, 0), moveResizeClientGeometry.size());
const QRect xFrameGeometry = Xcb::toXNative(moveResizeBufferGeometry);
const QRect xWrapperGeometry = Xcb::toXNative(moveResizeClientGeometry.translated(-moveResizeBufferGeometry.topLeft()));
const QRect xClientGeometry = Xcb::toXNative(QRectF(QPointF(0, 0), moveResizeClientGeometry.size()));
if (m_frame.deviceGeometry() == Xcb::toXNative(xFrameGeometry) && m_wrapper.deviceGeometry() == Xcb::toXNative(xWrapperGeometry) && m_client.deviceGeometry() == Xcb::toXNative(xClientGeometry)) {
if (m_frame.geometry() == xFrameGeometry && m_wrapper.geometry() == xWrapperGeometry && m_client.geometry() == xClientGeometry) {
return;
}